mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 07:58:59 +02:00
Merge branch 'master' into vr-edit-a
This commit is contained in:
commit
28c7ef2e97
46 changed files with 1154 additions and 1892 deletions
16
BUILD_OSX.md
16
BUILD_OSX.md
|
@ -1,28 +1,28 @@
|
||||||
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only OS X specific instructions are found in this file.
|
Please read the [general build guide](BUILD.md) for information on dependencies required for all platforms. Only macOS specific instructions are found in this file.
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
|
|
||||||
[Homebrew](https://brew.sh/) is an excellent package manager for OS X. It makes install of some High Fidelity dependencies very simple.
|
[Homebrew](https://brew.sh/) is an excellent package manager for macOS. It makes install of some High Fidelity dependencies very simple.
|
||||||
|
|
||||||
brew install cmake openssl
|
brew install cmake openssl qt
|
||||||
|
|
||||||
### OpenSSL
|
### OpenSSL
|
||||||
|
|
||||||
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
|
Assuming you've installed OpenSSL using the homebrew instructions above, you'll need to set OPENSSL_ROOT_DIR so CMake can find your installations.
|
||||||
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
For OpenSSL installed via homebrew, set OPENSSL_ROOT_DIR:
|
||||||
|
|
||||||
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2h_1/
|
export OPENSSL_ROOT_DIR=/usr/local/Cellar/openssl/1.0.2l
|
||||||
|
|
||||||
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||||
|
|
||||||
### Qt
|
### Qt
|
||||||
|
|
||||||
Download and install the [Qt 5.6.2 for macOS](http://download.qt.io/official_releases/qt/5.6/5.6.2/qt-opensource-mac-x64-clang-5.6.2.dmg).
|
Assuming you've installed Qt using the homebrew instructions above, you'll need to set QT_CMAKE_PREFIX_PATH so CMake can find your installations.
|
||||||
|
For Qt installed via homebrew, set QT_CMAKE_PREFIX_PATH:
|
||||||
|
|
||||||
Keep the default components checked when going through the installer.
|
export QT_CMAKE_PREFIX_PATH=/usr/local/Cellar/qt/5.9.1/lib/cmake
|
||||||
|
|
||||||
Once Qt is installed, you need to manually configure the following:
|
Note that this uses the version from the homebrew formula at the time of this writing, and the version in the path will likely change.
|
||||||
* Set the QT_CMAKE_PREFIX_PATH environment variable to your `Qt5.6.2/5.6/clang_64/lib/cmake/` directory.
|
|
||||||
|
|
||||||
### Xcode
|
### Xcode
|
||||||
|
|
||||||
|
|
|
@ -1162,7 +1162,8 @@ void AssetServer::handleFailedBake(QString originalAssetHash, QString assetPath,
|
||||||
_pendingBakes.remove(originalAssetHash);
|
_pendingBakes.remove(originalAssetHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssetServer::handleCompletedBake(QString originalAssetHash, QString originalAssetPath, QVector<QString> bakedFilePaths) {
|
void AssetServer::handleCompletedBake(QString originalAssetHash, QString originalAssetPath,
|
||||||
|
QString bakedTempOutputDir, QVector<QString> bakedFilePaths) {
|
||||||
bool errorCompletingBake { false };
|
bool errorCompletingBake { false };
|
||||||
QString errorReason;
|
QString errorReason;
|
||||||
|
|
||||||
|
@ -1234,6 +1235,16 @@ void AssetServer::handleCompletedBake(QString originalAssetHash, QString origina
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& filePath : bakedFilePaths) {
|
||||||
|
QFile file(filePath);
|
||||||
|
if (!file.remove()) {
|
||||||
|
qWarning() << "Failed to remove temporary file:" << filePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!QDir(bakedTempOutputDir).rmdir(".")) {
|
||||||
|
qWarning() << "Failed to remove temporary directory:" << bakedTempOutputDir;
|
||||||
|
}
|
||||||
|
|
||||||
if (!errorCompletingBake) {
|
if (!errorCompletingBake) {
|
||||||
// create the meta file to store which version of the baking process we just completed
|
// create the meta file to store which version of the baking process we just completed
|
||||||
writeMetaFile(originalAssetHash);
|
writeMetaFile(originalAssetHash);
|
||||||
|
|
|
@ -100,7 +100,8 @@ private:
|
||||||
void bakeAsset(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath);
|
void bakeAsset(const AssetHash& assetHash, const AssetPath& assetPath, const QString& filePath);
|
||||||
|
|
||||||
/// Move baked content for asset to baked directory and update baked status
|
/// Move baked content for asset to baked directory and update baked status
|
||||||
void handleCompletedBake(QString originalAssetHash, QString assetPath, QVector<QString> bakedFilePaths);
|
void handleCompletedBake(QString originalAssetHash, QString assetPath, QString bakedTempOutputDir,
|
||||||
|
QVector<QString> bakedFilePaths);
|
||||||
void handleFailedBake(QString originalAssetHash, QString assetPath, QString errors);
|
void handleFailedBake(QString originalAssetHash, QString assetPath, QString errors);
|
||||||
void handleAbortedBake(QString originalAssetHash, QString assetPath);
|
void handleAbortedBake(QString originalAssetHash, QString assetPath);
|
||||||
|
|
||||||
|
|
|
@ -24,20 +24,39 @@ BakeAssetTask::BakeAssetTask(const AssetHash& assetHash, const AssetPath& assetP
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void cleanupTempFiles(QString tempOutputDir, std::vector<QString> files) {
|
||||||
|
for (const auto& filename : files) {
|
||||||
|
QFile f { filename };
|
||||||
|
if (!f.remove()) {
|
||||||
|
qDebug() << "Failed to remove:" << filename;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!tempOutputDir.isEmpty()) {
|
||||||
|
QDir dir { tempOutputDir };
|
||||||
|
if (!dir.rmdir(".")) {
|
||||||
|
qDebug() << "Failed to remove temporary directory:" << tempOutputDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void BakeAssetTask::run() {
|
void BakeAssetTask::run() {
|
||||||
_isBaking.store(true);
|
_isBaking.store(true);
|
||||||
|
|
||||||
qRegisterMetaType<QVector<QString> >("QVector<QString>");
|
qRegisterMetaType<QVector<QString> >("QVector<QString>");
|
||||||
TextureBakerThreadGetter fn = []() -> QThread* { return QThread::currentThread(); };
|
TextureBakerThreadGetter fn = []() -> QThread* { return QThread::currentThread(); };
|
||||||
|
|
||||||
|
QString tempOutputDir;
|
||||||
|
|
||||||
if (_assetPath.endsWith(".fbx")) {
|
if (_assetPath.endsWith(".fbx")) {
|
||||||
|
tempOutputDir = PathUtils::generateTemporaryDir();
|
||||||
_baker = std::unique_ptr<FBXBaker> {
|
_baker = std::unique_ptr<FBXBaker> {
|
||||||
new FBXBaker(QUrl("file:///" + _filePath), fn, PathUtils::generateTemporaryDir())
|
new FBXBaker(QUrl("file:///" + _filePath), fn, tempOutputDir)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
tempOutputDir = PathUtils::generateTemporaryDir();
|
||||||
_baker = std::unique_ptr<TextureBaker> {
|
_baker = std::unique_ptr<TextureBaker> {
|
||||||
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
|
new TextureBaker(QUrl("file:///" + _filePath), image::TextureUsage::CUBE_TEXTURE,
|
||||||
PathUtils::generateTemporaryDir())
|
tempOutputDir)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,6 +71,8 @@ void BakeAssetTask::run() {
|
||||||
|
|
||||||
_wasAborted.store(true);
|
_wasAborted.store(true);
|
||||||
|
|
||||||
|
cleanupTempFiles(tempOutputDir, _baker->getOutputFiles());
|
||||||
|
|
||||||
emit bakeAborted(_assetHash, _assetPath);
|
emit bakeAborted(_assetHash, _assetPath);
|
||||||
} else if (_baker->hasErrors()) {
|
} else if (_baker->hasErrors()) {
|
||||||
qDebug() << "Failed to bake: " << _assetHash << _assetPath << _baker->getErrors();
|
qDebug() << "Failed to bake: " << _assetHash << _assetPath << _baker->getErrors();
|
||||||
|
@ -60,6 +81,8 @@ void BakeAssetTask::run() {
|
||||||
|
|
||||||
_didFinish.store(true);
|
_didFinish.store(true);
|
||||||
|
|
||||||
|
cleanupTempFiles(tempOutputDir, _baker->getOutputFiles());
|
||||||
|
|
||||||
emit bakeFailed(_assetHash, _assetPath, errors);
|
emit bakeFailed(_assetHash, _assetPath, errors);
|
||||||
} else {
|
} else {
|
||||||
auto vectorOutputFiles = QVector<QString>::fromStdVector(_baker->getOutputFiles());
|
auto vectorOutputFiles = QVector<QString>::fromStdVector(_baker->getOutputFiles());
|
||||||
|
@ -68,7 +91,7 @@ void BakeAssetTask::run() {
|
||||||
|
|
||||||
_didFinish.store(true);
|
_didFinish.store(true);
|
||||||
|
|
||||||
emit bakeComplete(_assetHash, _assetPath, vectorOutputFiles);
|
emit bakeComplete(_assetHash, _assetPath, tempOutputDir, vectorOutputFiles);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
bool didFinish() const { return _didFinish.load(); }
|
bool didFinish() const { return _didFinish.load(); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void bakeComplete(QString assetHash, QString assetPath, QVector<QString> outputFiles);
|
void bakeComplete(QString assetHash, QString assetPath, QString tempOutputDir, QVector<QString> outputFiles);
|
||||||
void bakeFailed(QString assetHash, QString assetPath, QString errors);
|
void bakeFailed(QString assetHash, QString assetPath, QString errors);
|
||||||
void bakeAborted(QString assetHash, QString assetPath);
|
void bakeAborted(QString assetHash, QString assetPath);
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// Here you can put a script that will be run by an assignment-client (AC)
|
// Here you can put a script that will be run by an assignment-client (AC)
|
||||||
// For examples, please go to http://public.highfidelity.io/scripts
|
// For examples, please go to https://github.com/highfidelity/hifi/tree/master/script-archive/acScripts
|
||||||
// The directory named acScripts contains assignment-client specific scripts you can try.
|
// The directory named acScripts contains assignment-client specific scripts you can try.
|
||||||
|
|
|
@ -27,6 +27,8 @@ ModalWindow {
|
||||||
destroyOnHidden: true
|
destroyOnHidden: true
|
||||||
visible: true
|
visible: true
|
||||||
|
|
||||||
|
readonly property bool isTablet: false
|
||||||
|
|
||||||
property string iconText: ""
|
property string iconText: ""
|
||||||
property int iconSize: 50
|
property int iconSize: 50
|
||||||
|
|
||||||
|
@ -35,6 +37,10 @@ ModalWindow {
|
||||||
|
|
||||||
keyboardOverride: true // Disable ModalWindow's keyboard.
|
keyboardOverride: true // Disable ModalWindow's keyboard.
|
||||||
|
|
||||||
|
function tryDestroy() {
|
||||||
|
root.destroy()
|
||||||
|
}
|
||||||
|
|
||||||
LoginDialog {
|
LoginDialog {
|
||||||
id: loginDialog
|
id: loginDialog
|
||||||
|
|
||||||
|
|
|
@ -29,11 +29,12 @@ Item {
|
||||||
readonly property int maxHeight: 720
|
readonly property int maxHeight: 720
|
||||||
|
|
||||||
function resize() {
|
function resize() {
|
||||||
|
if (root.isTablet === false) {
|
||||||
var targetWidth = Math.max(titleWidth, Math.max(additionalTextContainer.contentWidth,
|
var targetWidth = Math.max(titleWidth, Math.max(additionalTextContainer.contentWidth,
|
||||||
termsContainer.contentWidth))
|
termsContainer.contentWidth))
|
||||||
var targetHeight = 5 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height + termsContainer.height
|
|
||||||
|
|
||||||
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth))
|
||||||
|
}
|
||||||
|
var targetHeight = 5 * hifi.dimensions.contentSpacing.y + buttons.height + additionalTextContainer.height + termsContainer.height
|
||||||
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -61,11 +62,8 @@ Item {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.tryDestroy()
|
||||||
|
|
||||||
onClicked: root.destroy()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,17 +94,19 @@ Item {
|
||||||
id: termsContainer
|
id: termsContainer
|
||||||
anchors {
|
anchors {
|
||||||
top: additionalTextContainer.bottom
|
top: additionalTextContainer.bottom
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
margins: 0
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
width: parent.width
|
||||||
|
|
||||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
color: hifi.colors.baseGrayHighlight
|
color: hifi.colors.baseGrayHighlight
|
||||||
lineHeight: 1
|
lineHeight: 1
|
||||||
lineHeightMode: Text.ProportionalHeight
|
lineHeightMode: Text.ProportionalHeight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
fontSizeMode: Text.HorizontalFit
|
||||||
|
horizontalAlignment: Text.AlignVCenter
|
||||||
|
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
onLinkActivated: loginDialog.openUrl(link)
|
||||||
}
|
}
|
||||||
|
@ -128,9 +128,11 @@ Item {
|
||||||
console.log("Create Failed: " + error)
|
console.log("Create Failed: " + error)
|
||||||
|
|
||||||
bodyLoader.source = "UsernameCollisionBody.qml"
|
bodyLoader.source = "UsernameCollisionBody.qml"
|
||||||
|
if (!root.isTablet) {
|
||||||
bodyLoader.item.width = root.pane.width
|
bodyLoader.item.width = root.pane.width
|
||||||
bodyLoader.item.height = root.pane.height
|
bodyLoader.item.height = root.pane.height
|
||||||
}
|
}
|
||||||
|
}
|
||||||
onHandleLoginCompleted: {
|
onHandleLoginCompleted: {
|
||||||
console.log("Login Succeeded")
|
console.log("Login Succeeded")
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Hifi 1.0
|
import Hifi 1.0
|
||||||
import QtQuick 2.4
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||||
|
|
||||||
|
@ -45,8 +45,7 @@ Item {
|
||||||
function resize() {
|
function resize() {
|
||||||
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
||||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||||
4 * hifi.dimensions.contentSpacing.y + form.height +
|
4 * hifi.dimensions.contentSpacing.y + form.height;
|
||||||
hifi.dimensions.contentSpacing.y + buttons.height;
|
|
||||||
|
|
||||||
if (additionalInformation.visible) {
|
if (additionalInformation.visible) {
|
||||||
targetWidth = Math.max(targetWidth, additionalInformation.width);
|
targetWidth = Math.max(targetWidth, additionalInformation.width);
|
||||||
|
@ -66,9 +65,6 @@ Item {
|
||||||
if (loginDialog.isSteamRunning()) {
|
if (loginDialog.isSteamRunning()) {
|
||||||
additionalInformation.visible = !isLoading
|
additionalInformation.visible = !isLoading
|
||||||
}
|
}
|
||||||
|
|
||||||
leftButton.visible = !isLoading
|
|
||||||
buttons.visible = !isLoading
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BusyIndicator {
|
BusyIndicator {
|
||||||
|
@ -108,30 +104,27 @@ Item {
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: form
|
id: form
|
||||||
|
width: parent.width
|
||||||
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: mainTextContainer.bottom
|
top: mainTextContainer.bottom
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||||
}
|
}
|
||||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: usernameField
|
id: usernameField
|
||||||
anchors {
|
width: parent.width
|
||||||
verticalCenter: parent.verticalCenter
|
focus: true
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Username or Email"
|
label: "Username or Email"
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: usernameField.textFieldLabel.verticalCenter
|
||||||
|
left: usernameField.textFieldLabel.right
|
||||||
|
leftMargin: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
||||||
|
@ -143,23 +136,19 @@ Item {
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
onLinkActivated: loginDialog.openUrl(link)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
anchors {
|
width: parent.width
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Password"
|
label: "Password"
|
||||||
echoMode: TextInput.Password
|
echoMode: showPassword.checked ? TextInput.Normal : TextInput.Password
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: passwordField.textFieldLabel.verticalCenter
|
||||||
|
left: passwordField.textFieldLabel.right
|
||||||
|
leftMargin: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
||||||
|
@ -172,16 +161,13 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CheckBoxQQC2 {
|
||||||
|
id: showPassword
|
||||||
|
text: "Show password"
|
||||||
}
|
}
|
||||||
|
|
||||||
InfoItem {
|
InfoItem {
|
||||||
id: additionalInformation
|
id: additionalInformation
|
||||||
anchors {
|
|
||||||
top: form.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: loginDialog.isSteamRunning()
|
visible: loginDialog.isSteamRunning()
|
||||||
|
|
||||||
|
@ -193,52 +179,11 @@ Item {
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
|
||||||
Keyboard {
|
|
||||||
raised: keyboardEnabled && keyboardRaised
|
|
||||||
numeric: punctuationMode
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: buttons.top
|
|
||||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: leftButton
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Sign Up")
|
|
||||||
visible: !loginDialog.isSteamRunning()
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
bodyLoader.setSource("SignUpBody.qml")
|
|
||||||
bodyLoader.item.width = root.pane.width
|
|
||||||
bodyLoader.item.height = root.pane.height
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: buttons
|
id: buttons
|
||||||
anchors {
|
spacing: hifi.dimensions.contentSpacing.y*2
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
id: linkAccountButton
|
id: linkAccountButton
|
||||||
|
@ -253,17 +198,64 @@ Item {
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
onClicked: root.tryDestroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onClicked: root.destroy()
|
Row {
|
||||||
|
id: leftButton
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
spacing: hifi.dimensions.contentSpacing.y*2
|
||||||
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
||||||
|
RalewaySemiBold {
|
||||||
|
size: hifi.fontSizes.inputLabel
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
text: qsTr("Don't have an account?")
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
text: qsTr("Sign Up")
|
||||||
|
visible: !loginDialog.isSteamRunning()
|
||||||
|
|
||||||
|
onClicked: {
|
||||||
|
bodyLoader.setSource("SignUpBody.qml")
|
||||||
|
if (!root.isTablet) {
|
||||||
|
bodyLoader.item.width = root.pane.width
|
||||||
|
bodyLoader.item.height = root.pane.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||||
|
Keyboard {
|
||||||
|
raised: keyboardEnabled && keyboardRaised
|
||||||
|
numeric: punctuationMode
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.title = qsTr("Sign Into High Fidelity")
|
root.title = qsTr("Sign Into High Fidelity")
|
||||||
root.iconText = "<"
|
root.iconText = "<"
|
||||||
keyboardEnabled = HMD.active;
|
|
||||||
|
//dont rise local keyboard
|
||||||
|
keyboardEnabled = !root.isTablet && HMD.active;
|
||||||
|
//but rise Tablet's one instead for Tablet interface
|
||||||
|
if (root.isTablet) {
|
||||||
|
root.keyboardEnabled = HMD.active;
|
||||||
|
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
|
||||||
|
}
|
||||||
d.resize();
|
d.resize();
|
||||||
|
|
||||||
if (failAfterSignUp) {
|
if (failAfterSignUp) {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Hifi 1.0
|
import Hifi 1.0
|
||||||
import QtQuick 2.4
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||||
|
|
||||||
import "../controls-uit"
|
import "../controls-uit"
|
||||||
|
@ -18,8 +18,8 @@ import "../styles-uit"
|
||||||
Item {
|
Item {
|
||||||
id: signInBody
|
id: signInBody
|
||||||
clip: true
|
clip: true
|
||||||
width: root.pane.width
|
|
||||||
height: root.pane.height
|
height: root.pane.height
|
||||||
|
width: root.pane.width
|
||||||
|
|
||||||
property bool required: false
|
property bool required: false
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancel() {
|
function cancel() {
|
||||||
root.destroy()
|
root.tryDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
|
@ -121,8 +121,10 @@ Item {
|
||||||
console.log("Login Failed")
|
console.log("Login Failed")
|
||||||
|
|
||||||
bodyLoader.source = "CompleteProfileBody.qml"
|
bodyLoader.source = "CompleteProfileBody.qml"
|
||||||
|
if (!root.isTablet) {
|
||||||
bodyLoader.item.width = root.pane.width
|
bodyLoader.item.width = root.pane.width
|
||||||
bodyLoader.item.height = root.pane.height
|
bodyLoader.item.height = root.pane.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Hifi 1.0
|
import Hifi 1.0
|
||||||
import QtQuick 2.4
|
import QtQuick 2.7
|
||||||
import QtQuick.Controls 1.4
|
import QtQuick.Controls 1.4
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
||||||
|
|
||||||
|
@ -44,8 +44,7 @@ Item {
|
||||||
function resize() {
|
function resize() {
|
||||||
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
var targetWidth = Math.max(titleWidth, form.contentWidth);
|
||||||
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
var targetHeight = hifi.dimensions.contentSpacing.y + mainTextContainer.height +
|
||||||
4 * hifi.dimensions.contentSpacing.y + form.height +
|
4 * hifi.dimensions.contentSpacing.y + form.height;
|
||||||
hifi.dimensions.contentSpacing.y + buttons.height;
|
|
||||||
|
|
||||||
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
parent.width = root.width = Math.max(d.minWidth, Math.min(d.maxWidth, targetWidth));
|
||||||
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
parent.height = root.height = Math.max(d.minHeight, Math.min(d.maxHeight, targetHeight))
|
||||||
|
@ -96,44 +95,31 @@ Item {
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: form
|
id: form
|
||||||
|
width: parent.width
|
||||||
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
top: mainTextContainer.bottom
|
top: mainTextContainer.bottom
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
||||||
}
|
}
|
||||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
spacing: 2 * hifi.dimensions.contentSpacing.y
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: emailField
|
id: emailField
|
||||||
anchors {
|
width: parent.width
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Email"
|
label: "Email"
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: usernameField
|
id: usernameField
|
||||||
anchors {
|
width: parent.width
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Username"
|
label: "Username"
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.textFieldLabel.verticalCenter
|
||||||
|
left: parent.textFieldLabel.right
|
||||||
|
leftMargin: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
text: qsTr("No spaces / special chars.")
|
text: qsTr("No spaces / special chars.")
|
||||||
|
@ -145,23 +131,17 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
TextField {
|
||||||
id: passwordField
|
id: passwordField
|
||||||
anchors {
|
width: parent.width
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Password"
|
label: "Password"
|
||||||
echoMode: TextInput.Password
|
echoMode: TextInput.Password
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
ShortcutText {
|
||||||
anchors {
|
anchors {
|
||||||
verticalCenter: parent.verticalCenter
|
verticalCenter: parent.textFieldLabel.verticalCenter
|
||||||
|
left: parent.textFieldLabel.right
|
||||||
|
leftMargin: 10
|
||||||
}
|
}
|
||||||
|
|
||||||
text: qsTr("At least 6 characters")
|
text: qsTr("At least 6 characters")
|
||||||
|
@ -173,27 +153,9 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
|
||||||
Keyboard {
|
|
||||||
raised: keyboardEnabled && keyboardRaised
|
|
||||||
numeric: punctuationMode
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: buttons.top
|
|
||||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: leftButton
|
id: leftButton
|
||||||
anchors {
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
left: parent.left
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
@ -205,19 +167,17 @@ Item {
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
bodyLoader.setSource("LinkAccountBody.qml")
|
bodyLoader.setSource("LinkAccountBody.qml")
|
||||||
|
if (!root.isTablet) {
|
||||||
bodyLoader.item.width = root.pane.width
|
bodyLoader.item.width = root.pane.width
|
||||||
bodyLoader.item.height = root.pane.height
|
bodyLoader.item.height = root.pane.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: buttons
|
id: buttons
|
||||||
anchors {
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
|
||||||
|
@ -237,14 +197,33 @@ Item {
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
|
||||||
onClicked: root.destroy()
|
onClicked: root.tryDestroy()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
||||||
|
Keyboard {
|
||||||
|
raised: keyboardEnabled && keyboardRaised
|
||||||
|
numeric: punctuationMode
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.title = qsTr("Create an Account")
|
root.title = qsTr("Create an Account")
|
||||||
root.iconText = "<"
|
root.iconText = "<"
|
||||||
keyboardEnabled = HMD.active;
|
//dont rise local keyboard
|
||||||
|
keyboardEnabled = !root.isTablet && HMD.active;
|
||||||
|
//but rise Tablet's one instead for Tablet interface
|
||||||
|
if (root.isTablet) {
|
||||||
|
root.keyboardEnabled = HMD.active;
|
||||||
|
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
|
||||||
|
}
|
||||||
d.resize();
|
d.resize();
|
||||||
|
|
||||||
emailField.forceActiveFocus();
|
emailField.forceActiveFocus();
|
||||||
|
@ -275,10 +254,12 @@ Item {
|
||||||
onHandleLoginFailed: {
|
onHandleLoginFailed: {
|
||||||
// we failed to login, show the LoginDialog so the user will try again
|
// we failed to login, show the LoginDialog so the user will try again
|
||||||
bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true })
|
bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true })
|
||||||
|
if (!root.isTablet) {
|
||||||
bodyLoader.item.width = root.pane.width
|
bodyLoader.item.width = root.pane.width
|
||||||
bodyLoader.item.height = root.pane.height
|
bodyLoader.item.height = root.pane.height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Keys.onPressed: {
|
Keys.onPressed: {
|
||||||
if (!visible) {
|
if (!visible) {
|
||||||
|
|
|
@ -79,7 +79,7 @@ Item {
|
||||||
margins: 0
|
margins: 0
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
topMargin: hifi.dimensions.contentSpacing.y
|
||||||
}
|
}
|
||||||
width: 250
|
width: parent.width
|
||||||
|
|
||||||
placeholderText: "Choose your own"
|
placeholderText: "Choose your own"
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ Item {
|
||||||
bottom: parent.bottom
|
bottom: parent.bottom
|
||||||
right: parent.right
|
right: parent.right
|
||||||
margins: 0
|
margins: 0
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
bottomMargin: hifi.dimensions.contentSpacing.y
|
||||||
}
|
}
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
spacing: hifi.dimensions.contentSpacing.x
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
||||||
|
@ -122,14 +122,21 @@ Item {
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
text: qsTr("Cancel")
|
||||||
|
|
||||||
onClicked: root.destroy()
|
onClicked: root.tryDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.title = qsTr("Complete Your Profile")
|
root.title = qsTr("Complete Your Profile")
|
||||||
root.iconText = "<"
|
root.iconText = "<"
|
||||||
keyboardEnabled = HMD.active;
|
//dont rise local keyboard
|
||||||
|
keyboardEnabled = !root.isTablet && HMD.active;
|
||||||
|
//but rise Tablet's one instead for Tablet interface
|
||||||
|
if (root.isTablet) {
|
||||||
|
root.keyboardEnabled = HMD.active;
|
||||||
|
root.keyboardRaised = Qt.binding( function() { return keyboardRaised; })
|
||||||
|
}
|
||||||
|
|
||||||
d.resize();
|
d.resize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ Item {
|
||||||
|
|
||||||
text: qsTr("Close");
|
text: qsTr("Close");
|
||||||
|
|
||||||
onClicked: root.destroy()
|
onClicked: root.tryDestroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
//
|
|
||||||
// CompleteProfileBody.qml
|
|
||||||
//
|
|
||||||
// Created by Clement on 7/18/16
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: completeProfileBody
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: 200
|
|
||||||
|
|
||||||
text: qsTr("Create your profile")
|
|
||||||
color: hifi.buttons.blue
|
|
||||||
|
|
||||||
onClicked: loginDialog.createAccountFromStream()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
|
|
||||||
onClicked: bodyLoader.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
id: additionalTextContainer
|
|
||||||
anchors {
|
|
||||||
top: buttons.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
text: "<a href='https://fake.link'>Already have a High Fidelity profile? Link to an existing profile here.</a>"
|
|
||||||
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
lineHeight: 2
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
|
|
||||||
onLinkActivated: {
|
|
||||||
bodyLoader.setSource("LinkAccountBody.qml")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoItem {
|
|
||||||
id: termsContainer
|
|
||||||
anchors {
|
|
||||||
top: additionalTextContainer.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
text: qsTr("By creating this user profile, you agree to <a href='https://highfidelity.com/terms'>High Fidelity's Terms of Service</a>")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.baseGrayHighlight
|
|
||||||
lineHeight: 1
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
|
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
loginDialogRoot.title = qsTr("Complete Your Profile")
|
|
||||||
loginDialogRoot.iconText = "<"
|
|
||||||
d.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: loginDialog
|
|
||||||
onHandleCreateCompleted: {
|
|
||||||
console.log("Create Succeeded")
|
|
||||||
|
|
||||||
loginDialog.loginThroughSteam()
|
|
||||||
}
|
|
||||||
onHandleCreateFailed: {
|
|
||||||
console.log("Create Failed: " + error)
|
|
||||||
|
|
||||||
bodyLoadersetSource("UsernameCollisionBody.qml")
|
|
||||||
}
|
|
||||||
onHandleLoginCompleted: {
|
|
||||||
console.log("Login Succeeded")
|
|
||||||
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
|
||||||
}
|
|
||||||
onHandleLoginFailed: {
|
|
||||||
console.log("Login Failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,296 +0,0 @@
|
||||||
//
|
|
||||||
// LinkAccountBody.qml
|
|
||||||
//
|
|
||||||
// Created by Clement on 7/18/16
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: linkAccountBody
|
|
||||||
clip: true
|
|
||||||
height: parent.height
|
|
||||||
width: parent.width
|
|
||||||
property bool failAfterSignUp: false
|
|
||||||
|
|
||||||
function login() {
|
|
||||||
mainTextContainer.visible = false
|
|
||||||
toggleLoading(true)
|
|
||||||
loginDialog.login(usernameField.text, passwordField.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool keyboardEnabled: false
|
|
||||||
property bool keyboardRaised: false
|
|
||||||
property bool punctuationMode: false
|
|
||||||
|
|
||||||
onKeyboardRaisedChanged: d.resize();
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleLoading(isLoading) {
|
|
||||||
linkAccountSpinner.visible = isLoading
|
|
||||||
form.visible = !isLoading
|
|
||||||
|
|
||||||
if (loginDialog.isSteamRunning()) {
|
|
||||||
additionalInformation.visible = !isLoading
|
|
||||||
}
|
|
||||||
|
|
||||||
leftButton.visible = !isLoading
|
|
||||||
buttons.visible = !isLoading
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
id: linkAccountSpinner
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
running: true
|
|
||||||
|
|
||||||
width: 48
|
|
||||||
height: 48
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
id: mainTextContainer
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
text: qsTr("Username or password incorrect.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.redAccent
|
|
||||||
lineHeight: 1
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: form
|
|
||||||
anchors {
|
|
||||||
top: mainTextContainer.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: usernameField
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Username or Email"
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Username?</a>"
|
|
||||||
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
linkColor: hifi.colors.blueAccent
|
|
||||||
|
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: passwordField
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 350
|
|
||||||
|
|
||||||
label: "Password"
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
text: "<a href='https://highfidelity.com/users/password/new'>Forgot Password?</a>"
|
|
||||||
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
linkColor: hifi.colors.blueAccent
|
|
||||||
|
|
||||||
onLinkActivated: loginDialog.openUrl(link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoItem {
|
|
||||||
id: additionalInformation
|
|
||||||
anchors {
|
|
||||||
top: form.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: loginDialog.isSteamRunning()
|
|
||||||
|
|
||||||
text: qsTr("Your steam account informations will not be exposed to other users.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.baseGrayHighlight
|
|
||||||
lineHeight: 1
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
|
||||||
Keyboard {
|
|
||||||
raised: keyboardEnabled && keyboardRaised
|
|
||||||
numeric: punctuationMode
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: buttons.top
|
|
||||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: leftButton
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Sign Up")
|
|
||||||
visible: !loginDialog.isSteamRunning()
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
bodyLoader.setSource("SignUpBody.qml")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: linkAccountButton
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: 200
|
|
||||||
|
|
||||||
text: qsTr(loginDialog.isSteamRunning() ? "Link Account" : "Login")
|
|
||||||
color: hifi.buttons.blue
|
|
||||||
|
|
||||||
onClicked: linkAccountBody.login()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: {
|
|
||||||
bodyLoader.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
loginDialogRoot.title = qsTr("Sign Into High Fidelity")
|
|
||||||
loginDialogRoot.iconText = "<"
|
|
||||||
keyboardEnabled = HMD.active;
|
|
||||||
d.resize();
|
|
||||||
|
|
||||||
if (failAfterSignUp) {
|
|
||||||
mainTextContainer.text = "Account created successfully."
|
|
||||||
mainTextContainer.visible = true
|
|
||||||
}
|
|
||||||
|
|
||||||
usernameField.forceActiveFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: loginDialog
|
|
||||||
onHandleLoginCompleted: {
|
|
||||||
console.log("Login Succeeded, linking steam account")
|
|
||||||
|
|
||||||
if (loginDialog.isSteamRunning()) {
|
|
||||||
loginDialog.linkSteam()
|
|
||||||
} else {
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onHandleLoginFailed: {
|
|
||||||
console.log("Login Failed")
|
|
||||||
mainTextContainer.visible = true
|
|
||||||
toggleLoading(false)
|
|
||||||
}
|
|
||||||
onHandleLinkCompleted: {
|
|
||||||
console.log("Link Succeeded")
|
|
||||||
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
|
||||||
}
|
|
||||||
onHandleLinkFailed: {
|
|
||||||
console.log("Link Failed")
|
|
||||||
toggleLoading(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
|
||||||
if (!visible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event.key) {
|
|
||||||
case Qt.Key_Enter:
|
|
||||||
case Qt.Key_Return:
|
|
||||||
event.accepted = true
|
|
||||||
linkAccountBody.login()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,109 +0,0 @@
|
||||||
//
|
|
||||||
// SignInBody.qml
|
|
||||||
//
|
|
||||||
// Created by Clement on 7/18/16
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: signInBody
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
property bool required: false
|
|
||||||
|
|
||||||
function login() {
|
|
||||||
console.log("Trying to log in")
|
|
||||||
loginDialog.loginThroughSteam()
|
|
||||||
}
|
|
||||||
|
|
||||||
function cancel() {
|
|
||||||
bodyLoader.popup()
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoItem {
|
|
||||||
id: mainTextContainer
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
text: required ? qsTr("This domain's owner requires that you sign in:")
|
|
||||||
: qsTr("Sign in to access your user account:")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.baseGrayHighlight
|
|
||||||
lineHeight: 2
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
top: mainTextContainer.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
width: undefined // invalidate so that the image's size sets the width
|
|
||||||
height: undefined // invalidate so that the image's size sets the height
|
|
||||||
focus: true
|
|
||||||
|
|
||||||
style: OriginalStyles.ButtonStyle {
|
|
||||||
background: Image {
|
|
||||||
id: buttonImage
|
|
||||||
source: "../../images/steam-sign-in.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onClicked: signInBody.login()
|
|
||||||
}
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Cancel");
|
|
||||||
|
|
||||||
onClicked: signInBody.cancel()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
loginDialogRoot.title = required ? qsTr("Sign In Required")
|
|
||||||
: qsTr("Sign In")
|
|
||||||
loginDialogRoot.iconText = ""
|
|
||||||
d.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: loginDialog
|
|
||||||
onHandleLoginCompleted: {
|
|
||||||
console.log("Login Succeeded")
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : true })
|
|
||||||
}
|
|
||||||
onHandleLoginFailed: {
|
|
||||||
console.log("Login Failed")
|
|
||||||
bodyLoader.setSource("CompleteProfileBody.qml")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,276 +0,0 @@
|
||||||
//
|
|
||||||
// SignUpBody.qml
|
|
||||||
//
|
|
||||||
// Created by Stephen Birarda on 7 Dec 2016
|
|
||||||
// Copyright 2016 High Fidelity, Inc.
|
|
||||||
//
|
|
||||||
// Distributed under the Apache License, Version 2.0.
|
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: signupBody
|
|
||||||
clip: true
|
|
||||||
// height: parent.height
|
|
||||||
// width: parent.width
|
|
||||||
|
|
||||||
function signup() {
|
|
||||||
mainTextContainer.visible = false
|
|
||||||
toggleLoading(true)
|
|
||||||
loginDialog.signup(emailField.text, usernameField.text, passwordField.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool keyboardEnabled: false
|
|
||||||
property bool keyboardRaised: false
|
|
||||||
property bool punctuationMode: false
|
|
||||||
|
|
||||||
onKeyboardRaisedChanged: d.resize();
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleLoading(isLoading) {
|
|
||||||
linkAccountSpinner.visible = isLoading
|
|
||||||
form.visible = !isLoading
|
|
||||||
|
|
||||||
leftButton.visible = !isLoading
|
|
||||||
buttons.visible = !isLoading
|
|
||||||
}
|
|
||||||
|
|
||||||
BusyIndicator {
|
|
||||||
id: linkAccountSpinner
|
|
||||||
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
running: true
|
|
||||||
|
|
||||||
width: 48
|
|
||||||
height: 48
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
id: mainTextContainer
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
visible: false
|
|
||||||
|
|
||||||
text: qsTr("There was an unknown error while creating your account.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.redAccent
|
|
||||||
horizontalAlignment: Text.AlignLeft
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
id: form
|
|
||||||
anchors {
|
|
||||||
top: mainTextContainer.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: emailField
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 300
|
|
||||||
|
|
||||||
label: "Email"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: usernameField
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 300
|
|
||||||
|
|
||||||
label: "Username"
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
text: qsTr("No spaces / special chars.")
|
|
||||||
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
|
|
||||||
color: hifi.colors.blueAccent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: passwordField
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
width: 300
|
|
||||||
|
|
||||||
label: "Password"
|
|
||||||
echoMode: TextInput.Password
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
anchors {
|
|
||||||
verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
text: qsTr("At least 6 characters")
|
|
||||||
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
|
|
||||||
color: hifi.colors.blueAccent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
|
||||||
Keyboard {
|
|
||||||
raised: keyboardEnabled && keyboardRaised
|
|
||||||
numeric: punctuationMode
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: buttons.top
|
|
||||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: leftButton
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Existing User")
|
|
||||||
|
|
||||||
onClicked: {
|
|
||||||
bodyLoader.setSource("LinkAccountBody.qml")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
right: parent.right
|
|
||||||
bottom: parent.bottom
|
|
||||||
bottomMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
id: linkAccountButton
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: 200
|
|
||||||
|
|
||||||
text: qsTr("Sign Up")
|
|
||||||
color: hifi.buttons.blue
|
|
||||||
|
|
||||||
onClicked: signupBody.signup()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
|
|
||||||
onClicked: bodyLoader.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
loginDialogRoot.title = qsTr("Create an Account")
|
|
||||||
loginDialogRoot.iconText = "<"
|
|
||||||
keyboardEnabled = HMD.active;
|
|
||||||
d.resize();
|
|
||||||
|
|
||||||
emailField.forceActiveFocus();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: loginDialog
|
|
||||||
onHandleSignupCompleted: {
|
|
||||||
console.log("Sign Up Succeeded");
|
|
||||||
|
|
||||||
// now that we have an account, login with that username and password
|
|
||||||
loginDialog.login(usernameField.text, passwordField.text)
|
|
||||||
}
|
|
||||||
onHandleSignupFailed: {
|
|
||||||
console.log("Sign Up Failed")
|
|
||||||
toggleLoading(false)
|
|
||||||
|
|
||||||
mainTextContainer.text = errorString
|
|
||||||
mainTextContainer.visible = true
|
|
||||||
|
|
||||||
d.resize();
|
|
||||||
}
|
|
||||||
onHandleLoginCompleted: {
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack": false })
|
|
||||||
}
|
|
||||||
onHandleLoginFailed: {
|
|
||||||
// we failed to login, show the LoginDialog so the user will try again
|
|
||||||
bodyLoader.setSource("LinkAccountBody.qml", { "failAfterSignUp": true })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
|
||||||
if (!visible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event.key) {
|
|
||||||
case Qt.Key_Enter:
|
|
||||||
case Qt.Key_Return:
|
|
||||||
event.accepted = true
|
|
||||||
signupBody.signup()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,157 +0,0 @@
|
||||||
//
|
|
||||||
// UsernameCollisionBody.qml
|
|
||||||
//
|
|
||||||
// Created by Clement on 7/18/16
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Controls.Styles 1.4 as OriginalStyles
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: usernameCollisionBody
|
|
||||||
clip: true
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
|
|
||||||
function create() {
|
|
||||||
mainTextContainer.visible = false
|
|
||||||
loginDialog.createAccountFromStream(textField.text)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
property bool keyboardEnabled: false
|
|
||||||
property bool keyboardRaised: false
|
|
||||||
property bool punctuationMode: false
|
|
||||||
|
|
||||||
onKeyboardRaisedChanged: d.resize();
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
ShortcutText {
|
|
||||||
id: mainTextContainer
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
text: qsTr("Your Steam username is not available.")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.redAccent
|
|
||||||
lineHeight: 1
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TextField {
|
|
||||||
id: textField
|
|
||||||
anchors {
|
|
||||||
top: mainTextContainer.bottom
|
|
||||||
left: parent.left
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
width: 250
|
|
||||||
|
|
||||||
placeholderText: "Choose your own"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override ScrollingWindow's keyboard that would be at very bottom of dialog.
|
|
||||||
Keyboard {
|
|
||||||
raised: keyboardEnabled && keyboardRaised
|
|
||||||
numeric: punctuationMode
|
|
||||||
anchors {
|
|
||||||
left: parent.left
|
|
||||||
right: parent.right
|
|
||||||
bottom: buttons.top
|
|
||||||
bottomMargin: keyboardRaised ? 2 * hifi.dimensions.contentSpacing.y : 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
bottom: parent.bottom
|
|
||||||
right: parent.right
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: 200
|
|
||||||
|
|
||||||
text: qsTr("Create your profile")
|
|
||||||
color: hifi.buttons.blue
|
|
||||||
|
|
||||||
onClicked: usernameCollisionBody.create()
|
|
||||||
}
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Cancel")
|
|
||||||
onClicked: bodyLoader.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
loginDialogRoot.title = qsTr("Complete Your Profile")
|
|
||||||
loginDialogRoot.iconText = "<"
|
|
||||||
keyboardEnabled = HMD.active;
|
|
||||||
d.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: loginDialog
|
|
||||||
onHandleCreateCompleted: {
|
|
||||||
console.log("Create Succeeded")
|
|
||||||
|
|
||||||
loginDialog.loginThroughSteam()
|
|
||||||
}
|
|
||||||
onHandleCreateFailed: {
|
|
||||||
console.log("Create Failed: " + error)
|
|
||||||
|
|
||||||
mainTextContainer.visible = true
|
|
||||||
mainTextContainer.text = "\"" + textField.text + qsTr("\" is invalid or already taken.")
|
|
||||||
}
|
|
||||||
onHandleLoginCompleted: {
|
|
||||||
console.log("Login Succeeded")
|
|
||||||
|
|
||||||
bodyLoader.setSource("WelcomeBody.qml", { "welcomeBack" : false })
|
|
||||||
}
|
|
||||||
onHandleLoginFailed: {
|
|
||||||
console.log("Login Failed")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Keys.onPressed: {
|
|
||||||
if (!visible) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (event.key) {
|
|
||||||
case Qt.Key_Enter:
|
|
||||||
case Qt.Key_Return:
|
|
||||||
event.accepted = true
|
|
||||||
usernameCollisionBody.create()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,79 +0,0 @@
|
||||||
//
|
|
||||||
// WelcomeBody.qml
|
|
||||||
//
|
|
||||||
// Created by Clement on 7/18/16
|
|
||||||
// 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
|
|
||||||
//
|
|
||||||
|
|
||||||
import Hifi 1.0
|
|
||||||
import QtQuick 2.4
|
|
||||||
|
|
||||||
import "../controls-uit"
|
|
||||||
import "../styles-uit"
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: welcomeBody
|
|
||||||
clip: true
|
|
||||||
|
|
||||||
property bool welcomeBack: false
|
|
||||||
|
|
||||||
function setTitle() {
|
|
||||||
loginDialogRoot.title = (welcomeBack ? qsTr("Welcome back <b>") : qsTr("Welcome <b>")) + Account.username + qsTr("</b>!")
|
|
||||||
loginDialogRoot.iconText = ""
|
|
||||||
d.resize();
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
|
||||||
id: d
|
|
||||||
function resize() {}
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoItem {
|
|
||||||
id: mainTextContainer
|
|
||||||
anchors {
|
|
||||||
top: parent.top
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
|
|
||||||
text: qsTr("You are now signed into High Fidelity")
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
color: hifi.colors.baseGrayHighlight
|
|
||||||
lineHeight: 2
|
|
||||||
lineHeightMode: Text.ProportionalHeight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Row {
|
|
||||||
id: buttons
|
|
||||||
anchors {
|
|
||||||
top: mainTextContainer.bottom
|
|
||||||
horizontalCenter: parent.horizontalCenter
|
|
||||||
margins: 0
|
|
||||||
topMargin: 2 * hifi.dimensions.contentSpacing.y
|
|
||||||
}
|
|
||||||
spacing: hifi.dimensions.contentSpacing.x
|
|
||||||
onHeightChanged: d.resize(); onWidthChanged: d.resize();
|
|
||||||
|
|
||||||
Button {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
text: qsTr("Close");
|
|
||||||
|
|
||||||
onClicked: bodyLoader.popup()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
welcomeBody.setTitle()
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: Account
|
|
||||||
onUsernameChanged: welcomeBody.setTitle()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -35,6 +35,7 @@ TextField {
|
||||||
font.pixelSize: hifi.fontSizes.textFieldInput
|
font.pixelSize: hifi.fontSizes.textFieldInput
|
||||||
font.italic: textField.text == ""
|
font.italic: textField.text == ""
|
||||||
height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered.
|
height: implicitHeight + 3 // Make surrounding box higher so that highlight is vertically centered.
|
||||||
|
property alias textFieldLabel: textFieldLabel
|
||||||
|
|
||||||
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
|
y: textFieldLabel.visible ? textFieldLabel.height + textFieldLabel.anchors.bottomMargin : 0
|
||||||
|
|
||||||
|
|
|
@ -16,48 +16,66 @@ import "../controls-uit"
|
||||||
import "../styles-uit"
|
import "../styles-uit"
|
||||||
import "../windows"
|
import "../windows"
|
||||||
|
|
||||||
|
import "../LoginDialog"
|
||||||
|
|
||||||
TabletModalWindow {
|
TabletModalWindow {
|
||||||
id: loginDialogRoot
|
id: realRoot
|
||||||
objectName: "LoginDialog"
|
objectName: "LoginDialog"
|
||||||
|
|
||||||
signal sendToScript(var message);
|
signal sendToScript(var message);
|
||||||
property bool isHMD: false
|
property bool isHMD: false
|
||||||
property bool gotoPreviousApp: false;
|
property bool gotoPreviousApp: false;
|
||||||
color: hifi.colors.baseGray
|
color: hifi.colors.baseGray
|
||||||
|
title: qsTr("Sign in to High Fidelity")
|
||||||
|
property alias titleWidth: root.titleWidth
|
||||||
|
property alias punctuationMode: root.punctuationMode
|
||||||
|
|
||||||
property int colorScheme: hifi.colorSchemes.dark
|
//fake root for shared components expecting root here
|
||||||
property int titleWidth: 0
|
property var root: QtObject {
|
||||||
property string iconText: ""
|
id: root
|
||||||
property int icon: hifi.icons.none
|
|
||||||
property int iconSize: 35
|
|
||||||
MouseArea {
|
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
|
||||||
}
|
|
||||||
|
|
||||||
property bool keyboardOverride: true
|
|
||||||
onIconChanged: updateIcon();
|
|
||||||
|
|
||||||
property var items;
|
|
||||||
property string label: ""
|
|
||||||
|
|
||||||
onTitleWidthChanged: d.resize();
|
|
||||||
|
|
||||||
property bool keyboardEnabled: false
|
property bool keyboardEnabled: false
|
||||||
property bool keyboardRaised: false
|
property bool keyboardRaised: false
|
||||||
property bool punctuationMode: false
|
property bool punctuationMode: false
|
||||||
|
|
||||||
onKeyboardRaisedChanged: d.resize();
|
readonly property bool isTablet: true
|
||||||
|
|
||||||
|
property alias title: realRoot.title
|
||||||
|
property real width: realRoot.width
|
||||||
|
property real height: realRoot.height
|
||||||
|
|
||||||
|
property int titleWidth: 0
|
||||||
|
property string iconText: hifi.glyphs.avatar
|
||||||
|
property int iconSize: 35
|
||||||
|
|
||||||
|
property var pane: QtObject {
|
||||||
|
property real width: root.width
|
||||||
|
property real height: root.height
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryDestroy() {
|
||||||
|
canceled()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//property int colorScheme: hifi.colorSchemes.dark
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
width: realRoot.width
|
||||||
|
height: realRoot.height
|
||||||
|
}
|
||||||
|
|
||||||
|
property bool keyboardOverride: true
|
||||||
|
|
||||||
|
property var items;
|
||||||
|
property string label: ""
|
||||||
|
|
||||||
|
//onTitleWidthChanged: d.resize();
|
||||||
|
|
||||||
|
//onKeyboardRaisedChanged: d.resize();
|
||||||
|
|
||||||
signal canceled();
|
signal canceled();
|
||||||
|
|
||||||
function updateIcon() {
|
|
||||||
if (!root) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
iconText = hifi.glyphForIcon(root.icon);
|
|
||||||
}
|
|
||||||
|
|
||||||
property alias bodyLoader: bodyLoader
|
property alias bodyLoader: bodyLoader
|
||||||
property alias loginDialog: loginDialog
|
property alias loginDialog: loginDialog
|
||||||
property alias hifi: hifi
|
property alias hifi: hifi
|
||||||
|
@ -65,9 +83,10 @@ TabletModalWindow {
|
||||||
HifiConstants { id: hifi }
|
HifiConstants { id: hifi }
|
||||||
|
|
||||||
onCanceled: {
|
onCanceled: {
|
||||||
if (loginDialogRoot.Stack.view) {
|
if (bodyLoader.active === true) {
|
||||||
loginDialogRoot.Stack.view.pop();
|
//bodyLoader.active = false
|
||||||
} else if (gotoPreviousApp) {
|
}
|
||||||
|
if (gotoPreviousApp) {
|
||||||
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
tablet.returnToPreviousApp();
|
tablet.returnToPreviousApp();
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,45 +94,81 @@ TabletModalWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TabletModalFrame {
|
||||||
|
id: mfRoot
|
||||||
|
|
||||||
|
width: root.width
|
||||||
|
height: root.height + frameMarginTop + hifi.dimensions.contentMargin.x
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
verticalCenter: parent.verticalCenter
|
||||||
|
verticalCenterOffset: -loginKeyboard.height / 2
|
||||||
|
}
|
||||||
|
|
||||||
LoginDialog {
|
LoginDialog {
|
||||||
id: loginDialog
|
id: loginDialog
|
||||||
width: parent.width
|
|
||||||
height: parent.height
|
anchors {
|
||||||
StackView {
|
fill: parent
|
||||||
|
topMargin: parent.frameMarginTop
|
||||||
|
leftMargin: hifi.dimensions.contentMargin.x
|
||||||
|
rightMargin: hifi.dimensions.contentMargin.x
|
||||||
|
horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Loader {
|
||||||
id: bodyLoader
|
id: bodyLoader
|
||||||
property var item: currentItem
|
|
||||||
property var props
|
|
||||||
property string source: ""
|
|
||||||
|
|
||||||
onCurrentItemChanged: {
|
|
||||||
//cleanup source for future usage
|
|
||||||
source = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSource(src, props) {
|
|
||||||
source = "../TabletLoginDialog/" + src
|
|
||||||
bodyLoader.props = props
|
|
||||||
}
|
|
||||||
function popup() {
|
|
||||||
bodyLoader.pop()
|
|
||||||
|
|
||||||
//check if last screen, if yes, dialog is popped out
|
|
||||||
if (depth === 1)
|
|
||||||
loginDialogRoot.canceled()
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: 10
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
onSourceChanged: {
|
source: loginDialog.isSteamRunning() ? "../LoginDialog/SignInBody.qml" : "../LoginDialog/LinkAccountBody.qml"
|
||||||
if (source !== "") {
|
|
||||||
bodyLoader.push(Qt.resolvedUrl(source), props)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Component.onCompleted: {
|
|
||||||
setSource(loginDialog.isSteamRunning() ?
|
|
||||||
"SignInBody.qml" :
|
|
||||||
"LinkAccountBody.qml")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Keyboard {
|
||||||
|
id: loginKeyboard
|
||||||
|
raised: root.keyboardEnabled && root.keyboardRaised
|
||||||
|
numeric: root.punctuationMode
|
||||||
|
anchors {
|
||||||
|
left: parent.left
|
||||||
|
right: parent.right
|
||||||
|
bottom: parent.bottom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Keys.onPressed: {
|
||||||
|
if (!visible) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.modifiers === Qt.ControlModifier)
|
||||||
|
switch (event.key) {
|
||||||
|
case Qt.Key_A:
|
||||||
|
event.accepted = true
|
||||||
|
detailedText.selectAll()
|
||||||
|
break
|
||||||
|
case Qt.Key_C:
|
||||||
|
event.accepted = true
|
||||||
|
detailedText.copy()
|
||||||
|
break
|
||||||
|
case Qt.Key_Period:
|
||||||
|
if (Qt.platform.os === "osx") {
|
||||||
|
event.accepted = true
|
||||||
|
content.reject()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
} else switch (event.key) {
|
||||||
|
case Qt.Key_Escape:
|
||||||
|
case Qt.Key_Back:
|
||||||
|
event.accepted = true
|
||||||
|
destroy()
|
||||||
|
break
|
||||||
|
|
||||||
|
case Qt.Key_Enter:
|
||||||
|
case Qt.Key_Return:
|
||||||
|
event.accepted = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,7 +171,7 @@ ScrollingWindow {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetMappingsError(errorString) {
|
function handleGetMappingsError(errorString) {
|
||||||
errorMessageBox("There was a problem retreiving the list of assets from your Asset Server.\n" + errorString);
|
errorMessageBox("There was a problem retrieving the list of assets from your Asset Server.\n" + errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToWorld() {
|
function addToWorld() {
|
||||||
|
|
|
@ -167,6 +167,9 @@ Rectangle {
|
||||||
}
|
}
|
||||||
RalewayRegular {
|
RalewayRegular {
|
||||||
anchors.verticalCenter: parent.verticalCenter;
|
anchors.verticalCenter: parent.verticalCenter;
|
||||||
|
width: margins.sizeText + margins.sizeLevel
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: margins.sizeCheckBox
|
||||||
size: 16;
|
size: 16;
|
||||||
color: hifi.colors.lightGrayText;
|
color: hifi.colors.lightGrayText;
|
||||||
text: qsTr("CHOOSE INPUT DEVICE");
|
text: qsTr("CHOOSE INPUT DEVICE");
|
||||||
|
|
|
@ -172,7 +172,7 @@ Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGetMappingsError(errorString) {
|
function handleGetMappingsError(errorString) {
|
||||||
errorMessageBox("There was a problem retreiving the list of assets from your Asset Server.\n" + errorString);
|
errorMessageBox("There was a problem retrieving the list of assets from your Asset Server.\n" + errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addToWorld() {
|
function addToWorld() {
|
||||||
|
|
|
@ -189,7 +189,6 @@
|
||||||
#include "InterfaceParentFinder.h"
|
#include "InterfaceParentFinder.h"
|
||||||
#include "ui/OctreeStatsProvider.h"
|
#include "ui/OctreeStatsProvider.h"
|
||||||
|
|
||||||
#include "FrameTimingsScriptingInterface.h"
|
|
||||||
#include <GPUIdent.h>
|
#include <GPUIdent.h>
|
||||||
#include <gl/GLHelpers.h>
|
#include <gl/GLHelpers.h>
|
||||||
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
|
#include <src/scripting/LimitlessVoiceRecognitionScriptingInterface.h>
|
||||||
|
@ -2023,7 +2022,8 @@ void Application::cleanupBeforeQuit() {
|
||||||
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
|
// The cleanup process enqueues the transactions but does not process them. Calling this here will force the actual
|
||||||
// removal of the items.
|
// removal of the items.
|
||||||
// See https://highfidelity.fogbugz.com/f/cases/5328
|
// See https://highfidelity.fogbugz.com/f/cases/5328
|
||||||
_main3DScene->processTransactionQueue();
|
_main3DScene->enqueueFrame(); // flush all the transactions
|
||||||
|
_main3DScene->processTransactionQueue(); // process and apply deletions
|
||||||
|
|
||||||
// first stop all timers directly or by invokeMethod
|
// first stop all timers directly or by invokeMethod
|
||||||
// depending on what thread they run in
|
// depending on what thread they run in
|
||||||
|
@ -2221,8 +2221,6 @@ void Application::initializeGL() {
|
||||||
update(0);
|
update(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
|
||||||
|
|
||||||
extern void setupPreferences();
|
extern void setupPreferences();
|
||||||
|
|
||||||
void Application::initializeUi() {
|
void Application::initializeUi() {
|
||||||
|
@ -2383,106 +2381,11 @@ void Application::initializeUi() {
|
||||||
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
offscreenSurfaceCache->reserve(Web3DOverlay::QML, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::paintGL() {
|
void Application::updateCamera(RenderArgs& renderArgs) {
|
||||||
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
|
||||||
if (_aboutToQuit || _window->isMinimized()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_renderFrameCount++;
|
|
||||||
_lastTimeRendered.start();
|
|
||||||
|
|
||||||
auto lastPaintBegin = usecTimestampNow();
|
|
||||||
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
|
||||||
PerformanceTimer perfTimer("paintGL");
|
|
||||||
|
|
||||||
if (nullptr == _displayPlugin) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DisplayPluginPointer displayPlugin;
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
|
||||||
displayPlugin = getActiveDisplayPlugin();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
|
||||||
// If a display plugin loses it's underlying support, it
|
|
||||||
// needs to be able to signal us to not use it
|
|
||||||
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
|
||||||
updateDisplayMode();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the avatar with a fresh HMD pose
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/updateAvatar");
|
|
||||||
getMyAvatar()->updateFromHMDSensorMatrix(getHMDSensorPose());
|
|
||||||
}
|
|
||||||
|
|
||||||
auto lodManager = DependencyManager::get<LODManager>();
|
|
||||||
|
|
||||||
RenderArgs renderArgs;
|
|
||||||
|
|
||||||
float sensorToWorldScale = getMyAvatar()->getSensorToWorldScale();
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
|
||||||
{
|
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
|
||||||
// adjust near clip plane to account for sensor scaling.
|
|
||||||
auto adjustedProjection = glm::perspective(_viewFrustum.getFieldOfView(),
|
|
||||||
_viewFrustum.getAspectRatio(),
|
|
||||||
DEFAULT_NEAR_CLIP * sensorToWorldScale,
|
|
||||||
_viewFrustum.getFarClip());
|
|
||||||
_viewFrustum.setProjection(adjustedProjection);
|
|
||||||
_viewFrustum.calculate();
|
|
||||||
}
|
|
||||||
renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
|
||||||
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
|
||||||
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
|
||||||
{
|
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
|
||||||
renderArgs.setViewFrustum(_viewFrustum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/resizeGL");
|
|
||||||
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
|
||||||
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
|
||||||
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
|
||||||
resizeGL();
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/gpuContextReset");
|
|
||||||
_gpuContext->beginFrame(getHMDSensorPose());
|
|
||||||
// Reset the gpu::Context Stages
|
|
||||||
// Back to the default framebuffer;
|
|
||||||
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
|
|
||||||
batch.resetStages();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/renderOverlay");
|
|
||||||
PerformanceTimer perfTimer("renderOverlay");
|
|
||||||
// NOTE: There is no batch associated with this renderArgs
|
|
||||||
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
|
||||||
QSize size = getDeviceSize();
|
|
||||||
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
|
||||||
_applicationOverlay.renderOverlay(&renderArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 boomOffset;
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/updateCamera");
|
PROFILE_RANGE(render, "/updateCamera");
|
||||||
{
|
|
||||||
PerformanceTimer perfTimer("CameraUpdates");
|
PerformanceTimer perfTimer("CameraUpdates");
|
||||||
|
|
||||||
|
glm::vec3 boomOffset;
|
||||||
auto myAvatar = getMyAvatar();
|
auto myAvatar = getMyAvatar();
|
||||||
boomOffset = myAvatar->getModelScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
boomOffset = myAvatar->getModelScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
||||||
|
|
||||||
|
@ -2497,27 +2400,32 @@ void Application::paintGL() {
|
||||||
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
_myCamera.setPosition(extractTranslation(camMat));
|
_myCamera.setPosition(extractTranslation(camMat));
|
||||||
_myCamera.setOrientation(glmExtractRotation(camMat));
|
_myCamera.setOrientation(glmExtractRotation(camMat));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
||||||
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
||||||
}
|
}
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
}
|
||||||
|
else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
_myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat)));
|
_myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat)));
|
||||||
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
||||||
myAvatar->getOrientation() * boomOffset);
|
myAvatar->getOrientation() * boomOffset);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
|
_myCamera.setOrientation(myAvatar->getHead()->getOrientation());
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::CenterPlayerInView)) {
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
+ _myCamera.getOrientation() * boomOffset);
|
+ _myCamera.getOrientation() * boomOffset);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
+ myAvatar->getOrientation() * boomOffset);
|
+ myAvatar->getOrientation() * boomOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
}
|
||||||
|
else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
auto mirrorBodyOrientation = myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
|
auto mirrorBodyOrientation = myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f));
|
||||||
|
|
||||||
|
@ -2540,7 +2448,8 @@ void Application::paintGL() {
|
||||||
+ glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0)
|
+ glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0)
|
||||||
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
||||||
+ mirrorBodyOrientation * hmdOffset);
|
+ mirrorBodyOrientation * hmdOffset);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_myCamera.setOrientation(myAvatar->getOrientation()
|
_myCamera.setOrientation(myAvatar->getOrientation()
|
||||||
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
|
@ -2549,7 +2458,8 @@ void Application::paintGL() {
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||||
}
|
}
|
||||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
|
}
|
||||||
|
else if (_myCamera.getMode() == CAMERA_MODE_ENTITY) {
|
||||||
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
|
EntityItemPointer cameraEntity = _myCamera.getCameraEntityPointer();
|
||||||
if (cameraEntity != nullptr) {
|
if (cameraEntity != nullptr) {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
|
@ -2557,7 +2467,8 @@ void Application::paintGL() {
|
||||||
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
|
_myCamera.setOrientation(cameraEntity->getRotation() * hmdRotation);
|
||||||
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
glm::vec3 hmdOffset = extractTranslation(myAvatar->getHMDSensorMatrix());
|
||||||
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
|
_myCamera.setPosition(cameraEntity->getPosition() + (hmdRotation * hmdOffset));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
_myCamera.setOrientation(cameraEntity->getRotation());
|
_myCamera.setOrientation(cameraEntity->getRotation());
|
||||||
_myCamera.setPosition(cameraEntity->getPosition());
|
_myCamera.setPosition(cameraEntity->getPosition());
|
||||||
}
|
}
|
||||||
|
@ -2567,117 +2478,8 @@ void Application::paintGL() {
|
||||||
if (!isHMDMode()) {
|
if (!isHMDMode()) {
|
||||||
_myCamera.update();
|
_myCamera.update();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
renderArgs._cameraMode = (int8_t)_myCamera.getMode();
|
||||||
PROFILE_RANGE(render, "/updateCompositor");
|
|
||||||
getApplicationCompositor().setFrameInfo(_renderFrameCount, _myCamera.getTransform(), getMyAvatar()->getSensorToWorldMatrix());
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::FramebufferPointer finalFramebuffer;
|
|
||||||
QSize finalFramebufferSize;
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/getOutputFramebuffer");
|
|
||||||
// Primary rendering pass
|
|
||||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
|
||||||
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
|
||||||
// Final framebuffer that will be handled to the display-plugin
|
|
||||||
finalFramebuffer = framebufferCache->getFramebuffer();
|
|
||||||
}
|
|
||||||
|
|
||||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
|
||||||
float ipdScale = hmdInterface->getIPDScale();
|
|
||||||
|
|
||||||
// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
|
|
||||||
ipdScale *= sensorToWorldScale;
|
|
||||||
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/mainRender");
|
|
||||||
PerformanceTimer perfTimer("mainRender");
|
|
||||||
renderArgs._boomOffset = boomOffset;
|
|
||||||
// FIXME is this ever going to be different from the size previously set in the render args
|
|
||||||
// in the overlay render?
|
|
||||||
// Viewport is assigned to the size of the framebuffer
|
|
||||||
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
|
|
||||||
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
|
||||||
if (displayPlugin->isStereo()) {
|
|
||||||
// Stereo modes will typically have a larger projection matrix overall,
|
|
||||||
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
|
||||||
// plugins will imply the combined projection for both eyes.
|
|
||||||
//
|
|
||||||
// This is properly implemented for the Oculus plugins, but for OpenVR
|
|
||||||
// and Stereo displays I'm not sure how to get / calculate it, so we're
|
|
||||||
// just relying on the left FOV in each case and hoping that the
|
|
||||||
// overall culling margin of error doesn't cause popping in the
|
|
||||||
// right eye. There are FIXMEs in the relevant plugins
|
|
||||||
_myCamera.setProjection(displayPlugin->getCullingProjection(baseProjection));
|
|
||||||
renderArgs._context->enableStereo(true);
|
|
||||||
mat4 eyeOffsets[2];
|
|
||||||
mat4 eyeProjections[2];
|
|
||||||
|
|
||||||
// FIXME we probably don't need to set the projection matrix every frame,
|
|
||||||
// only when the display plugin changes (or in non-HMD modes when the user
|
|
||||||
// changes the FOV manually, which right now I don't think they can.
|
|
||||||
for_each_eye([&](Eye eye) {
|
|
||||||
// For providing the stereo eye views, the HMD head pose has already been
|
|
||||||
// applied to the avatar, so we need to get the difference between the head
|
|
||||||
// pose applied to the avatar and the per eye pose, and use THAT as
|
|
||||||
// the per-eye stereo matrix adjustment.
|
|
||||||
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
|
|
||||||
// Grab the translation
|
|
||||||
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
|
||||||
// Apply IPD scaling
|
|
||||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
|
||||||
eyeOffsets[eye] = eyeOffsetTransform;
|
|
||||||
eyeProjections[eye] = displayPlugin->getEyeProjection(eye, baseProjection);
|
|
||||||
});
|
|
||||||
renderArgs._context->setStereoProjections(eyeProjections);
|
|
||||||
renderArgs._context->setStereoViews(eyeOffsets);
|
|
||||||
|
|
||||||
// Configure the type of display / stereo
|
|
||||||
renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
|
|
||||||
}
|
|
||||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
|
||||||
displaySide(&renderArgs, _myCamera);
|
|
||||||
}
|
|
||||||
|
|
||||||
gpu::Batch postCompositeBatch;
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/postComposite");
|
|
||||||
PerformanceTimer perfTimer("postComposite");
|
|
||||||
renderArgs._batch = &postCompositeBatch;
|
|
||||||
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
|
||||||
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
|
||||||
_overlays.render3DHUDOverlays(&renderArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto frame = _gpuContext->endFrame();
|
|
||||||
frame->frameIndex = _renderFrameCount;
|
|
||||||
frame->framebuffer = finalFramebuffer;
|
|
||||||
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer){
|
|
||||||
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
|
|
||||||
};
|
|
||||||
frame->overlay = _applicationOverlay.getOverlayTexture();
|
|
||||||
frame->postCompositeBatch = postCompositeBatch;
|
|
||||||
// deliver final scene rendering commands to the display plugin
|
|
||||||
{
|
|
||||||
PROFILE_RANGE(render, "/pluginOutput");
|
|
||||||
PerformanceTimer perfTimer("pluginOutput");
|
|
||||||
_renderLoopCounter.increment();
|
|
||||||
displayPlugin->submitFrame(frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reset the framebuffer and stereo state
|
|
||||||
renderArgs._blitFramebuffer.reset();
|
|
||||||
renderArgs._context->enableStereo(false);
|
|
||||||
|
|
||||||
{
|
|
||||||
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
|
||||||
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::runTests() {
|
void Application::runTests() {
|
||||||
|
@ -5225,6 +5027,7 @@ void Application::update(float deltaTime) {
|
||||||
|
|
||||||
avatarManager->postUpdate(deltaTime, getMain3DScene());
|
avatarManager->postUpdate(deltaTime, getMain3DScene());
|
||||||
|
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE_EX(app, "PreRenderLambdas", 0xffff0000, (uint64_t)0);
|
PROFILE_RANGE_EX(app, "PreRenderLambdas", 0xffff0000, (uint64_t)0);
|
||||||
|
|
||||||
|
@ -5235,9 +5038,123 @@ void Application::update(float deltaTime) {
|
||||||
_postUpdateLambdas.clear();
|
_postUpdateLambdas.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editRenderArgs([this](AppRenderArgs& appRenderArgs) {
|
||||||
|
appRenderArgs._headPose= getHMDSensorPose();
|
||||||
|
|
||||||
|
auto myAvatar = getMyAvatar();
|
||||||
|
|
||||||
|
// update the avatar with a fresh HMD pose
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/updateAvatar");
|
||||||
|
myAvatar->updateFromHMDSensorMatrix(appRenderArgs._headPose);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lodManager = DependencyManager::get<LODManager>();
|
||||||
|
|
||||||
|
float sensorToWorldScale = getMyAvatar()->getSensorToWorldScale();
|
||||||
|
appRenderArgs._sensorToWorldScale = sensorToWorldScale;
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
||||||
|
{
|
||||||
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
// adjust near clip plane to account for sensor scaling.
|
||||||
|
auto adjustedProjection = glm::perspective(_viewFrustum.getFieldOfView(),
|
||||||
|
_viewFrustum.getAspectRatio(),
|
||||||
|
DEFAULT_NEAR_CLIP * sensorToWorldScale,
|
||||||
|
_viewFrustum.getFarClip());
|
||||||
|
_viewFrustum.setProjection(adjustedProjection);
|
||||||
|
_viewFrustum.calculate();
|
||||||
|
}
|
||||||
|
appRenderArgs._renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
||||||
|
lodManager->getBoundaryLevelAdjust(), RenderArgs::DEFAULT_RENDER_MODE,
|
||||||
|
RenderArgs::MONO, RenderArgs::RENDER_DEBUG_NONE);
|
||||||
|
appRenderArgs._renderArgs._scene = getMain3DScene();
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
appRenderArgs._renderArgs.setViewFrustum(_viewFrustum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/resizeGL");
|
||||||
|
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
|
||||||
|
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
|
||||||
|
PerformanceWarning warn(showWarnings, "Application::paintGL()");
|
||||||
|
resizeGL();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->updateCamera(appRenderArgs._renderArgs);
|
||||||
|
appRenderArgs._isStereo = false;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
float ipdScale = hmdInterface->getIPDScale();
|
||||||
|
|
||||||
|
// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
|
||||||
|
ipdScale *= sensorToWorldScale;
|
||||||
|
|
||||||
|
auto baseProjection = appRenderArgs._renderArgs.getViewFrustum().getProjection();
|
||||||
|
if (getActiveDisplayPlugin()->isStereo()) {
|
||||||
|
// Stereo modes will typically have a larger projection matrix overall,
|
||||||
|
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
||||||
|
// plugins will imply the combined projection for both eyes.
|
||||||
|
//
|
||||||
|
// This is properly implemented for the Oculus plugins, but for OpenVR
|
||||||
|
// and Stereo displays I'm not sure how to get / calculate it, so we're
|
||||||
|
// just relying on the left FOV in each case and hoping that the
|
||||||
|
// overall culling margin of error doesn't cause popping in the
|
||||||
|
// right eye. There are FIXMEs in the relevant plugins
|
||||||
|
_myCamera.setProjection(getActiveDisplayPlugin()->getCullingProjection(baseProjection));
|
||||||
|
appRenderArgs._isStereo = true;
|
||||||
|
|
||||||
|
auto& eyeOffsets = appRenderArgs._eyeOffsets;
|
||||||
|
auto& eyeProjections = appRenderArgs._eyeProjections;
|
||||||
|
|
||||||
|
// FIXME we probably don't need to set the projection matrix every frame,
|
||||||
|
// only when the display plugin changes (or in non-HMD modes when the user
|
||||||
|
// changes the FOV manually, which right now I don't think they can.
|
||||||
|
for_each_eye([&](Eye eye) {
|
||||||
|
// For providing the stereo eye views, the HMD head pose has already been
|
||||||
|
// applied to the avatar, so we need to get the difference between the head
|
||||||
|
// pose applied to the avatar and the per eye pose, and use THAT as
|
||||||
|
// the per-eye stereo matrix adjustment.
|
||||||
|
mat4 eyeToHead = getActiveDisplayPlugin()->getEyeToHeadTransform(eye);
|
||||||
|
// Grab the translation
|
||||||
|
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||||
|
// Apply IPD scaling
|
||||||
|
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
||||||
|
eyeOffsets[eye] = eyeOffsetTransform;
|
||||||
|
eyeProjections[eye] = getActiveDisplayPlugin()->getEyeProjection(eye, baseProjection);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Configure the type of display / stereo
|
||||||
|
appRenderArgs._renderArgs._displayMode = (isHMDMode() ? RenderArgs::STEREO_HMD : RenderArgs::STEREO_MONITOR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK
|
||||||
|
// load the view frustum
|
||||||
|
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||||
|
// Then we can move this logic into the Avatar::simulate call.
|
||||||
|
myAvatar->preDisplaySide(&appRenderArgs._renderArgs);
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
_myCamera.loadViewFrustum(_displayViewFrustum);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
appRenderArgs._renderArgs.setViewFrustum(_displayViewFrustum);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
AnimDebugDraw::getInstance().update();
|
AnimDebugDraw::getInstance().update();
|
||||||
|
|
||||||
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->update();
|
DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>()->update();
|
||||||
|
|
||||||
|
// Game loop is done, mark the end of the frame for the scene transactions and the render loop to take over
|
||||||
|
getMain3DScene()->enqueueFrame();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::sendAvatarViewFrustum() {
|
void Application::sendAvatarViewFrustum() {
|
||||||
|
@ -5296,7 +5213,6 @@ int Application::sendNackPackets() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
return packetsSent;
|
return packetsSent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5527,116 +5443,6 @@ void Application::copyDisplayViewFrustum(ViewFrustum& viewOut) const {
|
||||||
viewOut = _displayViewFrustum;
|
viewOut = _displayViewFrustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::copyShadowViewFrustum(ViewFrustum& viewOut) const {
|
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
|
||||||
viewOut = _shadowViewFrustum;
|
|
||||||
}
|
|
||||||
|
|
||||||
// WorldBox Render Data & rendering functions
|
|
||||||
|
|
||||||
class WorldBoxRenderData {
|
|
||||||
public:
|
|
||||||
typedef render::Payload<WorldBoxRenderData> Payload;
|
|
||||||
typedef Payload::DataPointer Pointer;
|
|
||||||
|
|
||||||
int _val = 0;
|
|
||||||
static render::ItemID _item; // unique WorldBoxRenderData
|
|
||||||
};
|
|
||||||
|
|
||||||
render::ItemID WorldBoxRenderData::_item { render::Item::INVALID_ITEM_ID };
|
|
||||||
|
|
||||||
namespace render {
|
|
||||||
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
|
||||||
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
|
||||||
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
|
||||||
PerformanceTimer perfTimer("worldBox");
|
|
||||||
|
|
||||||
auto& batch = *args->_batch;
|
|
||||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
|
||||||
renderWorldBox(args, batch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
|
|
||||||
|
|
||||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
|
||||||
// Then we can move this logic into the Avatar::simulate call.
|
|
||||||
auto myAvatar = getMyAvatar();
|
|
||||||
myAvatar->preDisplaySide(renderArgs);
|
|
||||||
|
|
||||||
PROFILE_RANGE(render, __FUNCTION__);
|
|
||||||
PerformanceTimer perfTimer("display");
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide()");
|
|
||||||
|
|
||||||
// load the view frustum
|
|
||||||
{
|
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
|
||||||
theCamera.loadViewFrustum(_displayViewFrustum);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO fix shadows and make them use the GPU library
|
|
||||||
|
|
||||||
// The pending changes collecting the changes here
|
|
||||||
render::Transaction transaction;
|
|
||||||
|
|
||||||
// Assuming nothing gets rendered through that
|
|
||||||
if (!selfAvatarOnly) {
|
|
||||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
|
||||||
// render models...
|
|
||||||
PerformanceTimer perfTimer("entities");
|
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
|
||||||
"Application::displaySide() ... entities...");
|
|
||||||
|
|
||||||
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
|
||||||
|
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
|
||||||
renderDebugFlags = static_cast<RenderArgs::DebugFlags>(renderDebugFlags |
|
|
||||||
static_cast<int>(RenderArgs::RENDER_DEBUG_HULLS));
|
|
||||||
}
|
|
||||||
renderArgs->_debugFlags = renderDebugFlags;
|
|
||||||
//ViveControllerManager::getInstance().updateRendering(renderArgs, _main3DScene, transaction);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME: Move this out of here!, WorldBox should be driven by the entity content just like the other entities
|
|
||||||
// Make sure the WorldBox is in the scene
|
|
||||||
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
|
||||||
auto worldBoxRenderData = make_shared<WorldBoxRenderData>();
|
|
||||||
auto worldBoxRenderPayload = make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
|
||||||
|
|
||||||
WorldBoxRenderData::_item = _main3DScene->allocateID();
|
|
||||||
|
|
||||||
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
|
||||||
} else {
|
|
||||||
transaction.updateItem<WorldBoxRenderData>(WorldBoxRenderData::_item,
|
|
||||||
[](WorldBoxRenderData& payload) {
|
|
||||||
payload._val++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
_main3DScene->enqueueTransaction(transaction);
|
|
||||||
}
|
|
||||||
|
|
||||||
// For now every frame pass the renderContext
|
|
||||||
{
|
|
||||||
PerformanceTimer perfTimer("EngineRun");
|
|
||||||
|
|
||||||
{
|
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
|
||||||
renderArgs->setViewFrustum(_displayViewFrustum);
|
|
||||||
}
|
|
||||||
renderArgs->_cameraMode = (int8_t)theCamera.getMode(); // HACK
|
|
||||||
renderArgs->_scene = getMain3DScene();
|
|
||||||
_renderEngine->getRenderContext()->args = renderArgs;
|
|
||||||
|
|
||||||
// Before the deferred pass, let's try to use the render engine
|
|
||||||
_renderEngine->run();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::resetSensors(bool andReload) {
|
void Application::resetSensors(bool andReload) {
|
||||||
DependencyManager::get<DdeFaceTracker>()->reset();
|
DependencyManager::get<DdeFaceTracker>()->reset();
|
||||||
DependencyManager::get<EyeTracker>()->reset();
|
DependencyManager::get<EyeTracker>()->reset();
|
||||||
|
@ -7677,5 +7483,4 @@ void Application::setAvatarOverrideUrl(const QUrl& url, bool save) {
|
||||||
_avatarOverrideUrl = url;
|
_avatarOverrideUrl = url;
|
||||||
_saveAvatarOverrideUrl = save;
|
_saveAvatarOverrideUrl = save;
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "Application.moc"
|
#include "Application.moc"
|
||||||
|
|
|
@ -76,6 +76,7 @@
|
||||||
#include <procedural/ProceduralSkybox.h>
|
#include <procedural/ProceduralSkybox.h>
|
||||||
#include <model/Skybox.h>
|
#include <model/Skybox.h>
|
||||||
#include <ModelScriptingInterface.h>
|
#include <ModelScriptingInterface.h>
|
||||||
|
#include "FrameTimingsScriptingInterface.h"
|
||||||
|
|
||||||
#include "Sound.h"
|
#include "Sound.h"
|
||||||
|
|
||||||
|
@ -147,6 +148,8 @@ public:
|
||||||
|
|
||||||
void initializeGL();
|
void initializeGL();
|
||||||
void initializeUi();
|
void initializeUi();
|
||||||
|
|
||||||
|
void updateCamera(RenderArgs& renderArgs);
|
||||||
void paintGL();
|
void paintGL();
|
||||||
void resizeGL();
|
void resizeGL();
|
||||||
|
|
||||||
|
@ -173,7 +176,6 @@ public:
|
||||||
// which might be different from the viewFrustum, i.e. shadowmap
|
// which might be different from the viewFrustum, i.e. shadowmap
|
||||||
// passes, mirror window passes, etc
|
// passes, mirror window passes, etc
|
||||||
void copyDisplayViewFrustum(ViewFrustum& viewOut) const;
|
void copyDisplayViewFrustum(ViewFrustum& viewOut) const;
|
||||||
void copyShadowViewFrustum(ViewFrustum& viewOut) const override;
|
|
||||||
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; }
|
||||||
QSharedPointer<EntityTreeRenderer> getEntities() const { return DependencyManager::get<EntityTreeRenderer>(); }
|
QSharedPointer<EntityTreeRenderer> getEntities() const { return DependencyManager::get<EntityTreeRenderer>(); }
|
||||||
QUndoStack* getUndoStack() { return &_undoStack; }
|
QUndoStack* getUndoStack() { return &_undoStack; }
|
||||||
|
@ -467,8 +469,6 @@ private:
|
||||||
|
|
||||||
void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions);
|
void queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions);
|
||||||
|
|
||||||
void renderRearViewMirror(RenderArgs* renderArgs, const QRect& region, bool isZoomed);
|
|
||||||
|
|
||||||
int sendNackPackets();
|
int sendNackPackets();
|
||||||
void sendAvatarViewFrustum();
|
void sendAvatarViewFrustum();
|
||||||
|
|
||||||
|
@ -478,7 +478,7 @@ private:
|
||||||
|
|
||||||
void initializeAcceptedFiles();
|
void initializeAcceptedFiles();
|
||||||
|
|
||||||
void displaySide(RenderArgs* renderArgs, Camera& whichCamera, bool selfAvatarOnly = false);
|
void runRenderFrame(RenderArgs* renderArgs/*, Camera& whichCamera, bool selfAvatarOnly = false*/);
|
||||||
|
|
||||||
bool importJSONFromURL(const QString& urlString);
|
bool importJSONFromURL(const QString& urlString);
|
||||||
bool importSVOFromURL(const QString& urlString);
|
bool importSVOFromURL(const QString& urlString);
|
||||||
|
@ -535,6 +535,8 @@ private:
|
||||||
RateCounter<500> _renderLoopCounter;
|
RateCounter<500> _renderLoopCounter;
|
||||||
RateCounter<500> _gameLoopCounter;
|
RateCounter<500> _gameLoopCounter;
|
||||||
|
|
||||||
|
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||||
|
|
||||||
QTimer _minimizedWindowTimer;
|
QTimer _minimizedWindowTimer;
|
||||||
QElapsedTimer _timerStart;
|
QElapsedTimer _timerStart;
|
||||||
QElapsedTimer _lastTimeUpdated;
|
QElapsedTimer _lastTimeUpdated;
|
||||||
|
@ -550,7 +552,6 @@ private:
|
||||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||||
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels)
|
ViewFrustum _lastQueriedViewFrustum; /// last view frustum used to query octree servers (voxels)
|
||||||
ViewFrustum _displayViewFrustum;
|
ViewFrustum _displayViewFrustum;
|
||||||
ViewFrustum _shadowViewFrustum;
|
|
||||||
quint64 _lastQueriedTime;
|
quint64 _lastQueriedTime;
|
||||||
|
|
||||||
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
OctreeQuery _octreeQuery; // NodeData derived class for querying octee cells from octree servers
|
||||||
|
@ -621,6 +622,24 @@ private:
|
||||||
render::EnginePointer _renderEngine{ new render::Engine() };
|
render::EnginePointer _renderEngine{ new render::Engine() };
|
||||||
gpu::ContextPointer _gpuContext; // initialized during window creation
|
gpu::ContextPointer _gpuContext; // initialized during window creation
|
||||||
|
|
||||||
|
mutable QMutex _renderArgsMutex{ QMutex::Recursive };
|
||||||
|
struct AppRenderArgs {
|
||||||
|
render::Args _renderArgs;
|
||||||
|
glm::mat4 _eyeToWorld;
|
||||||
|
glm::mat4 _eyeOffsets[2];
|
||||||
|
glm::mat4 _eyeProjections[2];
|
||||||
|
glm::mat4 _headPose;
|
||||||
|
glm::mat4 _sensorToWorld;
|
||||||
|
float _sensorToWorldScale { 1.0f };
|
||||||
|
bool _isStereo{ false };
|
||||||
|
};
|
||||||
|
AppRenderArgs _appRenderArgs;
|
||||||
|
|
||||||
|
|
||||||
|
using RenderArgsEditor = std::function <void (AppRenderArgs&)>;
|
||||||
|
void editRenderArgs(RenderArgsEditor editor);
|
||||||
|
|
||||||
|
|
||||||
Overlays _overlays;
|
Overlays _overlays;
|
||||||
ApplicationOverlay _applicationOverlay;
|
ApplicationOverlay _applicationOverlay;
|
||||||
OverlayConductor _overlayConductor;
|
OverlayConductor _overlayConductor;
|
||||||
|
|
240
interface/src/Application_render.cpp
Normal file
240
interface/src/Application_render.cpp
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
//
|
||||||
|
// Application_render.cpp
|
||||||
|
// interface/src
|
||||||
|
//
|
||||||
|
// 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 "Application.h"
|
||||||
|
#include <MainWindow.h>
|
||||||
|
|
||||||
|
#include <display-plugins/CompositorHelper.h>
|
||||||
|
#include <FramebufferCache.h>
|
||||||
|
#include "ui/Stats.h"
|
||||||
|
#include <SceneScriptingInterface.h>
|
||||||
|
#include "Util.h"
|
||||||
|
|
||||||
|
|
||||||
|
// Statically provided display and input plugins
|
||||||
|
extern DisplayPluginList getDisplayPlugins();
|
||||||
|
|
||||||
|
void Application::editRenderArgs(RenderArgsEditor editor) {
|
||||||
|
QMutexLocker renderLocker(&_renderArgsMutex);
|
||||||
|
editor(_appRenderArgs);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::paintGL() {
|
||||||
|
// Some plugins process message events, allowing paintGL to be called reentrantly.
|
||||||
|
if (_aboutToQuit || _window->isMinimized()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderFrameCount++;
|
||||||
|
_lastTimeRendered.start();
|
||||||
|
|
||||||
|
auto lastPaintBegin = usecTimestampNow();
|
||||||
|
PROFILE_RANGE_EX(render, __FUNCTION__, 0xff0000ff, (uint64_t)_renderFrameCount);
|
||||||
|
PerformanceTimer perfTimer("paintGL");
|
||||||
|
|
||||||
|
if (nullptr == _displayPlugin) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DisplayPluginPointer displayPlugin;
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/getActiveDisplayPlugin");
|
||||||
|
displayPlugin = getActiveDisplayPlugin();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/pluginBeginFrameRender");
|
||||||
|
// If a display plugin loses it's underlying support, it
|
||||||
|
// needs to be able to signal us to not use it
|
||||||
|
if (!displayPlugin->beginFrameRender(_renderFrameCount)) {
|
||||||
|
updateDisplayMode();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RenderArgs renderArgs;
|
||||||
|
glm::mat4 HMDSensorPose;
|
||||||
|
glm::mat4 eyeToWorld;
|
||||||
|
glm::mat4 sensorToWorld;
|
||||||
|
|
||||||
|
bool isStereo;
|
||||||
|
glm::mat4 stereoEyeOffsets[2];
|
||||||
|
glm::mat4 stereoEyeProjections[2];
|
||||||
|
|
||||||
|
{
|
||||||
|
QMutexLocker viewLocker(&_renderArgsMutex);
|
||||||
|
renderArgs = _appRenderArgs._renderArgs;
|
||||||
|
HMDSensorPose = _appRenderArgs._headPose;
|
||||||
|
eyeToWorld = _appRenderArgs._eyeToWorld;
|
||||||
|
sensorToWorld = _appRenderArgs._sensorToWorld;
|
||||||
|
isStereo = _appRenderArgs._isStereo;
|
||||||
|
for_each_eye([&](Eye eye) {
|
||||||
|
stereoEyeOffsets[eye] = _appRenderArgs._eyeOffsets[eye];
|
||||||
|
stereoEyeProjections[eye] = _appRenderArgs._eyeProjections[eye];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/gpuContextReset");
|
||||||
|
_gpuContext->beginFrame(HMDSensorPose);
|
||||||
|
// Reset the gpu::Context Stages
|
||||||
|
// Back to the default framebuffer;
|
||||||
|
gpu::doInBatch(_gpuContext, [&](gpu::Batch& batch) {
|
||||||
|
batch.resetStages();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/renderOverlay");
|
||||||
|
PerformanceTimer perfTimer("renderOverlay");
|
||||||
|
// NOTE: There is no batch associated with this renderArgs
|
||||||
|
// the ApplicationOverlay class assumes it's viewport is setup to be the device size
|
||||||
|
QSize size = getDeviceSize();
|
||||||
|
renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height());
|
||||||
|
_applicationOverlay.renderOverlay(&renderArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/updateCompositor");
|
||||||
|
getApplicationCompositor().setFrameInfo(_renderFrameCount, eyeToWorld, sensorToWorld);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::FramebufferPointer finalFramebuffer;
|
||||||
|
QSize finalFramebufferSize;
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/getOutputFramebuffer");
|
||||||
|
// Primary rendering pass
|
||||||
|
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||||
|
finalFramebufferSize = framebufferCache->getFrameBufferSize();
|
||||||
|
// Final framebuffer that will be handled to the display-plugin
|
||||||
|
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
if (isStereo) {
|
||||||
|
renderArgs._context->enableStereo(true);
|
||||||
|
renderArgs._context->setStereoProjections(stereoEyeProjections);
|
||||||
|
renderArgs._context->setStereoViews(stereoEyeOffsets);
|
||||||
|
}
|
||||||
|
|
||||||
|
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||||
|
runRenderFrame(&renderArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
gpu::Batch postCompositeBatch;
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/postComposite");
|
||||||
|
PerformanceTimer perfTimer("postComposite");
|
||||||
|
renderArgs._batch = &postCompositeBatch;
|
||||||
|
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
||||||
|
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
||||||
|
_overlays.render3DHUDOverlays(&renderArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto frame = _gpuContext->endFrame();
|
||||||
|
frame->frameIndex = _renderFrameCount;
|
||||||
|
frame->framebuffer = finalFramebuffer;
|
||||||
|
frame->framebufferRecycler = [](const gpu::FramebufferPointer& framebuffer) {
|
||||||
|
DependencyManager::get<FramebufferCache>()->releaseFramebuffer(framebuffer);
|
||||||
|
};
|
||||||
|
frame->overlay = _applicationOverlay.getOverlayTexture();
|
||||||
|
frame->postCompositeBatch = postCompositeBatch;
|
||||||
|
// deliver final scene rendering commands to the display plugin
|
||||||
|
{
|
||||||
|
PROFILE_RANGE(render, "/pluginOutput");
|
||||||
|
PerformanceTimer perfTimer("pluginOutput");
|
||||||
|
_renderLoopCounter.increment();
|
||||||
|
displayPlugin->submitFrame(frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the framebuffer and stereo state
|
||||||
|
renderArgs._blitFramebuffer.reset();
|
||||||
|
renderArgs._context->enableStereo(false);
|
||||||
|
|
||||||
|
{
|
||||||
|
Stats::getInstance()->setRenderDetails(renderArgs._details);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t lastPaintDuration = usecTimestampNow() - lastPaintBegin;
|
||||||
|
_frameTimingsScriptingInterface.addValue(lastPaintDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// WorldBox Render Data & rendering functions
|
||||||
|
|
||||||
|
class WorldBoxRenderData {
|
||||||
|
public:
|
||||||
|
typedef render::Payload<WorldBoxRenderData> Payload;
|
||||||
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
|
int _val = 0;
|
||||||
|
static render::ItemID _item; // unique WorldBoxRenderData
|
||||||
|
};
|
||||||
|
|
||||||
|
render::ItemID WorldBoxRenderData::_item{ render::Item::INVALID_ITEM_ID };
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
template <> const ItemKey payloadGetKey(const WorldBoxRenderData::Pointer& stuff) { return ItemKey::Builder::opaqueShape(); }
|
||||||
|
template <> const Item::Bound payloadGetBound(const WorldBoxRenderData::Pointer& stuff) { return Item::Bound(); }
|
||||||
|
template <> void payloadRender(const WorldBoxRenderData::Pointer& stuff, RenderArgs* args) {
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::WorldAxes)) {
|
||||||
|
PerformanceTimer perfTimer("worldBox");
|
||||||
|
|
||||||
|
auto& batch = *args->_batch;
|
||||||
|
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch);
|
||||||
|
renderWorldBox(args, batch);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Application::runRenderFrame(RenderArgs* renderArgs) {
|
||||||
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
|
PerformanceTimer perfTimer("display");
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::runRenderFrame()");
|
||||||
|
|
||||||
|
// The pending changes collecting the changes here
|
||||||
|
render::Transaction transaction;
|
||||||
|
|
||||||
|
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderEntities()) {
|
||||||
|
// render models...
|
||||||
|
PerformanceTimer perfTimer("entities");
|
||||||
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
|
"Application::runRenderFrame() ... entities...");
|
||||||
|
|
||||||
|
RenderArgs::DebugFlags renderDebugFlags = RenderArgs::RENDER_DEBUG_NONE;
|
||||||
|
|
||||||
|
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowHulls)) {
|
||||||
|
renderDebugFlags = static_cast<RenderArgs::DebugFlags>(renderDebugFlags |
|
||||||
|
static_cast<int>(RenderArgs::RENDER_DEBUG_HULLS));
|
||||||
|
}
|
||||||
|
renderArgs->_debugFlags = renderDebugFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the WorldBox is in the scene
|
||||||
|
// For the record, this one RenderItem is the first one we created and added to the scene.
|
||||||
|
// We could meoee that code elsewhere but you know...
|
||||||
|
if (!render::Item::isValidID(WorldBoxRenderData::_item)) {
|
||||||
|
auto worldBoxRenderData = std::make_shared<WorldBoxRenderData>();
|
||||||
|
auto worldBoxRenderPayload = std::make_shared<WorldBoxRenderData::Payload>(worldBoxRenderData);
|
||||||
|
|
||||||
|
WorldBoxRenderData::_item = _main3DScene->allocateID();
|
||||||
|
|
||||||
|
transaction.resetItem(WorldBoxRenderData::_item, worldBoxRenderPayload);
|
||||||
|
_main3DScene->enqueueTransaction(transaction);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PerformanceTimer perfTimer("EngineRun");
|
||||||
|
_renderEngine->getRenderContext()->args = renderArgs;
|
||||||
|
_renderEngine->run();
|
||||||
|
}
|
||||||
|
}
|
|
@ -49,11 +49,13 @@ LaserPointer::~LaserPointer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::enable() {
|
void LaserPointer::enable() {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
DependencyManager::get<RayPickScriptingInterface>()->enableRayPick(_rayPickUID);
|
DependencyManager::get<RayPickScriptingInterface>()->enableRayPick(_rayPickUID);
|
||||||
_renderingEnabled = true;
|
_renderingEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::disable() {
|
void LaserPointer::disable() {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
DependencyManager::get<RayPickScriptingInterface>()->disableRayPick(_rayPickUID);
|
DependencyManager::get<RayPickScriptingInterface>()->disableRayPick(_rayPickUID);
|
||||||
_renderingEnabled = false;
|
_renderingEnabled = false;
|
||||||
if (!_currentRenderState.empty()) {
|
if (!_currentRenderState.empty()) {
|
||||||
|
@ -67,6 +69,7 @@ void LaserPointer::disable() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::setRenderState(const std::string& state) {
|
void LaserPointer::setRenderState(const std::string& state) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
if (!_currentRenderState.empty() && state != _currentRenderState) {
|
if (!_currentRenderState.empty() && state != _currentRenderState) {
|
||||||
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
|
if (_renderStates.find(_currentRenderState) != _renderStates.end()) {
|
||||||
disableRenderState(_renderStates[_currentRenderState]);
|
disableRenderState(_renderStates[_currentRenderState]);
|
||||||
|
@ -79,6 +82,7 @@ void LaserPointer::setRenderState(const std::string& state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
|
void LaserPointer::editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
updateRenderStateOverlay(_renderStates[state].getStartID(), startProps);
|
updateRenderStateOverlay(_renderStates[state].getStartID(), startProps);
|
||||||
updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps);
|
updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps);
|
||||||
updateRenderStateOverlay(_renderStates[state].getEndID(), endProps);
|
updateRenderStateOverlay(_renderStates[state].getEndID(), endProps);
|
||||||
|
@ -92,6 +96,11 @@ void LaserPointer::updateRenderStateOverlay(const OverlayID& id, const QVariant&
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const RayPickResult LaserPointer::getPrevRayPickResult() {
|
||||||
|
QReadLocker lock(getLock());
|
||||||
|
return DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
||||||
|
}
|
||||||
|
|
||||||
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
|
void LaserPointer::updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState) {
|
||||||
if (!renderState.getStartID().isNull()) {
|
if (!renderState.getStartID().isNull()) {
|
||||||
QVariantMap startProps;
|
QVariantMap startProps;
|
||||||
|
@ -183,6 +192,8 @@ void LaserPointer::disableRenderState(const RenderState& renderState) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointer::update() {
|
void LaserPointer::update() {
|
||||||
|
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
||||||
|
QReadLocker lock(getLock());
|
||||||
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
RayPickResult prevRayPickResult = DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID);
|
||||||
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
|
if (_renderingEnabled && !_currentRenderState.empty() && _renderStates.find(_currentRenderState) != _renderStates.end() &&
|
||||||
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
|
(prevRayPickResult.type != IntersectionType::NONE || _laserLength > 0.0f || !_objectLockEnd.first.isNull())) {
|
||||||
|
@ -198,6 +209,51 @@ void LaserPointer::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setPrecisionPicking(const bool precisionPicking) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setLaserLength(const float laserLength) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_laserLength = laserLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setLockEndUUID(QUuid objectID, const bool isOverlay) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIgnoreEntities(const QScriptValue& ignoreEntities) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIncludeEntities(const QScriptValue& includeEntities) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIgnoreOverlays(const QScriptValue& ignoreOverlays) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIncludeOverlays(const QScriptValue& includeOverlays) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIncludeOverlays(_rayPickUID, includeOverlays);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIgnoreAvatars(const QScriptValue& ignoreAvatars) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIgnoreAvatars(_rayPickUID, ignoreAvatars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LaserPointer::setIncludeAvatars(const QScriptValue& includeAvatars) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
DependencyManager::get<RayPickScriptingInterface>()->setIncludeAvatars(_rayPickUID, includeAvatars);
|
||||||
|
}
|
||||||
|
|
||||||
RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :
|
RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, const OverlayID& endID) :
|
||||||
_startID(startID), _pathID(pathID), _endID(endID)
|
_startID(startID), _pathID(pathID), _endID(endID)
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,22 +58,24 @@ public:
|
||||||
QUuid getRayUID() { return _rayPickUID; }
|
QUuid getRayUID() { return _rayPickUID; }
|
||||||
void enable();
|
void enable();
|
||||||
void disable();
|
void disable();
|
||||||
const RayPickResult getPrevRayPickResult() { return DependencyManager::get<RayPickScriptingInterface>()->getPrevRayPickResult(_rayPickUID); }
|
const RayPickResult getPrevRayPickResult();
|
||||||
|
|
||||||
void setRenderState(const std::string& state);
|
void setRenderState(const std::string& state);
|
||||||
// You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays.
|
// You cannot use editRenderState to change the overlay type of any part of the laser pointer. You can only edit the properties of the existing overlays.
|
||||||
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
void editRenderState(const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps);
|
||||||
|
|
||||||
void setPrecisionPicking(const bool precisionPicking) { DependencyManager::get<RayPickScriptingInterface>()->setPrecisionPicking(_rayPickUID, precisionPicking); }
|
void setPrecisionPicking(const bool precisionPicking);
|
||||||
void setLaserLength(const float laserLength) { _laserLength = laserLength; }
|
void setLaserLength(const float laserLength);
|
||||||
void setIgnoreEntities(const QScriptValue& ignoreEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreEntities(_rayPickUID, ignoreEntities); }
|
void setLockEndUUID(QUuid objectID, const bool isOverlay);
|
||||||
void setIncludeEntities(const QScriptValue& includeEntities) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeEntities(_rayPickUID, includeEntities); }
|
|
||||||
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreOverlays(_rayPickUID, ignoreOverlays); }
|
|
||||||
void setIncludeOverlays(const QScriptValue& includeOverlays) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeOverlays(_rayPickUID, includeOverlays); }
|
|
||||||
void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { DependencyManager::get<RayPickScriptingInterface>()->setIgnoreAvatars(_rayPickUID, ignoreAvatars); }
|
|
||||||
void setIncludeAvatars(const QScriptValue& includeAvatars) { DependencyManager::get<RayPickScriptingInterface>()->setIncludeAvatars(_rayPickUID, includeAvatars); }
|
|
||||||
|
|
||||||
void setLockEndUUID(QUuid objectID, const bool isOverlay) { _objectLockEnd = std::pair<QUuid, bool>(objectID, isOverlay); }
|
void setIgnoreEntities(const QScriptValue& ignoreEntities);
|
||||||
|
void setIncludeEntities(const QScriptValue& includeEntities);
|
||||||
|
void setIgnoreOverlays(const QScriptValue& ignoreOverlays);
|
||||||
|
void setIncludeOverlays(const QScriptValue& includeOverlays);
|
||||||
|
void setIgnoreAvatars(const QScriptValue& ignoreAvatars);
|
||||||
|
void setIncludeAvatars(const QScriptValue& includeAvatars);
|
||||||
|
|
||||||
|
QReadWriteLock* getLock() { return &_lock; }
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
|
@ -89,6 +91,7 @@ private:
|
||||||
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
|
std::pair<QUuid, bool> _objectLockEnd { std::pair<QUuid, bool>(QUuid(), false)};
|
||||||
|
|
||||||
QUuid _rayPickUID;
|
QUuid _rayPickUID;
|
||||||
|
QReadWriteLock _lock;
|
||||||
|
|
||||||
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
void updateRenderStateOverlay(const OverlayID& id, const QVariant& props);
|
||||||
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);
|
void updateRenderState(const RenderState& renderState, const IntersectionType type, const float distance, const QUuid& objectID, const PickRay& pickRay, const bool defaultState);
|
||||||
|
|
|
@ -17,7 +17,6 @@ QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const La
|
||||||
QWriteLocker containsLock(&_containsLock);
|
QWriteLocker containsLock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_laserPointers[id] = laserPointer;
|
_laserPointers[id] = laserPointer;
|
||||||
_laserPointerLocks[id] = std::make_shared<QReadWriteLock>();
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
return QUuid();
|
return QUuid();
|
||||||
|
@ -26,46 +25,45 @@ QUuid LaserPointerManager::createLaserPointer(const QVariant& rayProps, const La
|
||||||
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
void LaserPointerManager::removeLaserPointer(const QUuid uid) {
|
||||||
QWriteLocker lock(&_containsLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_laserPointers.remove(uid);
|
_laserPointers.remove(uid);
|
||||||
_laserPointerLocks.remove(uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
void LaserPointerManager::enableLaserPointer(const QUuid uid) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->enable();
|
laserPointer.value()->enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::disableLaserPointer(const QUuid uid) {
|
void LaserPointerManager::disableLaserPointer(const QUuid uid) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->disable();
|
laserPointer.value()->disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setRenderState(QUuid uid, const std::string& renderState) {
|
void LaserPointerManager::setRenderState(QUuid uid, const std::string& renderState) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setRenderState(renderState);
|
laserPointer.value()->setRenderState(renderState);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
|
void LaserPointerManager::editRenderState(QUuid uid, const std::string& state, const QVariant& startProps, const QVariant& pathProps, const QVariant& endProps) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->editRenderState(state, startProps, pathProps, endProps);
|
laserPointer.value()->editRenderState(state, startProps, pathProps, endProps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
|
const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
return _laserPointers[uid]->getPrevRayPickResult();
|
return laserPointer.value()->getPrevRayPickResult();
|
||||||
}
|
}
|
||||||
return RayPickResult();
|
return RayPickResult();
|
||||||
}
|
}
|
||||||
|
@ -73,80 +71,79 @@ const RayPickResult LaserPointerManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
void LaserPointerManager::update() {
|
void LaserPointerManager::update() {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
for (QUuid& uid : _laserPointers.keys()) {
|
for (QUuid& uid : _laserPointers.keys()) {
|
||||||
// This only needs to be a read lock because update won't change any of the properties that can be modified from scripts
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QReadLocker laserLock(_laserPointerLocks[uid].get());
|
laserPointer.value()->update();
|
||||||
_laserPointers[uid]->update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
void LaserPointerManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setPrecisionPicking(precisionPicking);
|
laserPointer.value()->setPrecisionPicking(precisionPicking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) {
|
void LaserPointerManager::setLaserLength(QUuid uid, const float laserLength) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setLaserLength(laserLength);
|
laserPointer.value()->setLaserLength(laserLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
void LaserPointerManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIgnoreEntities(ignoreEntities);
|
laserPointer.value()->setIgnoreEntities(ignoreEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
|
void LaserPointerManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIncludeEntities(includeEntities);
|
laserPointer.value()->setIncludeEntities(includeEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
|
void LaserPointerManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIgnoreOverlays(ignoreOverlays);
|
laserPointer.value()->setIgnoreOverlays(ignoreOverlays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
|
void LaserPointerManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIncludeOverlays(includeOverlays);
|
laserPointer.value()->setIncludeOverlays(includeOverlays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
|
void LaserPointerManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIgnoreAvatars(ignoreAvatars);
|
laserPointer.value()->setIgnoreAvatars(ignoreAvatars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
void LaserPointerManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setIncludeAvatars(includeAvatars);
|
laserPointer.value()->setIncludeAvatars(includeAvatars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) {
|
void LaserPointerManager::setLockEndUUID(QUuid uid, QUuid objectID, const bool isOverlay) {
|
||||||
QReadLocker lock(&_containsLock);
|
QReadLocker lock(&_containsLock);
|
||||||
if (_laserPointers.contains(uid)) {
|
auto laserPointer = _laserPointers.find(uid);
|
||||||
QWriteLocker laserLock(_laserPointerLocks[uid].get());
|
if (laserPointer != _laserPointers.end()) {
|
||||||
_laserPointers[uid]->setLockEndUUID(objectID, isOverlay);
|
laserPointer.value()->setLockEndUUID(objectID, isOverlay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <QReadWriteLock>
|
|
||||||
|
|
||||||
#include "LaserPointer.h"
|
#include "LaserPointer.h"
|
||||||
|
|
||||||
|
@ -46,7 +45,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
QHash<QUuid, std::shared_ptr<LaserPointer>> _laserPointers;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _laserPointerLocks;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,3 +16,47 @@ RayPick::RayPick(const RayPickFilter& filter, const float maxDistance, const boo
|
||||||
_enabled(enabled)
|
_enabled(enabled)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
void RayPick::enable() {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_enabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::disable() {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const RayPickResult& RayPick::getPrevRayPickResult() {
|
||||||
|
QReadLocker lock(getLock());
|
||||||
|
return _prevResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIgnoreEntities(const QScriptValue& ignoreEntities) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_ignoreEntities = qVectorEntityItemIDFromScriptValue(ignoreEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIncludeEntities(const QScriptValue& includeEntities) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_includeEntities = qVectorEntityItemIDFromScriptValue(includeEntities);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIgnoreOverlays(const QScriptValue& ignoreOverlays) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_ignoreOverlays = qVectorOverlayIDFromScriptValue(ignoreOverlays);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIncludeOverlays(const QScriptValue& includeOverlays) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_includeOverlays = qVectorOverlayIDFromScriptValue(includeOverlays);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIgnoreAvatars(const QScriptValue& ignoreAvatars) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_ignoreAvatars = qVectorEntityItemIDFromScriptValue(ignoreAvatars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RayPick::setIncludeAvatars(const QScriptValue& includeAvatars) {
|
||||||
|
QWriteLocker lock(getLock());
|
||||||
|
_includeAvatars = qVectorEntityItemIDFromScriptValue(includeAvatars);
|
||||||
|
}
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include "EntityItemID.h"
|
#include "EntityItemID.h"
|
||||||
#include "ui/overlays/Overlay.h"
|
#include "ui/overlays/Overlay.h"
|
||||||
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
class RayPickFilter {
|
class RayPickFilter {
|
||||||
public:
|
public:
|
||||||
|
@ -102,13 +103,13 @@ public:
|
||||||
|
|
||||||
virtual const PickRay getPickRay(bool& valid) const = 0;
|
virtual const PickRay getPickRay(bool& valid) const = 0;
|
||||||
|
|
||||||
void enable() { _enabled = true; }
|
void enable();
|
||||||
void disable() { _enabled = false; }
|
void disable();
|
||||||
|
|
||||||
const RayPickFilter& getFilter() { return _filter; }
|
const RayPickFilter& getFilter() { return _filter; }
|
||||||
float getMaxDistance() { return _maxDistance; }
|
float getMaxDistance() { return _maxDistance; }
|
||||||
bool isEnabled() { return _enabled; }
|
bool isEnabled() { return _enabled; }
|
||||||
const RayPickResult& getPrevRayPickResult() { return _prevResult; }
|
const RayPickResult& getPrevRayPickResult();
|
||||||
|
|
||||||
void setPrecisionPicking(bool precisionPicking) { _filter.setFlag(RayPickFilter::PICK_COURSE, !precisionPicking); }
|
void setPrecisionPicking(bool precisionPicking) { _filter.setFlag(RayPickFilter::PICK_COURSE, !precisionPicking); }
|
||||||
|
|
||||||
|
@ -120,12 +121,14 @@ public:
|
||||||
const QVector<OverlayID>& getIncludeOverlays() { return _includeOverlays; }
|
const QVector<OverlayID>& getIncludeOverlays() { return _includeOverlays; }
|
||||||
const QVector<EntityItemID>& getIgnoreAvatars() { return _ignoreAvatars; }
|
const QVector<EntityItemID>& getIgnoreAvatars() { return _ignoreAvatars; }
|
||||||
const QVector<EntityItemID>& getIncludeAvatars() { return _includeAvatars; }
|
const QVector<EntityItemID>& getIncludeAvatars() { return _includeAvatars; }
|
||||||
void setIgnoreEntities(const QScriptValue& ignoreEntities) { _ignoreEntities = qVectorEntityItemIDFromScriptValue(ignoreEntities); }
|
void setIgnoreEntities(const QScriptValue& ignoreEntities);
|
||||||
void setIncludeEntities(const QScriptValue& includeEntities) { _includeEntities = qVectorEntityItemIDFromScriptValue(includeEntities); }
|
void setIncludeEntities(const QScriptValue& includeEntities);
|
||||||
void setIgnoreOverlays(const QScriptValue& ignoreOverlays) { _ignoreOverlays = qVectorOverlayIDFromScriptValue(ignoreOverlays); }
|
void setIgnoreOverlays(const QScriptValue& ignoreOverlays);
|
||||||
void setIncludeOverlays(const QScriptValue& includeOverlays) { _includeOverlays = qVectorOverlayIDFromScriptValue(includeOverlays); }
|
void setIncludeOverlays(const QScriptValue& includeOverlays);
|
||||||
void setIgnoreAvatars(const QScriptValue& ignoreAvatars) { _ignoreAvatars = qVectorEntityItemIDFromScriptValue(ignoreAvatars); }
|
void setIgnoreAvatars(const QScriptValue& ignoreAvatars);
|
||||||
void setIncludeAvatars(const QScriptValue& includeAvatars) { _includeAvatars = qVectorEntityItemIDFromScriptValue(includeAvatars); }
|
void setIncludeAvatars(const QScriptValue& includeAvatars);
|
||||||
|
|
||||||
|
QReadWriteLock* getLock() { return &_lock; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
RayPickFilter _filter;
|
RayPickFilter _filter;
|
||||||
|
@ -139,6 +142,8 @@ private:
|
||||||
QVector<OverlayID> _includeOverlays;
|
QVector<OverlayID> _includeOverlays;
|
||||||
QVector<EntityItemID> _ignoreAvatars;
|
QVector<EntityItemID> _ignoreAvatars;
|
||||||
QVector<EntityItemID> _includeAvatars;
|
QVector<EntityItemID> _includeAvatars;
|
||||||
|
|
||||||
|
QReadWriteLock _lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_RayPick_h
|
#endif // hifi_RayPick_h
|
||||||
|
|
|
@ -47,6 +47,7 @@ void RayPickManager::update() {
|
||||||
RayPickCache results;
|
RayPickCache results;
|
||||||
for (auto& uid : _rayPicks.keys()) {
|
for (auto& uid : _rayPicks.keys()) {
|
||||||
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
std::shared_ptr<RayPick> rayPick = _rayPicks[uid];
|
||||||
|
QWriteLocker lock(rayPick->getLock());
|
||||||
if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) {
|
if (!rayPick->isEnabled() || rayPick->getFilter().doesPickNothing() || rayPick->getMaxDistance() < 0.0f) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -114,7 +115,6 @@ void RayPickManager::update() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
|
||||||
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
if (rayPick->getMaxDistance() == 0.0f || (rayPick->getMaxDistance() > 0.0f && res.distance < rayPick->getMaxDistance())) {
|
||||||
rayPick->setRayPickResult(res);
|
rayPick->setRayPickResult(res);
|
||||||
} else {
|
} else {
|
||||||
|
@ -127,7 +127,6 @@ QUuid RayPickManager::createRayPick(const std::string& jointName, const glm::vec
|
||||||
QWriteLocker lock(&_containsLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicks[id] = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
|
_rayPicks[id] = std::make_shared<JointRayPick>(jointName, posOffset, dirOffset, filter, maxDistance, enabled);
|
||||||
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +134,6 @@ QUuid RayPickManager::createRayPick(const RayPickFilter& filter, const float max
|
||||||
QWriteLocker lock(&_containsLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicks[id] = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
|
_rayPicks[id] = std::make_shared<MouseRayPick>(filter, maxDistance, enabled);
|
||||||
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,93 +141,91 @@ QUuid RayPickManager::createRayPick(const glm::vec3& position, const glm::vec3&
|
||||||
QWriteLocker lock(&_containsLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
QUuid id = QUuid::createUuid();
|
QUuid id = QUuid::createUuid();
|
||||||
_rayPicks[id] = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
|
_rayPicks[id] = std::make_shared<StaticRayPick>(position, direction, filter, maxDistance, enabled);
|
||||||
_rayPickLocks[id] = std::make_shared<QReadWriteLock>();
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::removeRayPick(const QUuid uid) {
|
void RayPickManager::removeRayPick(const QUuid uid) {
|
||||||
QWriteLocker lock(&_containsLock);
|
QWriteLocker lock(&_containsLock);
|
||||||
_rayPicks.remove(uid);
|
_rayPicks.remove(uid);
|
||||||
_rayPickLocks.remove(uid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::enableRayPick(const QUuid uid) {
|
void RayPickManager::enableRayPick(const QUuid uid) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker rayPickLock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->enable();
|
rayPick.value()->enable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::disableRayPick(const QUuid uid) {
|
void RayPickManager::disableRayPick(const QUuid uid) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker rayPickLock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->disable();
|
rayPick.value()->disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
const RayPickResult RayPickManager::getPrevRayPickResult(const QUuid uid) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QReadLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
return _rayPicks[uid]->getPrevRayPickResult();
|
return rayPick.value()->getPrevRayPickResult();
|
||||||
}
|
}
|
||||||
return RayPickResult();
|
return RayPickResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
void RayPickManager::setPrecisionPicking(QUuid uid, const bool precisionPicking) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setPrecisionPicking(precisionPicking);
|
rayPick.value()->setPrecisionPicking(precisionPicking);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
void RayPickManager::setIgnoreEntities(QUuid uid, const QScriptValue& ignoreEntities) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIgnoreEntities(ignoreEntities);
|
rayPick.value()->setIgnoreEntities(ignoreEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
|
void RayPickManager::setIncludeEntities(QUuid uid, const QScriptValue& includeEntities) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIncludeEntities(includeEntities);
|
rayPick.value()->setIncludeEntities(includeEntities);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
|
void RayPickManager::setIgnoreOverlays(QUuid uid, const QScriptValue& ignoreOverlays) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIgnoreOverlays(ignoreOverlays);
|
rayPick.value()->setIgnoreOverlays(ignoreOverlays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
|
void RayPickManager::setIncludeOverlays(QUuid uid, const QScriptValue& includeOverlays) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIncludeOverlays(includeOverlays);
|
rayPick.value()->setIncludeOverlays(includeOverlays);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
|
void RayPickManager::setIgnoreAvatars(QUuid uid, const QScriptValue& ignoreAvatars) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIgnoreAvatars(ignoreAvatars);
|
rayPick.value()->setIgnoreAvatars(ignoreAvatars);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
void RayPickManager::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
||||||
QReadLocker containsLock(&_containsLock);
|
QReadLocker containsLock(&_containsLock);
|
||||||
if (_rayPicks.contains(uid)) {
|
auto rayPick = _rayPicks.find(uid);
|
||||||
QWriteLocker lock(_rayPickLocks[uid].get());
|
if (rayPick != _rayPicks.end()) {
|
||||||
_rayPicks[uid]->setIncludeAvatars(includeAvatars);
|
rayPick.value()->setIncludeAvatars(includeAvatars);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <QtCore/QObject>
|
#include <QtCore/QObject>
|
||||||
#include <QReadWriteLock>
|
|
||||||
|
|
||||||
#include "RegisteredMetaTypes.h"
|
#include "RegisteredMetaTypes.h"
|
||||||
|
|
||||||
|
@ -47,7 +46,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
QHash<QUuid, std::shared_ptr<RayPick>> _rayPicks;
|
||||||
QHash<QUuid, std::shared_ptr<QReadWriteLock>> _rayPickLocks;
|
|
||||||
QReadWriteLock _containsLock;
|
QReadWriteLock _containsLock;
|
||||||
|
|
||||||
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
typedef QHash<QPair<glm::vec3, glm::vec3>, std::unordered_map<RayPickFilter::Flags, RayPickResult>> RayPickCache;
|
||||||
|
|
|
@ -265,7 +265,6 @@ void Base3DOverlay::parentDeleted() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Base3DOverlay::update(float duration) {
|
void Base3DOverlay::update(float duration) {
|
||||||
|
|
||||||
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
|
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
|
||||||
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
||||||
if (_renderTransformDirty) {
|
if (_renderTransformDirty) {
|
||||||
|
|
|
@ -18,6 +18,8 @@ class Baker : public QObject {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
virtual ~Baker() = default;
|
||||||
|
|
||||||
bool shouldStop();
|
bool shouldStop();
|
||||||
|
|
||||||
bool hasErrors() const { return !_errorList.isEmpty(); }
|
bool hasErrors() const { return !_errorList.isEmpty(); }
|
||||||
|
|
|
@ -56,6 +56,17 @@ FBXBaker::FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGet
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FBXBaker::~FBXBaker() {
|
||||||
|
if (_tempDir.exists()) {
|
||||||
|
if (!_tempDir.remove(_originalFBXFilePath)) {
|
||||||
|
qCWarning(model_baking) << "Failed to remove temporary copy of fbx file:" << _originalFBXFilePath;
|
||||||
|
}
|
||||||
|
if (!_tempDir.rmdir(".")) {
|
||||||
|
qCWarning(model_baking) << "Failed to remove temporary directory:" << _tempDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void FBXBaker::abort() {
|
void FBXBaker::abort() {
|
||||||
Baker::abort();
|
Baker::abort();
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,7 @@ class FBXBaker : public Baker {
|
||||||
public:
|
public:
|
||||||
FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
FBXBaker(const QUrl& fbxURL, TextureBakerThreadGetter textureThreadGetter,
|
||||||
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
const QString& bakedOutputDir, const QString& originalOutputDir = "");
|
||||||
|
~FBXBaker() override;
|
||||||
|
|
||||||
QUrl getFBXUrl() const { return _fbxURL; }
|
QUrl getFBXUrl() const { return _fbxURL; }
|
||||||
QString getBakedFBXFilePath() const { return _bakedFBXFilePath; }
|
QString getBakedFBXFilePath() const { return _bakedFBXFilePath; }
|
||||||
|
|
|
@ -260,15 +260,27 @@ void EntityTreeRenderer::update(bool simulate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
PerformanceTimer sceneTimer("scene");
|
||||||
auto scene = _viewState->getMain3DScene();
|
auto scene = _viewState->getMain3DScene();
|
||||||
if (scene) {
|
if (scene) {
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
|
{
|
||||||
|
PerformanceTimer pt("add");
|
||||||
addPendingEntities(scene, transaction);
|
addPendingEntities(scene, transaction);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
PerformanceTimer pt("change");
|
||||||
updateChangedEntities(scene, transaction);
|
updateChangedEntities(scene, transaction);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
PerformanceTimer pt("enqueue");
|
||||||
scene->enqueueTransaction(transaction);
|
scene->enqueueTransaction(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
bool EntityTreeRenderer::findBestZoneAndMaybeContainingEntities(QVector<EntityItemID>* entitiesContainingAvatar) {
|
||||||
bool didUpdate = false;
|
bool didUpdate = false;
|
||||||
|
|
|
@ -31,9 +31,6 @@ public:
|
||||||
/// copies the current view frustum for rendering the view state
|
/// copies the current view frustum for rendering the view state
|
||||||
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const = 0;
|
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const = 0;
|
||||||
|
|
||||||
/// copies the shadow view frustum for rendering the view state
|
|
||||||
virtual void copyShadowViewFrustum(ViewFrustum& viewOut) const = 0;
|
|
||||||
|
|
||||||
virtual QThread* getMainThread() = 0;
|
virtual QThread* getMainThread() = 0;
|
||||||
|
|
||||||
virtual PickRay computePickRay(float x, float y) const = 0;
|
virtual PickRay computePickRay(float x, float y) const = 0;
|
||||||
|
|
|
@ -144,6 +144,7 @@ void AnimDebugDraw::shutdown() {
|
||||||
if (scene && _itemID) {
|
if (scene && _itemID) {
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
transaction.removeItem(_itemID);
|
transaction.removeItem(_itemID);
|
||||||
|
render::Item::clearID(_itemID);
|
||||||
scene->enqueueTransaction(transaction);
|
scene->enqueueTransaction(transaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -316,7 +317,9 @@ void AnimDebugDraw::update() {
|
||||||
if (!scene) {
|
if (!scene) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!render::Item::isValidID(_itemID)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
render::Transaction transaction;
|
render::Transaction transaction;
|
||||||
transaction.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {
|
transaction.updateItem<AnimDebugDrawData>(_itemID, [&](AnimDebugDrawData& data) {
|
||||||
|
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "TransitionStage.h"
|
#include "TransitionStage.h"
|
||||||
|
|
||||||
// Comment this to disable transitions (fades)
|
|
||||||
#define SCENE_ENABLE_TRANSITIONS
|
|
||||||
|
|
||||||
using namespace render;
|
using namespace render;
|
||||||
|
|
||||||
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
|
void Transaction::resetItem(ItemID id, const PayloadPointer& payload) {
|
||||||
|
@ -102,15 +99,45 @@ void consolidateTransaction(TransactionQueue& queue, Transaction& singleBatch) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scene::processTransactionQueue() {
|
uint32_t Scene::enqueueFrame() {
|
||||||
PROFILE_RANGE(render, __FUNCTION__);
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
Transaction consolidatedTransaction;
|
Transaction consolidatedTransaction;
|
||||||
|
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
std::unique_lock<std::mutex> lock(_transactionQueueMutex);
|
||||||
consolidateTransaction(_transactionQueue, consolidatedTransaction);
|
consolidateTransaction(_transactionQueue, consolidatedTransaction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t frameNumber = 0;
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||||
|
_transactionFrames.push_back(consolidatedTransaction);
|
||||||
|
_transactionFrameNumber++;
|
||||||
|
frameNumber = _transactionFrameNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
return frameNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Scene::processTransactionQueue() {
|
||||||
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
|
|
||||||
|
TransactionFrames queuedFrames;
|
||||||
|
{
|
||||||
|
// capture the queued frames and clear the queue
|
||||||
|
std::unique_lock<std::mutex> lock(_transactionFramesMutex);
|
||||||
|
queuedFrames = _transactionFrames;
|
||||||
|
_transactionFrames.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// go through the queue of frames and process them
|
||||||
|
for (auto& frame : queuedFrames) {
|
||||||
|
processTransactionFrame(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scene::processTransactionFrame(const Transaction& transaction) {
|
||||||
|
PROFILE_RANGE(render, __FUNCTION__);
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> lock(_itemsMutex);
|
std::unique_lock<std::mutex> lock(_itemsMutex);
|
||||||
// Here we should be able to check the value of last ItemID allocated
|
// Here we should be able to check the value of last ItemID allocated
|
||||||
|
@ -123,32 +150,31 @@ void Scene::processTransactionQueue() {
|
||||||
// capture anything coming from the transaction
|
// capture anything coming from the transaction
|
||||||
|
|
||||||
// resets and potential NEW items
|
// resets and potential NEW items
|
||||||
resetItems(consolidatedTransaction._resetItems);
|
resetItems(transaction._resetItems);
|
||||||
|
|
||||||
// Update the numItemsAtomic counter AFTER the reset changes went through
|
// Update the numItemsAtomic counter AFTER the reset changes went through
|
||||||
_numAllocatedItems.exchange(maxID);
|
_numAllocatedItems.exchange(maxID);
|
||||||
|
|
||||||
// updates
|
// updates
|
||||||
updateItems(consolidatedTransaction._updatedItems);
|
updateItems(transaction._updatedItems);
|
||||||
|
|
||||||
// removes
|
// removes
|
||||||
removeItems(consolidatedTransaction._removedItems);
|
removeItems(transaction._removedItems);
|
||||||
|
|
||||||
#ifdef SCENE_ENABLE_TRANSITIONS
|
|
||||||
// add transitions
|
// add transitions
|
||||||
transitionItems(consolidatedTransaction._addedTransitions);
|
transitionItems(transaction._addedTransitions);
|
||||||
reApplyTransitions(consolidatedTransaction._reAppliedTransitions);
|
reApplyTransitions(transaction._reAppliedTransitions);
|
||||||
queryTransitionItems(consolidatedTransaction._queriedTransitions);
|
queryTransitionItems(transaction._queriedTransitions);
|
||||||
#endif
|
|
||||||
// Update the numItemsAtomic counter AFTER the pending changes went through
|
// Update the numItemsAtomic counter AFTER the pending changes went through
|
||||||
_numAllocatedItems.exchange(maxID);
|
_numAllocatedItems.exchange(maxID);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (consolidatedTransaction.touchTransactions()) {
|
if (transaction.touchTransactions()) {
|
||||||
std::unique_lock<std::mutex> lock(_selectionsMutex);
|
std::unique_lock<std::mutex> lock(_selectionsMutex);
|
||||||
|
|
||||||
// resets and potential NEW items
|
// resets and potential NEW items
|
||||||
resetSelections(consolidatedTransaction._resetSelections);
|
resetSelections(transaction._resetSelections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,6 +117,9 @@ public:
|
||||||
// Enqueue transaction to the scene
|
// Enqueue transaction to the scene
|
||||||
void enqueueTransaction(const Transaction& transaction);
|
void enqueueTransaction(const Transaction& transaction);
|
||||||
|
|
||||||
|
// Enqueue end of frame transactions boundary
|
||||||
|
uint32_t enqueueFrame();
|
||||||
|
|
||||||
// Process the pending transactions queued
|
// Process the pending transactions queued
|
||||||
void processTransactionQueue();
|
void processTransactionQueue();
|
||||||
|
|
||||||
|
@ -162,6 +165,15 @@ protected:
|
||||||
std::mutex _transactionQueueMutex;
|
std::mutex _transactionQueueMutex;
|
||||||
TransactionQueue _transactionQueue;
|
TransactionQueue _transactionQueue;
|
||||||
|
|
||||||
|
|
||||||
|
std::mutex _transactionFramesMutex;
|
||||||
|
using TransactionFrames = std::list<Transaction>;
|
||||||
|
TransactionFrames _transactionFrames;
|
||||||
|
uint32_t _transactionFrameNumber{ 0 };
|
||||||
|
|
||||||
|
// Process one transaction frame
|
||||||
|
void processTransactionFrame(const Transaction& transaction);
|
||||||
|
|
||||||
// The actual database
|
// The actual database
|
||||||
// database of items is protected for editing by a mutex
|
// database of items is protected for editing by a mutex
|
||||||
std::mutex _itemsMutex;
|
std::mutex _itemsMutex;
|
||||||
|
|
|
@ -443,10 +443,6 @@ protected:
|
||||||
viewOut = _viewFrustum;
|
viewOut = _viewFrustum;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyShadowViewFrustum(ViewFrustum& viewOut) const override {
|
|
||||||
viewOut = _shadowViewFrustum;
|
|
||||||
}
|
|
||||||
|
|
||||||
QThread* getMainThread() override {
|
QThread* getMainThread() override {
|
||||||
return QThread::currentThread();
|
return QThread::currentThread();
|
||||||
}
|
}
|
||||||
|
@ -1118,7 +1114,6 @@ private:
|
||||||
RenderThread _renderThread;
|
RenderThread _renderThread;
|
||||||
QWindowCamera _camera;
|
QWindowCamera _camera;
|
||||||
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
ViewFrustum _viewFrustum; // current state of view frustum, perspective, orientation, etc.
|
||||||
ViewFrustum _shadowViewFrustum; // current state of view frustum, perspective, orientation, etc.
|
|
||||||
model::SunSkyStage _sunSkyStage;
|
model::SunSkyStage _sunSkyStage;
|
||||||
model::LightPointer _globalLight { std::make_shared<model::Light>() };
|
model::LightPointer _globalLight { std::make_shared<model::Light>() };
|
||||||
bool _ready { false };
|
bool _ready { false };
|
||||||
|
|
Loading…
Reference in a new issue