Merge branch 'master' into vr-edit-a

This commit is contained in:
David Rowe 2017-10-06 11:54:08 +13:00
commit 28c7ef2e97
46 changed files with 1154 additions and 1892 deletions

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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);

View file

@ -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.

View file

@ -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

View file

@ -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")

View file

@ -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) {

View file

@ -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
} }
} }
} }
}

View file

@ -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) {

View file

@ -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();
} }

View file

@ -77,7 +77,7 @@ Item {
text: qsTr("Close"); text: qsTr("Close");
onClicked: root.destroy() onClicked: root.tryDestroy()
} }
} }

View file

@ -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")
}
}
}

View file

@ -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
}
}
}

View file

@ -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")
}
}
}

View file

@ -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
}
}
}

View file

@ -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
}
}
}

View file

@ -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()
}
}

View file

@ -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

View file

@ -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
}
}
} }

View file

@ -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() {

View file

@ -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");

View file

@ -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() {

View file

@ -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"

View file

@ -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;

View 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();
}
}

View file

@ -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)
{ {

View file

@ -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);

View file

@ -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);
} }
} }

View file

@ -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;
}; };

View file

@ -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);
}

View file

@ -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

View file

@ -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);
} }
} }

View file

@ -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;

View file

@ -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) {

View file

@ -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(); }

View file

@ -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();

View file

@ -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; }

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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);
} }
} }

View file

@ -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;

View file

@ -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 };