diff --git a/CMakeLists.txt b/CMakeLists.txt index a887a35fcc..d52a557cb1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,6 +7,11 @@ else() cmake_minimum_required(VERSION 3.2) endif() +# squelch the Policy CMP0074 warning without requiring an update to cmake 3.12. +if ((${CMAKE_MAJOR_VERSION} EQUAL 3 AND ${CMAKE_MINOR_VERSION} GREATER 11) OR ${CMAKE_MAJOR_VERSION} GREATER 3) + cmake_policy(SET CMP0074 NEW) +endif() + project(hifi) include("cmake/init.cmake") diff --git a/android/gradle.properties b/android/gradle.properties new file mode 100644 index 0000000000..ac639c5ae7 --- /dev/null +++ b/android/gradle.properties @@ -0,0 +1 @@ +org.gradle.jvmargs=-Xms2g -Xmx4g diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index 5f1e1ca74a..1561af4d25 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -369,11 +369,7 @@ void Agent::executeScript() { // setup an Avatar for the script to use auto scriptedAvatar = DependencyManager::get(); - scriptedAvatar->setID(getSessionUUID()); - - connect(_scriptEngine.data(), SIGNAL(update(float)), - scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection); scriptedAvatar->setForceFaceTrackerConnected(true); // call model URL setters with empty URLs so our avatar, if user, will have the default models @@ -505,8 +501,6 @@ void Agent::executeScript() { DependencyManager::set(_entityViewer.getTree()); - _avatarAudioTimer.start(); - // Agents should run at 45hz static const int AVATAR_DATA_HZ = 45; static const int AVATAR_DATA_IN_MSECS = MSECS_PER_SECOND / AVATAR_DATA_HZ; @@ -531,7 +525,8 @@ void Agent::executeScript() { } avatarDataTimer->stop(); - _avatarAudioTimer.stop(); + + setIsAvatar(false); // will stop timers for sending identity packets } setFinished(true); @@ -583,28 +578,33 @@ void Agent::setIsAvatar(bool isAvatar) { } _isAvatar = isAvatar; - if (_isAvatar && !_avatarIdentityTimer) { - // set up the avatar timers - _avatarIdentityTimer = new QTimer(this); - _avatarQueryTimer = new QTimer(this); + auto scriptableAvatar = DependencyManager::get(); + if (_isAvatar) { + if (!_avatarIdentityTimer) { + // set up the avatar timers + _avatarIdentityTimer = new QTimer(this); + _avatarQueryTimer = new QTimer(this); - // connect our slot - connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket); - connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars); + // connect our slot + connect(_avatarIdentityTimer, &QTimer::timeout, this, &Agent::sendAvatarIdentityPacket); + connect(_avatarQueryTimer, &QTimer::timeout, this, &Agent::queryAvatars); - static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; - static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000; + static const int AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS = 1000; + static const int AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS = 1000; - // start the timers - _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets - _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); + // start the timers + _avatarIdentityTimer->start(AVATAR_IDENTITY_PACKET_SEND_INTERVAL_MSECS); // FIXME - we shouldn't really need to constantly send identity packets + _avatarQueryTimer->start(AVATAR_VIEW_PACKET_SEND_INTERVAL_MSECS); - // tell the avatarAudioTimer to start ticking - QMetaObject::invokeMethod(&_avatarAudioTimer, "start"); - } + connect(_scriptEngine.data(), &ScriptEngine::update, + scriptableAvatar.data(), &ScriptableAvatar::update, Qt::QueuedConnection); - if (!_isAvatar) { + // tell the avatarAudioTimer to start ticking + QMetaObject::invokeMethod(&_avatarAudioTimer, "start"); + } + _entityEditSender.setMyAvatar(scriptableAvatar.data()); + } else { if (_avatarIdentityTimer) { _avatarIdentityTimer->stop(); delete _avatarIdentityTimer; @@ -631,14 +631,14 @@ void Agent::setIsAvatar(bool isAvatar) { packet->writePrimitive(KillAvatarReason::NoReason); nodeList->sendPacket(std::move(packet), *node); }); + + disconnect(_scriptEngine.data(), &ScriptEngine::update, + scriptableAvatar.data(), &ScriptableAvatar::update); + + QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); } - QMetaObject::invokeMethod(&_avatarAudioTimer, "stop"); - _entityEditSender.setMyAvatar(nullptr); - } else { - auto scriptableAvatar = DependencyManager::get(); - _entityEditSender.setMyAvatar(scriptableAvatar.data()); } } @@ -789,7 +789,7 @@ void Agent::processAgentAvatarAudio() { // seek past the sequence number, will be packed when destination node is known audioPacket->seek(sizeof(quint16)); - if (silentFrame) { + if (silentFrame && !_flushEncoder) { if (!_isListeningToAudioStream) { // if we have a silent frame and we're not listening then just send nothing and break out of here @@ -811,7 +811,7 @@ void Agent::processAgentAvatarAudio() { // no matter what, the loudness should be set to 0 computeLoudness(nullptr, scriptedAvatar); - } else if (nextSoundOutput) { + } else if (nextSoundOutput || _flushEncoder) { // write the codec audioPacket->writeString(_selectedCodecName); @@ -865,8 +865,6 @@ void Agent::processAgentAvatarAudio() { } void Agent::aboutToFinish() { - setIsAvatar(false);// will stop timers for sending identity packets - // our entity tree is going to go away so tell that to the EntityScriptingInterface DependencyManager::get()->setEntityTree(nullptr); diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 4545f48c41..7e1420ef60 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -497,7 +497,7 @@ void AudioMixerClientData::processStreamPacket(ReceivedMessage& message, Concurr if (newStream) { // whenever a stream is added, push it to the concurrent vector of streams added this frame - addedStreams.emplace_back(getNodeID(), getNodeLocalID(), matchingStream->getStreamIdentifier(), matchingStream.get()); + addedStreams.push_back(AddedStream(getNodeID(), getNodeLocalID(), matchingStream->getStreamIdentifier(), matchingStream.get())); } } diff --git a/assignment-client/src/avatars/AvatarMixerSlave.cpp b/assignment-client/src/avatars/AvatarMixerSlave.cpp index b6ec006c39..f3f47dff74 100644 --- a/assignment-client/src/avatars/AvatarMixerSlave.cpp +++ b/assignment-client/src/avatars/AvatarMixerSlave.cpp @@ -380,6 +380,11 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node) if (lastSeqToReceiver == lastSeqFromSender && lastSeqToReceiver != 0) { ++numAvatarsHeldBack; shouldIgnore = true; + } else if (lastSeqFromSender == 0) { + // We have have not yet recieved any data about this avatar. Ignore it for now + // This is important for Agent scripts that are not avatar + // so that they don't appear to be an avatar at the origin + shouldIgnore = true; } else if (lastSeqFromSender - lastSeqToReceiver > 1) { // this is a skip - we still send the packet but capture the presence of the skip so we see it happening ++numAvatarsWithSkippedFrames; diff --git a/assignment-client/src/avatars/ScriptableAvatar.h b/assignment-client/src/avatars/ScriptableAvatar.h index 52beba72a1..578bd84a8f 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.h +++ b/assignment-client/src/avatars/ScriptableAvatar.h @@ -164,7 +164,7 @@ public: void setHasAudioEnabledFaceMovement(bool hasAudioEnabledFaceMovement); bool getHasAudioEnabledFaceMovement() const override { return _headData->getHasAudioEnabledFaceMovement(); } -private slots: +public slots: void update(float deltatime); private: diff --git a/domain-server/resources/web/content/js/content.js b/domain-server/resources/web/content/js/content.js index 853e87ae23..346e846748 100644 --- a/domain-server/resources/web/content/js/content.js +++ b/domain-server/resources/web/content/js/content.js @@ -59,6 +59,7 @@ $(document).ready(function(){ $.ajax({ url: '/content/upload', type: 'POST', + timeout: 3600000, // Set timeout to 1h cache: false, processData: false, contentType: false, diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 8136bf3b53..b540592d7e 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -2906,7 +2906,7 @@ void DomainServer::updateReplicationNodes(ReplicationServerDirection direction) // collect them in a vector to separately remove them with handleKillNode (since eachNode has a read lock and // we cannot recursively take the write lock required by handleKillNode) std::vector nodesToKill; - nodeList->eachNode([direction, replicationNodesInSettings, replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) { + nodeList->eachNode([&direction, &replicationNodesInSettings, &replicationDirection, &nodesToKill](const SharedNodePointer& otherNode) { if ((direction == Upstream && NodeType::isUpstream(otherNode->getType())) || (direction == Downstream && NodeType::isDownstream(otherNode->getType()))) { bool nodeInSettings = find(replicationNodesInSettings.cbegin(), replicationNodesInSettings.cend(), diff --git a/interface/resources/QtWebEngine/UIDelegates/Menu.qml b/interface/resources/QtWebEngine/UIDelegates/Menu.qml index 46c00e758e..adfd29df9e 100644 --- a/interface/resources/QtWebEngine/UIDelegates/Menu.qml +++ b/interface/resources/QtWebEngine/UIDelegates/Menu.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import "../../qml/controls-uit" -import "../../qml/styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: menu diff --git a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml index 6014b6834b..b4d3ca4bb2 100644 --- a/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml +++ b/interface/resources/QtWebEngine/UIDelegates/MenuItem.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import "../../qml/controls-uit" -import "../../qml/styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: root diff --git a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml index e4ab3037ef..089c745571 100644 --- a/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml +++ b/interface/resources/QtWebEngine/UIDelegates/PromptDialog.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 -import "../../qml/controls-uit" -import "../../qml/styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../../qml/dialogs" QtObject { diff --git a/interface/resources/html/img/tablet-help-keyboard.jpg b/interface/resources/html/img/tablet-help-keyboard.jpg index 7045abed75..f19c399f3a 100644 Binary files a/interface/resources/html/img/tablet-help-keyboard.jpg and b/interface/resources/html/img/tablet-help-keyboard.jpg differ diff --git a/interface/resources/meshes/controller/touch/touch_l_bumper.fbx b/interface/resources/meshes/controller/touch/touch_l_bumper.fbx index 7d051735c3..d6cdf59bf3 100644 Binary files a/interface/resources/meshes/controller/touch/touch_l_bumper.fbx and b/interface/resources/meshes/controller/touch/touch_l_bumper.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_l_button_x.fbx b/interface/resources/meshes/controller/touch/touch_l_button_x.fbx index 8297e623bb..9a3f6928f7 100644 Binary files a/interface/resources/meshes/controller/touch/touch_l_button_x.fbx and b/interface/resources/meshes/controller/touch/touch_l_button_x.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_l_button_y.fbx b/interface/resources/meshes/controller/touch/touch_l_button_y.fbx index c87ad5c8fc..020b26c4ca 100644 Binary files a/interface/resources/meshes/controller/touch/touch_l_button_y.fbx and b/interface/resources/meshes/controller/touch/touch_l_button_y.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_l_joystick.fbx b/interface/resources/meshes/controller/touch/touch_l_joystick.fbx index eaf8b3e382..49c55b60df 100644 Binary files a/interface/resources/meshes/controller/touch/touch_l_joystick.fbx and b/interface/resources/meshes/controller/touch/touch_l_joystick.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_l_trigger.fbx b/interface/resources/meshes/controller/touch/touch_l_trigger.fbx index 2cbf15272d..bc8ca86fb2 100644 Binary files a/interface/resources/meshes/controller/touch/touch_l_trigger.fbx and b/interface/resources/meshes/controller/touch/touch_l_trigger.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_r_bumper.fbx b/interface/resources/meshes/controller/touch/touch_r_bumper.fbx index ddff4ba40f..47d692e004 100644 Binary files a/interface/resources/meshes/controller/touch/touch_r_bumper.fbx and b/interface/resources/meshes/controller/touch/touch_r_bumper.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_r_button_a.fbx b/interface/resources/meshes/controller/touch/touch_r_button_a.fbx index 8386ed565c..73adb34e4b 100644 Binary files a/interface/resources/meshes/controller/touch/touch_r_button_a.fbx and b/interface/resources/meshes/controller/touch/touch_r_button_a.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_r_button_b.fbx b/interface/resources/meshes/controller/touch/touch_r_button_b.fbx index 504374c26b..2c7a813832 100644 Binary files a/interface/resources/meshes/controller/touch/touch_r_button_b.fbx and b/interface/resources/meshes/controller/touch/touch_r_button_b.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_r_joystick.fbx b/interface/resources/meshes/controller/touch/touch_r_joystick.fbx index 8602f28d70..0fd3bbec96 100644 Binary files a/interface/resources/meshes/controller/touch/touch_r_joystick.fbx and b/interface/resources/meshes/controller/touch/touch_r_joystick.fbx differ diff --git a/interface/resources/meshes/controller/touch/touch_r_trigger.fbx b/interface/resources/meshes/controller/touch/touch_r_trigger.fbx index e43f066bce..694de0530c 100644 Binary files a/interface/resources/meshes/controller/touch/touch_r_trigger.fbx and b/interface/resources/meshes/controller/touch/touch_r_trigger.fbx differ diff --git a/interface/resources/qml/AudioScopeUI.qml b/interface/resources/qml/AudioScopeUI.qml index aa181dbf8d..91908807e2 100644 --- a/interface/resources/qml/AudioScopeUI.qml +++ b/interface/resources/qml/AudioScopeUI.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import "styles-uit" -import "controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit Item { id: root diff --git a/interface/resources/qml/Browser.qml b/interface/resources/qml/Browser.qml index 4474cfb2cd..01de7a36f9 100644 --- a/interface/resources/qml/Browser.qml +++ b/interface/resources/qml/Browser.qml @@ -2,9 +2,9 @@ import QtQuick 2.5 import QtWebChannel 1.0 import QtWebEngine 1.5 -import "controls-uit" +import controlsUit 1.0 import "styles" as HifiStyles -import "styles-uit" +import stylesUit 1.0 import "windows" ScrollingWindow { diff --git a/interface/resources/qml/CurrentAPI.qml b/interface/resources/qml/CurrentAPI.qml index 96bfb5c36b..4ea45041c3 100644 --- a/interface/resources/qml/CurrentAPI.qml +++ b/interface/resources/qml/CurrentAPI.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import "styles-uit" -import "controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { id: root diff --git a/interface/resources/qml/InfoView.qml b/interface/resources/qml/InfoView.qml index f18969fb2f..8c5900b4c3 100644 --- a/interface/resources/qml/InfoView.qml +++ b/interface/resources/qml/InfoView.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import Hifi 1.0 as Hifi -import "controls-uit" +import controlsUit 1.0 import "windows" as Windows Windows.ScrollingWindow { diff --git a/interface/resources/qml/InteractiveWindow.qml b/interface/resources/qml/InteractiveWindow.qml index e8ddbf823d..c217238e93 100644 --- a/interface/resources/qml/InteractiveWindow.qml +++ b/interface/resources/qml/InteractiveWindow.qml @@ -12,9 +12,9 @@ import QtQuick 2.3 import "windows" as Windows import "controls" -import "controls-uit" as Controls +import controlsUit 1.0 as Controls import "styles" -import "styles-uit" +import stylesUit 1.0 Windows.Window { id: root; diff --git a/interface/resources/qml/LoginDialog.qml b/interface/resources/qml/LoginDialog.qml index 336858502d..12117aaba4 100644 --- a/interface/resources/qml/LoginDialog.qml +++ b/interface/resources/qml/LoginDialog.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.4 -import "controls-uit" -import "styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "windows" import "LoginDialog" diff --git a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml index 96b638c911..a40110b1e9 100644 --- a/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/+android/LinkAccountBody.qml @@ -13,8 +13,8 @@ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: linkAccountBody diff --git a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml index 3a44a8d741..10909e4c85 100644 --- a/interface/resources/qml/LoginDialog/+android/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/+android/SignUpBody.qml @@ -13,8 +13,8 @@ import QtQuick 2.4 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: signupBody diff --git a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml index fe4c511f1d..3a57061de4 100644 --- a/interface/resources/qml/LoginDialog/CompleteProfileBody.qml +++ b/interface/resources/qml/LoginDialog/CompleteProfileBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: completeProfileBody diff --git a/interface/resources/qml/LoginDialog/LinkAccountBody.qml b/interface/resources/qml/LoginDialog/LinkAccountBody.qml index 48cf124127..7951d45c0e 100644 --- a/interface/resources/qml/LoginDialog/LinkAccountBody.qml +++ b/interface/resources/qml/LoginDialog/LinkAccountBody.qml @@ -13,8 +13,9 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 + Item { id: linkAccountBody clip: true diff --git a/interface/resources/qml/LoginDialog/SignInBody.qml b/interface/resources/qml/LoginDialog/SignInBody.qml index 9cb1add704..7fe29e13f6 100644 --- a/interface/resources/qml/LoginDialog/SignInBody.qml +++ b/interface/resources/qml/LoginDialog/SignInBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls.Styles 1.4 as OriginalStyles -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: signInBody diff --git a/interface/resources/qml/LoginDialog/SignUpBody.qml b/interface/resources/qml/LoginDialog/SignUpBody.qml index bb30696e4c..d3c898d76f 100644 --- a/interface/resources/qml/LoginDialog/SignUpBody.qml +++ b/interface/resources/qml/LoginDialog/SignUpBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.7 import QtQuick.Controls 1.4 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: signupBody diff --git a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml index bf05a36ce1..2a41353534 100644 --- a/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml +++ b/interface/resources/qml/LoginDialog/UsernameCollisionBody.qml @@ -12,8 +12,8 @@ import Hifi 1.0 import QtQuick 2.4 import QtQuick.Controls 1.4 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: usernameCollisionBody diff --git a/interface/resources/qml/LoginDialog/WelcomeBody.qml b/interface/resources/qml/LoginDialog/WelcomeBody.qml index 551ec263b7..020e6db002 100644 --- a/interface/resources/qml/LoginDialog/WelcomeBody.qml +++ b/interface/resources/qml/LoginDialog/WelcomeBody.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.4 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: welcomeBody diff --git a/interface/resources/qml/QmlWebWindow.qml b/interface/resources/qml/QmlWebWindow.qml index 8c4d6145ec..322535641d 100644 --- a/interface/resources/qml/QmlWebWindow.qml +++ b/interface/resources/qml/QmlWebWindow.qml @@ -13,8 +13,8 @@ import QtWebEngine 1.1 import QtWebChannel 1.0 import "windows" as Windows -import "controls-uit" as Controls -import "styles-uit" +import controlsUit 1.0 as Controls +import stylesUit 1.0 Windows.ScrollingWindow { id: root diff --git a/interface/resources/qml/QmlWindow.qml b/interface/resources/qml/QmlWindow.qml index bef6423e25..53e6bcc37d 100644 --- a/interface/resources/qml/QmlWindow.qml +++ b/interface/resources/qml/QmlWindow.qml @@ -2,9 +2,9 @@ import QtQuick 2.3 import "windows" as Windows import "controls" -import "controls-uit" as Controls +import controlsUit 1.0 as Controls import "styles" -import "styles-uit" +import stylesUit 1.0 Windows.Window { id: root diff --git a/interface/resources/qml/TabletBrowser.qml b/interface/resources/qml/TabletBrowser.qml index 141c1f25a7..720a904231 100644 --- a/interface/resources/qml/TabletBrowser.qml +++ b/interface/resources/qml/TabletBrowser.qml @@ -3,9 +3,9 @@ import QtWebChannel 1.0 import QtWebEngine 1.5 import "controls" -import "controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls import "styles" as HifiStyles -import "styles-uit" +import stylesUit 1.0 import "windows" Item { diff --git a/interface/resources/qml/UpdateDialog.qml b/interface/resources/qml/UpdateDialog.qml index 5e05601ce4..9c22d0b65b 100644 --- a/interface/resources/qml/UpdateDialog.qml +++ b/interface/resources/qml/UpdateDialog.qml @@ -4,9 +4,9 @@ import QtQuick.Controls 1.3 import QtQuick.Controls.Styles 1.3 import QtGraphicalEffects 1.0 -import "controls-uit" +import controlsUit 1.0 import "styles" as HifiStyles -import "styles-uit" +import stylesUit 1.0 import "windows" ScrollingWindow { diff --git a/interface/resources/qml/controls/Button.qml b/interface/resources/qml/controls/Button.qml index 6cbdec5644..b677822c0e 100644 --- a/interface/resources/qml/controls/Button.qml +++ b/interface/resources/qml/controls/Button.qml @@ -3,7 +3,6 @@ import QtQuick.Controls 2.2 as Original import "." import "../styles" -import "../controls-uit" Original.Button { id: control diff --git a/interface/resources/qml/controls/FlickableWebViewCore.qml b/interface/resources/qml/controls/FlickableWebViewCore.qml index 943f15e1de..cce32c137a 100644 --- a/interface/resources/qml/controls/FlickableWebViewCore.qml +++ b/interface/resources/qml/controls/FlickableWebViewCore.qml @@ -4,7 +4,7 @@ import QtWebChannel 1.0 import QtQuick.Controls 2.2 -import "../styles-uit" as StylesUIt +import stylesUit 1.0 as StylesUIt Item { id: flick diff --git a/interface/resources/qml/controls/TabletWebButton.qml b/interface/resources/qml/controls/TabletWebButton.qml index d016f71f2d..140461d817 100644 --- a/interface/resources/qml/controls/TabletWebButton.qml +++ b/interface/resources/qml/controls/TabletWebButton.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import "../styles-uit" +import stylesUit 1.0 Rectangle { property alias text: label.text diff --git a/interface/resources/qml/controls/TabletWebScreen.qml b/interface/resources/qml/controls/TabletWebScreen.qml index bb037ad478..be11f16498 100644 --- a/interface/resources/qml/controls/TabletWebScreen.qml +++ b/interface/resources/qml/controls/TabletWebScreen.qml @@ -1,5 +1,5 @@ import QtQuick 2.7 -import "../controls-uit" as HiFiControls +import controlsUit 1.0 as HiFiControls Item { id: root diff --git a/interface/resources/qml/controls/TabletWebView.qml b/interface/resources/qml/controls/TabletWebView.qml index db695dbfb2..0c5ca37e00 100644 --- a/interface/resources/qml/controls/TabletWebView.qml +++ b/interface/resources/qml/controls/TabletWebView.qml @@ -1,8 +1,8 @@ import QtQuick 2.7 import QtWebEngine 1.5 -import "../controls-uit" as HiFiControls +import controlsUit 1.0 as HiFiControls import "../styles" as HifiStyles -import "../styles-uit" +import stylesUit 1.0 Item { id: root diff --git a/interface/resources/qml/controls/WebView.qml b/interface/resources/qml/controls/WebView.qml index 71bf69fdc8..375bcd50e0 100644 --- a/interface/resources/qml/controls/WebView.qml +++ b/interface/resources/qml/controls/WebView.qml @@ -1,5 +1,5 @@ import QtQuick 2.7 -import "../controls-uit" as HiFiControls +import controlsUit 1.0 as HiFiControls Item { width: parent !== null ? parent.width : undefined diff --git a/interface/resources/qml/controls-uit/+android/ImageButton.qml b/interface/resources/qml/controlsUit/+android/ImageButton.qml similarity index 96% rename from interface/resources/qml/controls-uit/+android/ImageButton.qml rename to interface/resources/qml/controlsUit/+android/ImageButton.qml index 5ebf7cd3e9..88eaf95d76 100644 --- a/interface/resources/qml/controls-uit/+android/ImageButton.qml +++ b/interface/resources/qml/controlsUit/+android/ImageButton.qml @@ -1,6 +1,6 @@ // // ImageButton.qml -// interface/resources/qml/controls-uit +// interface/resources/qml/controlsUit // // Created by Gabriel Calero & Cristian Duarte on 12 Oct 2017 // Copyright 2017 High Fidelity, Inc. @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Layouts 1.3 -import "../styles-uit" as HifiStyles +import "../stylesUit" as HifiStyles Item { id: button @@ -79,4 +79,4 @@ Item { } } ] -} \ No newline at end of file +} diff --git a/interface/resources/qml/controls-uit/AttachmentsTable.qml b/interface/resources/qml/controlsUit/AttachmentsTable.qml similarity index 98% rename from interface/resources/qml/controls-uit/AttachmentsTable.qml rename to interface/resources/qml/controlsUit/AttachmentsTable.qml index 8ee9909ab8..a2677962da 100644 --- a/interface/resources/qml/controls-uit/AttachmentsTable.qml +++ b/interface/resources/qml/controlsUit/AttachmentsTable.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.XmlListModel 2.0 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls import "../windows" import "../hifi/models" diff --git a/interface/resources/qml/controls-uit/BaseWebView.qml b/interface/resources/qml/controlsUit/BaseWebView.qml similarity index 100% rename from interface/resources/qml/controls-uit/BaseWebView.qml rename to interface/resources/qml/controlsUit/BaseWebView.qml diff --git a/interface/resources/qml/controls-uit/Button.qml b/interface/resources/qml/controlsUit/Button.qml similarity index 99% rename from interface/resources/qml/controls-uit/Button.qml rename to interface/resources/qml/controlsUit/Button.qml index f1a6e4bb4a..6ea7ce4b4c 100644 --- a/interface/resources/qml/controls-uit/Button.qml +++ b/interface/resources/qml/controlsUit/Button.qml @@ -12,7 +12,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 as Original import TabletScriptingInterface 1.0 -import "../styles-uit" +import "../stylesUit" Original.Button { id: control; diff --git a/interface/resources/qml/controls-uit/CheckBox.qml b/interface/resources/qml/controlsUit/CheckBox.qml similarity index 99% rename from interface/resources/qml/controls-uit/CheckBox.qml rename to interface/resources/qml/controlsUit/CheckBox.qml index 6e4a3df010..abf08908fb 100644 --- a/interface/resources/qml/controls-uit/CheckBox.qml +++ b/interface/resources/qml/controlsUit/CheckBox.qml @@ -11,7 +11,7 @@ import QtQuick 2.2 import QtQuick.Controls 2.2 as Original -import "../styles-uit" +import "../stylesUit" import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml b/interface/resources/qml/controlsUit/CheckBoxQQC2.qml similarity index 98% rename from interface/resources/qml/controls-uit/CheckBoxQQC2.qml rename to interface/resources/qml/controlsUit/CheckBoxQQC2.qml index 8a9686ff5e..91d35ecd58 100644 --- a/interface/resources/qml/controls-uit/CheckBoxQQC2.qml +++ b/interface/resources/qml/controlsUit/CheckBoxQQC2.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../styles-uit" -import "../controls-uit" as HiFiControls +import "../stylesUit" +import "." as HiFiControls import TabletScriptingInterface 1.0 CheckBox { diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controlsUit/ComboBox.qml similarity index 99% rename from interface/resources/qml/controls-uit/ComboBox.qml rename to interface/resources/qml/controlsUit/ComboBox.qml index 245b565a62..8d1d7a5262 100644 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controlsUit/ComboBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls FocusScope { id: root diff --git a/interface/resources/qml/controls-uit/ContentSection.qml b/interface/resources/qml/controlsUit/ContentSection.qml similarity index 99% rename from interface/resources/qml/controls-uit/ContentSection.qml rename to interface/resources/qml/controlsUit/ContentSection.qml index 47a13e9262..262c29220f 100644 --- a/interface/resources/qml/controls-uit/ContentSection.qml +++ b/interface/resources/qml/controlsUit/ContentSection.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../styles-uit" +import "../stylesUit" Column { property string name: "Content Section" diff --git a/interface/resources/qml/controls-uit/FilterBar.qml b/interface/resources/qml/controlsUit/FilterBar.qml similarity index 99% rename from interface/resources/qml/controls-uit/FilterBar.qml rename to interface/resources/qml/controlsUit/FilterBar.qml index ecae790b22..3e407040bc 100644 --- a/interface/resources/qml/controls-uit/FilterBar.qml +++ b/interface/resources/qml/controlsUit/FilterBar.qml @@ -12,8 +12,8 @@ import QtQuick 2.9 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls Item { id: root; diff --git a/interface/resources/qml/controls-uit/GlyphButton.qml b/interface/resources/qml/controlsUit/GlyphButton.qml similarity index 99% rename from interface/resources/qml/controls-uit/GlyphButton.qml rename to interface/resources/qml/controlsUit/GlyphButton.qml index 9129486720..17f7fba2d6 100644 --- a/interface/resources/qml/controls-uit/GlyphButton.qml +++ b/interface/resources/qml/controlsUit/GlyphButton.qml @@ -12,7 +12,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 as Original import TabletScriptingInterface 1.0 -import "../styles-uit" +import "../stylesUit" Original.Button { id: control diff --git a/interface/resources/qml/controls-uit/HorizontalRule.qml b/interface/resources/qml/controlsUit/HorizontalRule.qml similarity index 100% rename from interface/resources/qml/controls-uit/HorizontalRule.qml rename to interface/resources/qml/controlsUit/HorizontalRule.qml diff --git a/interface/resources/qml/controls-uit/HorizontalSpacer.qml b/interface/resources/qml/controlsUit/HorizontalSpacer.qml similarity index 94% rename from interface/resources/qml/controls-uit/HorizontalSpacer.qml rename to interface/resources/qml/controlsUit/HorizontalSpacer.qml index 545154ab44..efcabf2699 100644 --- a/interface/resources/qml/controls-uit/HorizontalSpacer.qml +++ b/interface/resources/qml/controlsUit/HorizontalSpacer.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" Item { id: root diff --git a/interface/resources/qml/controls-uit/ImageMessageBox.qml b/interface/resources/qml/controlsUit/ImageMessageBox.qml similarity index 98% rename from interface/resources/qml/controls-uit/ImageMessageBox.qml rename to interface/resources/qml/controlsUit/ImageMessageBox.qml index 74313f7ffe..46d93383a4 100644 --- a/interface/resources/qml/controls-uit/ImageMessageBox.qml +++ b/interface/resources/qml/controlsUit/ImageMessageBox.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" Item { id: imageBox diff --git a/interface/resources/qml/controls-uit/Key.qml b/interface/resources/qml/controlsUit/Key.qml similarity index 100% rename from interface/resources/qml/controls-uit/Key.qml rename to interface/resources/qml/controlsUit/Key.qml diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controlsUit/Keyboard.qml similarity index 100% rename from interface/resources/qml/controls-uit/Keyboard.qml rename to interface/resources/qml/controlsUit/Keyboard.qml diff --git a/interface/resources/qml/controls-uit/Label.qml b/interface/resources/qml/controlsUit/Label.qml similarity index 97% rename from interface/resources/qml/controls-uit/Label.qml rename to interface/resources/qml/controlsUit/Label.qml index 4c7051b495..7f208cde88 100644 --- a/interface/resources/qml/controls-uit/Label.qml +++ b/interface/resources/qml/controlsUit/Label.qml @@ -10,7 +10,7 @@ import QtQuick 2.7 -import "../styles-uit" +import "../stylesUit" RalewaySemiBold { HifiConstants { id: hifi } diff --git a/interface/resources/qml/controls-uit/QueuedButton.qml b/interface/resources/qml/controlsUit/QueuedButton.qml similarity index 98% rename from interface/resources/qml/controls-uit/QueuedButton.qml rename to interface/resources/qml/controlsUit/QueuedButton.qml index 6612d582df..70ad9eb112 100644 --- a/interface/resources/qml/controls-uit/QueuedButton.qml +++ b/interface/resources/qml/controlsUit/QueuedButton.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" import "." as HifiControls HifiControls.Button { diff --git a/interface/resources/qml/controls-uit/RadioButton.qml b/interface/resources/qml/controlsUit/RadioButton.qml similarity index 97% rename from interface/resources/qml/controls-uit/RadioButton.qml rename to interface/resources/qml/controlsUit/RadioButton.qml index 56324c55d7..ad62a77aa7 100644 --- a/interface/resources/qml/controls-uit/RadioButton.qml +++ b/interface/resources/qml/controlsUit/RadioButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 as Original -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/controls-uit/ScrollBar.qml b/interface/resources/qml/controlsUit/ScrollBar.qml similarity index 98% rename from interface/resources/qml/controls-uit/ScrollBar.qml rename to interface/resources/qml/controlsUit/ScrollBar.qml index 125e84e585..bcb1f62429 100644 --- a/interface/resources/qml/controls-uit/ScrollBar.qml +++ b/interface/resources/qml/controlsUit/ScrollBar.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../styles-uit" +import "../stylesUit" ScrollBar { visible: size < 1.0 diff --git a/interface/resources/qml/controls-uit/Separator.qml b/interface/resources/qml/controlsUit/Separator.qml similarity index 98% rename from interface/resources/qml/controls-uit/Separator.qml rename to interface/resources/qml/controlsUit/Separator.qml index 3350764ae9..da6b9adf57 100644 --- a/interface/resources/qml/controls-uit/Separator.qml +++ b/interface/resources/qml/controlsUit/Separator.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" Item { property int colorScheme: 0; diff --git a/interface/resources/qml/controls-uit/Slider.qml b/interface/resources/qml/controlsUit/Slider.qml similarity index 98% rename from interface/resources/qml/controls-uit/Slider.qml rename to interface/resources/qml/controlsUit/Slider.qml index 2a5d4c137d..8cb08b69e2 100644 --- a/interface/resources/qml/controls-uit/Slider.qml +++ b/interface/resources/qml/controlsUit/Slider.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls Slider { id: slider diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controlsUit/SpinBox.qml similarity index 98% rename from interface/resources/qml/controls-uit/SpinBox.qml rename to interface/resources/qml/controlsUit/SpinBox.qml index 3d3ea7a75e..d24c7c5e8c 100644 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controlsUit/SpinBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls SpinBox { id: spinBox diff --git a/interface/resources/qml/controls-uit/Switch.qml b/interface/resources/qml/controlsUit/Switch.qml similarity index 99% rename from interface/resources/qml/controls-uit/Switch.qml rename to interface/resources/qml/controlsUit/Switch.qml index bfe86b1420..0961ef2500 100644 --- a/interface/resources/qml/controls-uit/Switch.qml +++ b/interface/resources/qml/controlsUit/Switch.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 as Original -import "../styles-uit" +import "../stylesUit" Item { id: rootSwitch; diff --git a/interface/resources/qml/controls-uit/Table.qml b/interface/resources/qml/controlsUit/Table.qml similarity index 99% rename from interface/resources/qml/controls-uit/Table.qml rename to interface/resources/qml/controlsUit/Table.qml index ce4e1c376a..ab74361046 100644 --- a/interface/resources/qml/controls-uit/Table.qml +++ b/interface/resources/qml/controlsUit/Table.qml @@ -13,7 +13,7 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Controls 2.3 as QQC2 -import "../styles-uit" +import "../stylesUit" TableView { id: tableView diff --git a/interface/resources/qml/controls-uit/TabletContentSection.qml b/interface/resources/qml/controlsUit/TabletContentSection.qml similarity index 99% rename from interface/resources/qml/controls-uit/TabletContentSection.qml rename to interface/resources/qml/controlsUit/TabletContentSection.qml index c34f4afdd6..dccaf31bbe 100644 --- a/interface/resources/qml/controls-uit/TabletContentSection.qml +++ b/interface/resources/qml/controlsUit/TabletContentSection.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../styles-uit" +import "../stylesUit" Column { property string name: "Content Section" diff --git a/interface/resources/qml/controls-uit/TabletHeader.qml b/interface/resources/qml/controlsUit/TabletHeader.qml similarity index 96% rename from interface/resources/qml/controls-uit/TabletHeader.qml rename to interface/resources/qml/controlsUit/TabletHeader.qml index 56203de286..f626700742 100644 --- a/interface/resources/qml/controls-uit/TabletHeader.qml +++ b/interface/resources/qml/controlsUit/TabletHeader.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" Rectangle { diff --git a/interface/resources/qml/controls-uit/TextAction.qml b/interface/resources/qml/controlsUit/TextAction.qml similarity index 96% rename from interface/resources/qml/controls-uit/TextAction.qml rename to interface/resources/qml/controlsUit/TextAction.qml index 1745a6c273..a0a1bb7d07 100644 --- a/interface/resources/qml/controls-uit/TextAction.qml +++ b/interface/resources/qml/controlsUit/TextAction.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls Item { property string icon: "" diff --git a/interface/resources/qml/controls-uit/TextEdit.qml b/interface/resources/qml/controlsUit/TextEdit.qml similarity index 95% rename from interface/resources/qml/controls-uit/TextEdit.qml rename to interface/resources/qml/controlsUit/TextEdit.qml index a72a3b13d8..7446c5040f 100644 --- a/interface/resources/qml/controls-uit/TextEdit.qml +++ b/interface/resources/qml/controlsUit/TextEdit.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" TextEdit { diff --git a/interface/resources/qml/controls-uit/TextField.qml b/interface/resources/qml/controlsUit/TextField.qml similarity index 99% rename from interface/resources/qml/controls-uit/TextField.qml rename to interface/resources/qml/controlsUit/TextField.qml index 917068ac01..d78f3a1340 100644 --- a/interface/resources/qml/controls-uit/TextField.qml +++ b/interface/resources/qml/controlsUit/TextField.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../styles-uit" -import "../controls-uit" as HifiControls +import "../stylesUit" +import "." as HifiControls TextField { id: textField diff --git a/interface/resources/qml/controls-uit/ToolTip.qml b/interface/resources/qml/controlsUit/ToolTip.qml similarity index 100% rename from interface/resources/qml/controls-uit/ToolTip.qml rename to interface/resources/qml/controlsUit/ToolTip.qml diff --git a/interface/resources/qml/controls-uit/Tree.qml b/interface/resources/qml/controlsUit/Tree.qml similarity index 99% rename from interface/resources/qml/controls-uit/Tree.qml rename to interface/resources/qml/controlsUit/Tree.qml index 5199a10a27..f2c49095b1 100644 --- a/interface/resources/qml/controls-uit/Tree.qml +++ b/interface/resources/qml/controlsUit/Tree.qml @@ -15,7 +15,7 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Controls 2.2 as QQC2 -import "../styles-uit" +import "../stylesUit" TreeView { id: treeView diff --git a/interface/resources/qml/controls-uit/VerticalSpacer.qml b/interface/resources/qml/controlsUit/VerticalSpacer.qml similarity index 94% rename from interface/resources/qml/controls-uit/VerticalSpacer.qml rename to interface/resources/qml/controlsUit/VerticalSpacer.qml index 2df65f1002..4c93aa1801 100644 --- a/interface/resources/qml/controls-uit/VerticalSpacer.qml +++ b/interface/resources/qml/controlsUit/VerticalSpacer.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import "../stylesUit" Item { id: root diff --git a/interface/resources/qml/controls-uit/WebGlyphButton.qml b/interface/resources/qml/controlsUit/WebGlyphButton.qml similarity index 98% rename from interface/resources/qml/controls-uit/WebGlyphButton.qml rename to interface/resources/qml/controlsUit/WebGlyphButton.qml index fd7cd001b2..7739ecd5e7 100644 --- a/interface/resources/qml/controls-uit/WebGlyphButton.qml +++ b/interface/resources/qml/controlsUit/WebGlyphButton.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 as Original -import "../styles-uit" +import "../stylesUit" Original.Button { id: control diff --git a/interface/resources/qml/controls-uit/WebSpinner.qml b/interface/resources/qml/controlsUit/WebSpinner.qml similarity index 100% rename from interface/resources/qml/controls-uit/WebSpinner.qml rename to interface/resources/qml/controlsUit/WebSpinner.qml diff --git a/interface/resources/qml/controls-uit/WebView.qml b/interface/resources/qml/controlsUit/WebView.qml similarity index 100% rename from interface/resources/qml/controls-uit/WebView.qml rename to interface/resources/qml/controlsUit/WebView.qml diff --git a/interface/resources/qml/controls-uit/qmldir b/interface/resources/qml/controlsUit/qmldir similarity index 100% rename from interface/resources/qml/controls-uit/qmldir rename to interface/resources/qml/controlsUit/qmldir diff --git a/interface/resources/qml/dialogs/AssetDialog.qml b/interface/resources/qml/dialogs/AssetDialog.qml index e8d28e9b37..b8eaab0b8d 100644 --- a/interface/resources/qml/dialogs/AssetDialog.qml +++ b/interface/resources/qml/dialogs/AssetDialog.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import "../styles-uit" +import stylesUit 1.0 import "../windows" import "assetDialog" diff --git a/interface/resources/qml/dialogs/CustomQueryDialog.qml b/interface/resources/qml/dialogs/CustomQueryDialog.qml index 0c86b93c4b..026068eee1 100644 --- a/interface/resources/qml/dialogs/CustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/CustomQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7; import QtQuick.Dialogs 1.2 as OriginalDialogs; import QtQuick.Controls 2.3 -import "../controls-uit"; -import "../styles-uit"; +import controlsUit 1.0 +import stylesUit 1.0 import "../windows"; ModalWindow { diff --git a/interface/resources/qml/dialogs/FileDialog.qml b/interface/resources/qml/dialogs/FileDialog.qml index 6651af0db3..b7340575dd 100644 --- a/interface/resources/qml/dialogs/FileDialog.qml +++ b/interface/resources/qml/dialogs/FileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" import "fileDialog" diff --git a/interface/resources/qml/dialogs/MessageDialog.qml b/interface/resources/qml/dialogs/MessageDialog.qml index b5ac6cab72..9428e3ab6e 100644 --- a/interface/resources/qml/dialogs/MessageDialog.qml +++ b/interface/resources/qml/dialogs/MessageDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" import "messageDialog" diff --git a/interface/resources/qml/dialogs/PreferencesDialog.qml b/interface/resources/qml/dialogs/PreferencesDialog.qml index fffd0e2ed9..9df1d0b963 100644 --- a/interface/resources/qml/dialogs/PreferencesDialog.qml +++ b/interface/resources/qml/dialogs/PreferencesDialog.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../controls-uit" as HifiControls -import "../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 import "../windows" import "preferences" diff --git a/interface/resources/qml/dialogs/QueryDialog.qml b/interface/resources/qml/dialogs/QueryDialog.qml index 41ee30e6d5..9cfb3011bd 100644 --- a/interface/resources/qml/dialogs/QueryDialog.qml +++ b/interface/resources/qml/dialogs/QueryDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" ModalWindow { diff --git a/interface/resources/qml/dialogs/TabletAssetDialog.qml b/interface/resources/qml/dialogs/TabletAssetDialog.qml index 897378e40c..b3bd45f972 100644 --- a/interface/resources/qml/dialogs/TabletAssetDialog.qml +++ b/interface/resources/qml/dialogs/TabletAssetDialog.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import stylesUit 1.0 import "../windows" import "assetDialog" diff --git a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml index 81a2c5c1e0..c7772984ab 100644 --- a/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletCustomQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs import QtQuick.Controls 2.3 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" TabletModalWindow { diff --git a/interface/resources/qml/dialogs/TabletFileDialog.qml b/interface/resources/qml/dialogs/TabletFileDialog.qml index 6848c230e3..3be6e30dd0 100644 --- a/interface/resources/qml/dialogs/TabletFileDialog.qml +++ b/interface/resources/qml/dialogs/TabletFileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" import "fileDialog" diff --git a/interface/resources/qml/dialogs/TabletLoginDialog.qml b/interface/resources/qml/dialogs/TabletLoginDialog.qml index c85b2b2ba0..6314921286 100644 --- a/interface/resources/qml/dialogs/TabletLoginDialog.qml +++ b/interface/resources/qml/dialogs/TabletLoginDialog.qml @@ -11,8 +11,8 @@ import Hifi 1.0 import QtQuick 2.5 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" import "../LoginDialog" diff --git a/interface/resources/qml/dialogs/TabletMessageBox.qml b/interface/resources/qml/dialogs/TabletMessageBox.qml index fabe0dd247..1e6f0734ad 100644 --- a/interface/resources/qml/dialogs/TabletMessageBox.qml +++ b/interface/resources/qml/dialogs/TabletMessageBox.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" import "messageDialog" diff --git a/interface/resources/qml/dialogs/TabletQueryDialog.qml b/interface/resources/qml/dialogs/TabletQueryDialog.qml index 5746a3d67c..8f63730b8e 100644 --- a/interface/resources/qml/dialogs/TabletQueryDialog.qml +++ b/interface/resources/qml/dialogs/TabletQueryDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Dialogs 1.2 as OriginalDialogs import QtQuick.Controls 2.3 -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../windows" TabletModalWindow { diff --git a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml index c3e842bc2f..da976ef3e1 100644 --- a/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml +++ b/interface/resources/qml/dialogs/assetDialog/AssetDialogContent.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 import QtQuick.Controls 1.5 as QQC1 -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../fileDialog" diff --git a/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml index 50a10974b5..6c042b5598 100644 --- a/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml +++ b/interface/resources/qml/dialogs/fileDialog/FileTypeSelection.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../../controls-uit" +import controlsUit 1.0 ComboBox { id: root diff --git a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml index 8411980db7..f5715fa2c2 100644 --- a/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml +++ b/interface/resources/qml/dialogs/messageDialog/MessageDialogButton.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 -import "../../controls-uit" +import controlsUit 1.0 Button { property var dialog; diff --git a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml index 0efc3776b3..9505e70530 100644 --- a/interface/resources/qml/dialogs/preferences/AvatarPreference.qml +++ b/interface/resources/qml/dialogs/preferences/AvatarPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../../controls-uit" +import controlsUit 1.0 import "../../hifi/tablet/tabletWindows/preferences" Preference { diff --git a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml index 2cf50891c9..6059f8ff1c 100644 --- a/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/BrowsablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml index 454a9124ae..09c5b4329d 100644 --- a/interface/resources/qml/dialogs/preferences/ButtonPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ButtonPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml index e2172d8eda..f6f840bbe8 100644 --- a/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/CheckBoxPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml index 3b3efaf520..98cb397976 100644 --- a/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/ComboBoxPreference.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../../controls-uit" as HiFiControls -import "../../styles-uit" +import controlsUit 1.0 as HiFiControls +import stylesUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/EditablePreference.qml b/interface/resources/qml/dialogs/preferences/EditablePreference.qml index 8acf8e1f76..e0c79ebba0 100644 --- a/interface/resources/qml/dialogs/preferences/EditablePreference.qml +++ b/interface/resources/qml/dialogs/preferences/EditablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml b/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml index cfc2e94ed9..f963003c59 100644 --- a/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml +++ b/interface/resources/qml/dialogs/preferences/PrimaryHandPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml index 103904a666..0a09d8d609 100644 --- a/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml +++ b/interface/resources/qml/dialogs/preferences/RadioButtonsPreference.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/Section.qml b/interface/resources/qml/dialogs/preferences/Section.qml index c2c6583b7e..a9b755ad83 100644 --- a/interface/resources/qml/dialogs/preferences/Section.qml +++ b/interface/resources/qml/dialogs/preferences/Section.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import Hifi 1.0 -import "../../controls-uit" as HiFiControls -import "../../styles-uit" +import controlsUit 1.0 as HiFiControls +import stylesUit 1.0 import "." Preference { diff --git a/interface/resources/qml/dialogs/preferences/SliderPreference.qml b/interface/resources/qml/dialogs/preferences/SliderPreference.qml index 2bdda09fc3..c8a2aae158 100644 --- a/interface/resources/qml/dialogs/preferences/SliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SliderPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml index b2c334b674..1b080c2759 100644 --- a/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinBoxPreference.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml index 126e62fc30..cbc804d9d7 100644 --- a/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml +++ b/interface/resources/qml/dialogs/preferences/SpinnerSliderPreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../dialogs" -import "../../controls-uit" +import controlsUit 1.0 Preference { id: root diff --git a/interface/resources/qml/hifi/+android/ActionBar.qml b/interface/resources/qml/hifi/+android/ActionBar.qml index d487901d6f..3c58156f30 100644 --- a/interface/resources/qml/hifi/+android/ActionBar.qml +++ b/interface/resources/qml/hifi/+android/ActionBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/AudioBar.qml b/interface/resources/qml/hifi/+android/AudioBar.qml index 6cc17fccf7..912572fdf8 100644 --- a/interface/resources/qml/hifi/+android/AudioBar.qml +++ b/interface/resources/qml/hifi/+android/AudioBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/AvatarOption.qml b/interface/resources/qml/hifi/+android/AvatarOption.qml index 85d7e52eb2..7eba3c2a67 100644 --- a/interface/resources/qml/hifi/+android/AvatarOption.qml +++ b/interface/resources/qml/hifi/+android/AvatarOption.qml @@ -11,7 +11,7 @@ import QtQuick.Layouts 1.3 import QtQuick 2.5 -import "../controls-uit" as HifiControlsUit +import controlsUit 1.0 as HifiControlsUit ColumnLayout { id: itemRoot diff --git a/interface/resources/qml/hifi/+android/StatsBar.qml b/interface/resources/qml/hifi/+android/StatsBar.qml index aee438b44f..64e93b4a08 100644 --- a/interface/resources/qml/hifi/+android/StatsBar.qml +++ b/interface/resources/qml/hifi/+android/StatsBar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/WindowHeader.qml b/interface/resources/qml/hifi/+android/WindowHeader.qml index 4ec0a0c6e6..5316fc4786 100644 --- a/interface/resources/qml/hifi/+android/WindowHeader.qml +++ b/interface/resources/qml/hifi/+android/WindowHeader.qml @@ -16,8 +16,8 @@ import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "." import "../styles" as HifiStyles -import "../styles-uit" -import "../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/+android/bottomHudOptions.qml b/interface/resources/qml/hifi/+android/bottomHudOptions.qml index 22beccf531..6b830d94c2 100644 --- a/interface/resources/qml/hifi/+android/bottomHudOptions.qml +++ b/interface/resources/qml/hifi/+android/bottomHudOptions.qml @@ -16,8 +16,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 import "../../styles" as HifiStyles -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls import ".." import "." diff --git a/interface/resources/qml/hifi/+android/modesbar.qml b/interface/resources/qml/hifi/+android/modesbar.qml index 994bf1efe4..1bf04fb8d9 100644 --- a/interface/resources/qml/hifi/+android/modesbar.qml +++ b/interface/resources/qml/hifi/+android/modesbar.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls import ".." diff --git a/interface/resources/qml/hifi/AssetServer.qml b/interface/resources/qml/hifi/AssetServer.qml index 1a7f5bac40..ad337a6361 100644 --- a/interface/resources/qml/hifi/AssetServer.qml +++ b/interface/resources/qml/hifi/AssetServer.qml @@ -14,8 +14,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import "../styles-uit" -import "../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../windows" as Windows import "../dialogs" diff --git a/interface/resources/qml/hifi/AvatarApp.qml b/interface/resources/qml/hifi/AvatarApp.qml index aea5931627..39590748cf 100644 --- a/interface/resources/qml/hifi/AvatarApp.qml +++ b/interface/resources/qml/hifi/AvatarApp.qml @@ -3,8 +3,8 @@ import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtQml.Models 2.1 import QtGraphicalEffects 1.0 -import "../controls-uit" as HifiControls -import "../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 import "avatarapp" Rectangle { diff --git a/interface/resources/qml/hifi/Card.qml b/interface/resources/qml/hifi/Card.qml index 83bf1e2c54..7f29324416 100644 --- a/interface/resources/qml/hifi/Card.qml +++ b/interface/resources/qml/hifi/Card.qml @@ -17,7 +17,7 @@ import QtGraphicalEffects 1.0 import TabletScriptingInterface 1.0 import "toolbars" -import "../styles-uit" +import stylesUit 1.0 Item { id: root; diff --git a/interface/resources/qml/hifi/ComboDialog.qml b/interface/resources/qml/hifi/ComboDialog.qml index e5dc8a9c1a..74d9c1019b 100644 --- a/interface/resources/qml/hifi/ComboDialog.qml +++ b/interface/resources/qml/hifi/ComboDialog.qml @@ -10,8 +10,8 @@ // import QtQuick 2.5 -import "../styles-uit" -import "../controls-uit" +import stylesUit 1.0 +import controlsUit 1.0 Item { property var dialogTitleText : ""; diff --git a/interface/resources/qml/hifi/Desktop.qml b/interface/resources/qml/hifi/Desktop.qml index 4d342fe775..511d9377e5 100644 --- a/interface/resources/qml/hifi/Desktop.qml +++ b/interface/resources/qml/hifi/Desktop.qml @@ -8,7 +8,7 @@ import "../desktop" as OriginalDesktop import ".." import "." import "./toolbars" -import "../controls-uit" +import controlsUit 1.0 OriginalDesktop.Desktop { id: desktop diff --git a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml index 9e9dcc75b2..048add24e5 100644 --- a/interface/resources/qml/hifi/DesktopLetterboxMessage.qml +++ b/interface/resources/qml/hifi/DesktopLetterboxMessage.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import stylesUit 1.0 Item { property alias text: popupText.text diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 346481fe1f..4cfd4804b3 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -15,7 +15,7 @@ import Hifi 1.0 import QtQuick 2.5 import QtGraphicalEffects 1.0 import "toolbars" -import "../styles-uit" +import stylesUit 1.0 import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. Column { diff --git a/interface/resources/qml/hifi/LetterboxMessage.qml b/interface/resources/qml/hifi/LetterboxMessage.qml index 8a18d88842..68bebdd041 100644 --- a/interface/resources/qml/hifi/LetterboxMessage.qml +++ b/interface/resources/qml/hifi/LetterboxMessage.qml @@ -10,7 +10,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import stylesUit 1.0 Item { property alias text: popupText.text diff --git a/interface/resources/qml/hifi/NameCard.qml b/interface/resources/qml/hifi/NameCard.qml index dfa6555150..242ca5ab57 100644 --- a/interface/resources/qml/hifi/NameCard.qml +++ b/interface/resources/qml/hifi/NameCard.qml @@ -13,8 +13,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtGraphicalEffects 1.0 -import "../styles-uit" -import "../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "toolbars" // references Users, UserActivityLogger, MyAvatar, Vec3, Quat, AddressManager, Account from root context diff --git a/interface/resources/qml/hifi/Pal.qml b/interface/resources/qml/hifi/Pal.qml index 1384cb8711..368beaab47 100644 --- a/interface/resources/qml/hifi/Pal.qml +++ b/interface/resources/qml/hifi/Pal.qml @@ -15,8 +15,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 -import "../styles-uit" -import "../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/SkyboxChanger.qml b/interface/resources/qml/hifi/SkyboxChanger.qml index f0c97a11a3..a66fc38415 100644 --- a/interface/resources/qml/hifi/SkyboxChanger.qml +++ b/interface/resources/qml/hifi/SkyboxChanger.qml @@ -10,8 +10,8 @@ // import QtQuick 2.5 -import "../styles-uit" -import "../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import QtQuick.Controls 2.2 Item { diff --git a/interface/resources/qml/hifi/SpectatorCamera.qml b/interface/resources/qml/hifi/SpectatorCamera.qml index 4bf80e410b..09b722b906 100644 --- a/interface/resources/qml/hifi/SpectatorCamera.qml +++ b/interface/resources/qml/hifi/SpectatorCamera.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 -import "../styles-uit" -import "../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../controls" as HifiControls // references HMD, XXX from root context diff --git a/interface/resources/qml/hifi/TabletTextButton.qml b/interface/resources/qml/hifi/TabletTextButton.qml index e5ff1d381d..6c9e0331df 100644 --- a/interface/resources/qml/hifi/TabletTextButton.qml +++ b/interface/resources/qml/hifi/TabletTextButton.qml @@ -10,7 +10,7 @@ import Hifi 1.0 import QtQuick 2.4 -import "../styles-uit" +import stylesUit 1.0 Rectangle { property alias text: label.text diff --git a/interface/resources/qml/hifi/TextButton.qml b/interface/resources/qml/hifi/TextButton.qml index 02e49d86e4..61588a9603 100644 --- a/interface/resources/qml/hifi/TextButton.qml +++ b/interface/resources/qml/hifi/TextButton.qml @@ -9,7 +9,7 @@ // import Hifi 1.0 import QtQuick 2.4 -import "../styles-uit" +import stylesUit 1.0 Rectangle { property alias text: label.text; diff --git a/interface/resources/qml/hifi/WebBrowser.qml b/interface/resources/qml/hifi/WebBrowser.qml index ab93752d92..c05de26471 100644 --- a/interface/resources/qml/hifi/WebBrowser.qml +++ b/interface/resources/qml/hifi/WebBrowser.qml @@ -18,8 +18,8 @@ import QtGraphicalEffects 1.0 import QtWebEngine 1.5 import QtWebChannel 1.0 -import "../styles-uit" -import "../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../windows" import "../controls" diff --git a/interface/resources/qml/hifi/audio/Audio.qml b/interface/resources/qml/hifi/audio/Audio.qml index f4a708567a..c8dd83cd62 100644 --- a/interface/resources/qml/hifi/audio/Audio.qml +++ b/interface/resources/qml/hifi/audio/Audio.qml @@ -15,8 +15,8 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" import "./" as AudioControls diff --git a/interface/resources/qml/hifi/audio/AudioTabButton.qml b/interface/resources/qml/hifi/audio/AudioTabButton.qml index 3a3ed90f5e..32331ccb6e 100644 --- a/interface/resources/qml/hifi/audio/AudioTabButton.qml +++ b/interface/resources/qml/hifi/audio/AudioTabButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 TabButton { id: control diff --git a/interface/resources/qml/hifi/audio/CheckBox.qml b/interface/resources/qml/hifi/audio/CheckBox.qml index 3a954d4004..5ab62a5091 100644 --- a/interface/resources/qml/hifi/audio/CheckBox.qml +++ b/interface/resources/qml/hifi/audio/CheckBox.qml @@ -11,7 +11,7 @@ import QtQuick 2.7 -import "../../controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls HifiControls.CheckBoxQQC2 { color: "white" diff --git a/interface/resources/qml/hifi/audio/PlaySampleSound.qml b/interface/resources/qml/hifi/audio/PlaySampleSound.qml index 2b9599a3cc..cfe55af9c4 100644 --- a/interface/resources/qml/hifi/audio/PlaySampleSound.qml +++ b/interface/resources/qml/hifi/audio/PlaySampleSound.qml @@ -13,8 +13,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls RowLayout { property var sound: null; diff --git a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml index 5fff14e4a1..0740914440 100644 --- a/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml +++ b/interface/resources/qml/hifi/avatarapp/AdjustWearables.qml @@ -1,9 +1,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Layouts 1.3 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit -import "../../controls" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit Rectangle { id: root; diff --git a/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml b/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml index 9d9db010fb..d3c9cd1d5f 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarAppHeader.qml @@ -1,6 +1,6 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../styles-uit" +import stylesUit 1.0 ShadowRectangle { id: header diff --git a/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml b/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml index f66c7121cb..36cb4b1080 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarAppStyle.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 import QtQuick.Window 2.2 -import "../../styles-uit" +import stylesUit 1.0 QtObject { readonly property QtObject colors: QtObject { diff --git a/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml b/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml index cb73e9fe71..8b28d4c66b 100644 --- a/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml +++ b/interface/resources/qml/hifi/avatarapp/AvatarWearablesIndicator.qml @@ -1,6 +1,6 @@ import QtQuick 2.9 -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 ShadowRectangle { property int wearablesCount: 0 diff --git a/interface/resources/qml/hifi/avatarapp/BlueButton.qml b/interface/resources/qml/hifi/avatarapp/BlueButton.qml index e668951517..0cc84d5ba0 100644 --- a/interface/resources/qml/hifi/avatarapp/BlueButton.qml +++ b/interface/resources/qml/hifi/avatarapp/BlueButton.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit HifiControlsUit.Button { HifiConstants { diff --git a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml index 1387c0791a..780981a5a3 100644 --- a/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml +++ b/interface/resources/qml/hifi/avatarapp/CreateFavoriteDialog.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/InputField.qml b/interface/resources/qml/hifi/avatarapp/InputField.qml index 905518ef0f..2020d56c96 100644 --- a/interface/resources/qml/hifi/avatarapp/InputField.qml +++ b/interface/resources/qml/hifi/avatarapp/InputField.qml @@ -1,7 +1,7 @@ import QtQuick 2.5 import QtQuick.Controls 2.2 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit TextField { id: textField diff --git a/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml b/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml index 4b868b47ce..6c2101498c 100644 --- a/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml +++ b/interface/resources/qml/hifi/avatarapp/InputTextStyle4.qml @@ -1,5 +1,5 @@ -import "../../controls-uit" as HifiControlsUit -import "../../styles-uit" +import controlsUit 1.0 as HifiControlsUit +import stylesUit 1.0 import QtQuick 2.0 import QtQuick.Controls 2.2 diff --git a/interface/resources/qml/hifi/avatarapp/MessageBox.qml b/interface/resources/qml/hifi/avatarapp/MessageBox.qml index f111303214..eb28745b1a 100644 --- a/interface/resources/qml/hifi/avatarapp/MessageBox.qml +++ b/interface/resources/qml/hifi/avatarapp/MessageBox.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/Settings.qml b/interface/resources/qml/hifi/avatarapp/Settings.qml index 71bfbb084d..38acce2b2c 100644 --- a/interface/resources/qml/hifi/avatarapp/Settings.qml +++ b/interface/resources/qml/hifi/avatarapp/Settings.qml @@ -2,8 +2,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml index c2d84bb371..a2c84fad47 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowGlyph.qml @@ -1,4 +1,4 @@ -import "../../styles-uit" +import stylesUit 1.0 import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml index 3995446e49..51e1043702 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowImage.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowImage.qml @@ -1,4 +1,4 @@ -import "../../styles-uit" +import stylesUit 1.0 import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml index 741fce3d8d..3968fcb1ff 100644 --- a/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml +++ b/interface/resources/qml/hifi/avatarapp/ShadowRectangle.qml @@ -1,4 +1,4 @@ -import "../../styles-uit" +import stylesUit 1.0 import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml index e2c456ec04..69aff47373 100644 --- a/interface/resources/qml/hifi/avatarapp/SquareLabel.qml +++ b/interface/resources/qml/hifi/avatarapp/SquareLabel.qml @@ -1,5 +1,5 @@ -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import QtQuick 2.9 import QtGraphicalEffects 1.0 diff --git a/interface/resources/qml/hifi/avatarapp/Vector3.qml b/interface/resources/qml/hifi/avatarapp/Vector3.qml index d77665f992..698123104f 100644 --- a/interface/resources/qml/hifi/avatarapp/Vector3.qml +++ b/interface/resources/qml/hifi/avatarapp/Vector3.qml @@ -1,7 +1,7 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../controls" as HifiControls Row { diff --git a/interface/resources/qml/hifi/avatarapp/WhiteButton.qml b/interface/resources/qml/hifi/avatarapp/WhiteButton.qml index dc729ae097..d0a4a152db 100644 --- a/interface/resources/qml/hifi/avatarapp/WhiteButton.qml +++ b/interface/resources/qml/hifi/avatarapp/WhiteButton.qml @@ -1,6 +1,6 @@ import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit HifiControlsUit.Button { HifiConstants { diff --git a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml index b13f23f17d..ac6aa3d56c 100644 --- a/interface/resources/qml/hifi/commerce/checkout/Checkout.qml +++ b/interface/resources/qml/hifi/commerce/checkout/Checkout.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml index 9d9216c461..8cfea0bcd9 100644 --- a/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml +++ b/interface/resources/qml/hifi/commerce/common/CommerceLightbox.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml index 1b77dcd3e9..429f993817 100644 --- a/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml +++ b/interface/resources/qml/hifi/commerce/common/EmulatedMarketplaceHeader.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml index 5f874d3f04..6002747596 100644 --- a/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml +++ b/interface/resources/qml/hifi/commerce/common/FirstUseTutorial.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg index ce0d87363f..5632467c32 100644 Binary files a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg and b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-1.jpg differ diff --git a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg index 40bed974af..38ebf08162 100644 Binary files a/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg and b/interface/resources/qml/hifi/commerce/common/images/Purchase-First-Run-2.jpg differ diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml index 41eacd68d5..1eb8af31e6 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/ConnectionItem.qml @@ -16,8 +16,8 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../../../../styles-uit" -import "../../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../../controls" as HifiControls import "../../wallet" as HifiWallet diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml index 9293dc83ab..9e1a967d50 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/RecipientDisplay.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.6 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import "../../../../styles-uit" -import "../../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../../controls" as HifiControls import "../" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml index a515c8031f..f204d943fe 100644 --- a/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml +++ b/interface/resources/qml/hifi/commerce/common/sendAsset/SendAsset.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.6 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import "../../../../styles-uit" -import "../../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../../controls" as HifiControls import "../" as HifiCommerceCommon import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. @@ -39,6 +39,7 @@ Item { property string sendingPubliclyEffectImage; property var http; property var listModelName; + property var keyboardContainer: nil; // This object is always used in a popup or full-screen Wallet section. // This MouseArea is used to prevent a user from being @@ -1125,8 +1126,7 @@ Item { checked: Settings.getValue("sendAssetsNearbyPublicly", true); text: "Show Effect" // Anchors - anchors.top: messageContainer.bottom; - anchors.topMargin: 16; + anchors.verticalCenter: bottomBarContainer.verticalCenter; anchors.left: parent.left; anchors.leftMargin: 20; width: 130; @@ -1168,6 +1168,9 @@ Item { lightboxPopup.visible = false; } lightboxPopup.visible = true; + if (keyboardContainer) { + keyboardContainer.keyboardRaised = false; + } } } } @@ -1178,8 +1181,8 @@ Item { anchors.leftMargin: 20; anchors.right: parent.right; anchors.rightMargin: 20; - anchors.bottom: parent.bottom; - anchors.bottomMargin: 20; + anchors.top: messageContainer.bottom; + anchors.topMargin: 20; height: 60; // "CANCEL" button @@ -1187,11 +1190,11 @@ Item { id: cancelButton_sendAssetStep; color: root.assetName === "" ? hifi.buttons.noneBorderlessWhite : hifi.buttons.noneBorderlessGray; colorScheme: hifi.colorSchemes.dark; - anchors.left: parent.left; - anchors.leftMargin: 24; + anchors.right: sendButton.left; + anchors.rightMargin: 24; anchors.verticalCenter: parent.verticalCenter; height: 40; - width: 150; + width: 100; text: "CANCEL"; onClicked: { resetSendAssetData(); @@ -1205,10 +1208,10 @@ Item { color: hifi.buttons.blue; colorScheme: root.assetName === "" ? hifi.colorSchemes.dark : hifi.colorSchemes.light; anchors.right: parent.right; - anchors.rightMargin: 24; + anchors.rightMargin: 0; anchors.verticalCenter: parent.verticalCenter; height: 40; - width: 150; + width: 100; text: "SUBMIT"; onClicked: { if (root.assetName === "" && parseInt(amountTextField.text) > parseInt(balanceText.text)) { diff --git a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml index d24344b40a..7721dc3142 100644 --- a/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml +++ b/interface/resources/qml/hifi/commerce/inspectionCertificate/InspectionCertificate.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet diff --git a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml index 89b1dd3915..fecc8d5fee 100644 --- a/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml +++ b/interface/resources/qml/hifi/commerce/marketplaceItemTester/MarketplaceItemTester.qml @@ -77,7 +77,7 @@ Rectangle { // // TITLE BAR END // - + Rectangle { id: spinner z: 999 @@ -303,6 +303,6 @@ Rectangle { itemType: entityType, itemId: resourceObjectId }); } - + signal sendToScript(var message) } diff --git a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml index eeb9ac3c54..9d2df1a865 100644 --- a/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml +++ b/interface/resources/qml/hifi/commerce/purchases/PurchasedItem.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../wallet" as HifiWallet import TabletScriptingInterface 1.0 diff --git a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml index 2435678e77..8b7ebcf768 100644 --- a/interface/resources/qml/hifi/commerce/purchases/Purchases.qml +++ b/interface/resources/qml/hifi/commerce/purchases/Purchases.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. import "../wallet" as HifiWallet @@ -158,6 +158,7 @@ Rectangle { listModelName: "Gift Connections"; z: 998; visible: root.activeView === "giftAsset"; + keyboardContainer: root; anchors.fill: parent; parentAppTitleBarHeight: 70; parentAppNavBarHeight: 0; @@ -585,7 +586,7 @@ Rectangle { visible: purchasesModel.count !== 0; clip: true; model: purchasesModel; - snapMode: ListView.SnapToItem; + snapMode: ListView.NoSnap; // Anchors anchors.top: separator.bottom; anchors.left: parent.left; diff --git a/interface/resources/qml/hifi/commerce/wallet/Help.qml b/interface/resources/qml/hifi/commerce/wallet/Help.qml index 6d8fc3c33f..24ca5407b2 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Help.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Help.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml index eadf1ca8a2..b1fbb91c80 100644 --- a/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml +++ b/interface/resources/qml/hifi/commerce/wallet/NeedsLogIn.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml index 8451c90836..6ddfe0da1c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseChange.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml index c4abd40d2a..86d50e87ec 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseModal.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml index e052b78876..179ffcf707 100644 --- a/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/PassphraseSelection.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/Security.qml b/interface/resources/qml/hifi/commerce/wallet/Security.qml index 14ac696ef7..f0b1ecd4e0 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Security.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Security.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml index 01df18352b..da0d0d59d5 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageChange.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml index 599c6a1851..82933eebcb 100644 --- a/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml +++ b/interface/resources/qml/hifi/commerce/wallet/SecurityImageSelection.qml @@ -13,8 +13,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls // references XXX from root context diff --git a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml index 588b80c435..0cca581c4f 100644 --- a/interface/resources/qml/hifi/commerce/wallet/Wallet.qml +++ b/interface/resources/qml/hifi/commerce/wallet/Wallet.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon import "../common/sendAsset" @@ -354,6 +354,7 @@ Rectangle { listModelName: "Send Money Connections"; z: 997; visible: root.activeView === "sendMoney"; + keyboardContainer: root; anchors.fill: parent; parentAppTitleBarHeight: titleBarContainer.height; parentAppNavBarHeight: tabButtonsContainer.height; diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml b/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml index 19065ee542..e7163a3641 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletChoice.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import "../common" as HifiCommerceCommon -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit Item { diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 627da1d43f..1e78027f91 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -15,8 +15,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 import QtQuick.Controls 2.2 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "qrc:////qml//hifi//models" as HifiModels // Absolute path so the same code works everywhere. diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml index dc6ce45a74..b793075843 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletSetup.qml @@ -14,8 +14,8 @@ import Hifi 1.0 as Hifi import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../../styles-uit" -import "../../../controls-uit" as HifiControlsUit +import stylesUit 1.0 +import controlsUit 1.0 as HifiControlsUit import "../../../controls" as HifiControls import "../common" as HifiCommerceCommon diff --git a/interface/resources/qml/hifi/dialogs/AboutDialog.qml b/interface/resources/qml/hifi/dialogs/AboutDialog.qml index b8e6e89aec..3d5d1a94a3 100644 --- a/interface/resources/qml/hifi/dialogs/AboutDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AboutDialog.qml @@ -10,7 +10,7 @@ import QtQuick 2.8 -import "../../styles-uit" +import stylesUit 1.0 import "../../windows" ScrollingWindow { diff --git a/interface/resources/qml/hifi/dialogs/RunningScripts.qml b/interface/resources/qml/hifi/dialogs/RunningScripts.qml index 9a180a66f6..be17e65ab3 100644 --- a/interface/resources/qml/hifi/dialogs/RunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/RunningScripts.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" import "../" diff --git a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml index 579aa1cb1e..d26bf81e57 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAboutDialog.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../../styles-uit" +import stylesUit 1.0 Rectangle { width: 480 diff --git a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml index 0eeb252049..f665032b01 100644 --- a/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml +++ b/interface/resources/qml/hifi/dialogs/TabletAssetServer.qml @@ -14,8 +14,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" import ".." diff --git a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml index afe06897df..763f56b92b 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDCDialog.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml index 50df4dedbc..213dca8b48 100644 --- a/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml +++ b/interface/resources/qml/hifi/dialogs/TabletDebugWindow.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import Hifi 1.0 as Hifi -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Rectangle { id: root diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml index 24798af21a..4cfc99e0eb 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatistics.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml index d5c5a5ee02..e86dfd7554 100644 --- a/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml +++ b/interface/resources/qml/hifi/dialogs/TabletEntityStatisticsItem.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Column { id: root diff --git a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml index ab53f03477..bb3d668850 100644 --- a/interface/resources/qml/hifi/dialogs/TabletLODTools.qml +++ b/interface/resources/qml/hifi/dialogs/TabletLODTools.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" Rectangle { diff --git a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml index 018c8f5737..6cd220307d 100644 --- a/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml +++ b/interface/resources/qml/hifi/dialogs/TabletRunningScripts.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" import "../" diff --git a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml index ce1abc6154..b1aa8e5c45 100644 --- a/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml +++ b/interface/resources/qml/hifi/dialogs/content/ModelBrowserContent.qml @@ -1,7 +1,7 @@ import QtQuick 2.7 import QtQuick.Controls 2.3 -import "../../../controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls Column { width: pane.contentWidth diff --git a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml index e3115a5738..6b2aa331e8 100644 --- a/interface/resources/qml/hifi/tablet/CalibratingScreen.qml +++ b/interface/resources/qml/hifi/tablet/CalibratingScreen.qml @@ -10,9 +10,9 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../styles-uit" +import stylesUit 1.0 import "../../controls" -import "../../controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls Rectangle { diff --git a/interface/resources/qml/hifi/tablet/ControllerSettings.qml b/interface/resources/qml/hifi/tablet/ControllerSettings.qml index 6706830537..b8bbd71f33 100644 --- a/interface/resources/qml/hifi/tablet/ControllerSettings.qml +++ b/interface/resources/qml/hifi/tablet/ControllerSettings.qml @@ -11,9 +11,9 @@ import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 import Qt.labs.settings 1.0 -import "../../styles-uit" +import stylesUit 1.0 import "../../controls" -import "../../controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls import "../../dialogs" import "../../dialogs/preferences" import "tabletWindows" diff --git a/interface/resources/qml/hifi/tablet/EditEntityList.qml b/interface/resources/qml/hifi/tablet/EditEntityList.qml index d484885103..d2fb99ea0a 100644 --- a/interface/resources/qml/hifi/tablet/EditEntityList.qml +++ b/interface/resources/qml/hifi/tablet/EditEntityList.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 WebView { diff --git a/interface/resources/qml/hifi/tablet/EditTabButton.qml b/interface/resources/qml/hifi/tablet/EditTabButton.qml index 13894f4d15..5fc4341eb8 100644 --- a/interface/resources/qml/hifi/tablet/EditTabButton.qml +++ b/interface/resources/qml/hifi/tablet/EditTabButton.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 TabButton { id: control diff --git a/interface/resources/qml/hifi/tablet/EditTabView.qml b/interface/resources/qml/hifi/tablet/EditTabView.qml index 4ac8755570..332fab6112 100644 --- a/interface/resources/qml/hifi/tablet/EditTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditTabView.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 TabBar { id: editTabView diff --git a/interface/resources/qml/hifi/tablet/EditToolsTabView.qml b/interface/resources/qml/hifi/tablet/EditToolsTabView.qml index 00084b8ca9..76078b4afd 100644 --- a/interface/resources/qml/hifi/tablet/EditToolsTabView.qml +++ b/interface/resources/qml/hifi/tablet/EditToolsTabView.qml @@ -4,8 +4,8 @@ import QtWebChannel 1.0 import "../../controls" import "../toolbars" import QtGraphicalEffects 1.0 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 TabBar { id: editTabView diff --git a/interface/resources/qml/hifi/tablet/InputRecorder.qml b/interface/resources/qml/hifi/tablet/InputRecorder.qml index 527a6cacb4..9b63a612a8 100644 --- a/interface/resources/qml/hifi/tablet/InputRecorder.qml +++ b/interface/resources/qml/hifi/tablet/InputRecorder.qml @@ -9,8 +9,8 @@ import QtQuick 2.5 import Hifi 1.0 -import "../../styles-uit" -import "../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../../windows" import "../../dialogs" diff --git a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml index 526a42f8e2..dde372648b 100644 --- a/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewMaterialDialog.qml @@ -13,8 +13,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtQuick.Dialogs 1.2 as OriginalDialogs -import "../../styles-uit" -import "../../controls-uit" +import stylesUit 1.0 +import controlsUit 1.0 import "../dialogs" Rectangle { diff --git a/interface/resources/qml/hifi/tablet/NewModelDialog.qml b/interface/resources/qml/hifi/tablet/NewModelDialog.qml index 10b844c987..9540979479 100644 --- a/interface/resources/qml/hifi/tablet/NewModelDialog.qml +++ b/interface/resources/qml/hifi/tablet/NewModelDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import QtQuick.Dialogs 1.2 as OriginalDialogs -import "../../styles-uit" -import "../../controls-uit" +import stylesUit 1.0 +import controlsUit 1.0 import "../dialogs" Rectangle { @@ -116,9 +116,14 @@ Rectangle { Column { id: column2 width: 200 - height: 400 + height: 600 spacing: 10 + CheckBox { + id: grabbable + text: qsTr("Grabbable") + } + CheckBox { id: dynamic text: qsTr("Dynamic") @@ -217,9 +222,10 @@ Rectangle { newModelDialog.sendToScript({ method: "newModelDialogAdd", params: { - textInput: modelURL.text, - checkBox: dynamic.checked, - comboBox: collisionType.currentIndex + url: modelURL.text, + dynamic: dynamic.checked, + collisionShapeIndex: collisionType.currentIndex, + grabbable: grabbable.checked } }); } diff --git a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml index c2aff08e35..684d12c9b4 100644 --- a/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml +++ b/interface/resources/qml/hifi/tablet/OpenVrConfiguration.qml @@ -9,9 +9,9 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../../styles-uit" +import stylesUit 1.0 import "../../controls" -import "../../controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls import "." diff --git a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml index 3d518289fb..0f26ba20aa 100644 --- a/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletAddressDialog.qml @@ -18,8 +18,8 @@ import "../../styles" import "../../windows" import "../" import "../toolbars" -import "../../styles-uit" as HifiStyles -import "../../controls-uit" as HifiControls +import stylesUit 1.0 as HifiStyles +import controlsUit 1.0 as HifiControls import QtQuick.Controls 2.2 as QQC2 import QtQuick.Templates 2.2 as T diff --git a/interface/resources/qml/hifi/tablet/TabletHome.qml b/interface/resources/qml/hifi/tablet/TabletHome.qml index 1922b02f93..934ed91995 100644 --- a/interface/resources/qml/hifi/tablet/TabletHome.qml +++ b/interface/resources/qml/hifi/tablet/TabletHome.qml @@ -6,7 +6,7 @@ import QtQuick.Layouts 1.3 import TabletScriptingInterface 1.0 import "." -import "../../styles-uit" +import stylesUit 1.0 import "../audio" as HifiAudio Item { diff --git a/interface/resources/qml/hifi/tablet/TabletMenu.qml b/interface/resources/qml/hifi/tablet/TabletMenu.qml index 6540d53fca..267fb9f0cf 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenu.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenu.qml @@ -7,7 +7,7 @@ import QtWebEngine 1.1 import "." -import "../../styles-uit" +import stylesUit 1.0 import "../../controls" FocusScope { diff --git a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml index 74f175e049..25db90c771 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuItem.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuItem.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import "../../controls-uit" -import "../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Item { id: root diff --git a/interface/resources/qml/hifi/tablet/TabletMenuView.qml b/interface/resources/qml/hifi/tablet/TabletMenuView.qml index b632a17e57..73b0405984 100644 --- a/interface/resources/qml/hifi/tablet/TabletMenuView.qml +++ b/interface/resources/qml/hifi/tablet/TabletMenuView.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import TabletScriptingInterface 1.0 -import "../../styles-uit" +import stylesUit 1.0 import "." FocusScope { diff --git a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml index d69d760b95..ce4e641476 100644 --- a/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml +++ b/interface/resources/qml/hifi/tablet/TabletModelBrowserDialog.qml @@ -10,8 +10,8 @@ import QtQuick 2.5 -import "../../controls-uit" as HifiControls -import "../../styles-uit" +import controlsUit 1.0 as HifiControls +import stylesUit 1.0 import "../dialogs/content" Item { diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml index 871d1c92a9..8e91655dda 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletFileDialog.qml @@ -16,8 +16,8 @@ import QtQuick.Controls 1.4 as QQC1 import QtQuick.Controls 2.3 import ".." -import "../../../controls-uit" -import "../../../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 import "../../../windows" import "../../../dialogs/fileDialog" diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml index 3708f75114..57ca705352 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/TabletPreferencesDialog.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import "." import "./preferences" -import "../../../styles-uit" -import "../../../controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { id: dialog diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml index 6ac3f706e4..57fdeb482b 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/Section.qml @@ -12,8 +12,8 @@ import QtQuick 2.5 import Hifi 1.0 import "../../../../dialogs/preferences" -import "../../../../controls-uit" as HiFiControls -import "../../../../styles-uit" +import controlsUit 1.0 as HiFiControls +import stylesUit 1.0 import "." Preference { diff --git a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml index 8c0e934971..36b927f5f9 100644 --- a/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml +++ b/interface/resources/qml/hifi/tablet/tabletWindows/preferences/TabletBrowsablePreference.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "../../../../dialogs" -import "../../../../controls-uit" +import controlsUit 1.0 import "../" Preference { diff --git a/interface/resources/qml/styles-uit/+android/HifiConstants.qml b/interface/resources/qml/stylesUit/+android/HifiConstants.qml similarity index 100% rename from interface/resources/qml/styles-uit/+android/HifiConstants.qml rename to interface/resources/qml/stylesUit/+android/HifiConstants.qml diff --git a/interface/resources/qml/styles-uit/AnonymousProRegular.qml b/interface/resources/qml/stylesUit/AnonymousProRegular.qml similarity index 100% rename from interface/resources/qml/styles-uit/AnonymousProRegular.qml rename to interface/resources/qml/stylesUit/AnonymousProRegular.qml diff --git a/interface/resources/qml/styles-uit/ButtonLabel.qml b/interface/resources/qml/stylesUit/ButtonLabel.qml similarity index 100% rename from interface/resources/qml/styles-uit/ButtonLabel.qml rename to interface/resources/qml/stylesUit/ButtonLabel.qml diff --git a/interface/resources/qml/styles-uit/FiraSansRegular.qml b/interface/resources/qml/stylesUit/FiraSansRegular.qml similarity index 100% rename from interface/resources/qml/styles-uit/FiraSansRegular.qml rename to interface/resources/qml/stylesUit/FiraSansRegular.qml diff --git a/interface/resources/qml/styles-uit/FiraSansSemiBold.qml b/interface/resources/qml/stylesUit/FiraSansSemiBold.qml similarity index 100% rename from interface/resources/qml/styles-uit/FiraSansSemiBold.qml rename to interface/resources/qml/stylesUit/FiraSansSemiBold.qml diff --git a/interface/resources/qml/styles-uit/HiFiGlyphs.qml b/interface/resources/qml/stylesUit/HiFiGlyphs.qml similarity index 100% rename from interface/resources/qml/styles-uit/HiFiGlyphs.qml rename to interface/resources/qml/stylesUit/HiFiGlyphs.qml diff --git a/interface/resources/qml/styles-uit/HifiConstants.qml b/interface/resources/qml/stylesUit/HifiConstants.qml similarity index 100% rename from interface/resources/qml/styles-uit/HifiConstants.qml rename to interface/resources/qml/stylesUit/HifiConstants.qml diff --git a/interface/resources/qml/styles-uit/IconButton.qml b/interface/resources/qml/stylesUit/IconButton.qml similarity index 100% rename from interface/resources/qml/styles-uit/IconButton.qml rename to interface/resources/qml/stylesUit/IconButton.qml diff --git a/interface/resources/qml/styles-uit/InfoItem.qml b/interface/resources/qml/stylesUit/InfoItem.qml similarity index 100% rename from interface/resources/qml/styles-uit/InfoItem.qml rename to interface/resources/qml/stylesUit/InfoItem.qml diff --git a/interface/resources/qml/styles-uit/InputLabel.qml b/interface/resources/qml/stylesUit/InputLabel.qml similarity index 100% rename from interface/resources/qml/styles-uit/InputLabel.qml rename to interface/resources/qml/stylesUit/InputLabel.qml diff --git a/interface/resources/qml/styles-uit/ListItem.qml b/interface/resources/qml/stylesUit/ListItem.qml similarity index 100% rename from interface/resources/qml/styles-uit/ListItem.qml rename to interface/resources/qml/stylesUit/ListItem.qml diff --git a/interface/resources/qml/styles-uit/Logs.qml b/interface/resources/qml/stylesUit/Logs.qml similarity index 100% rename from interface/resources/qml/styles-uit/Logs.qml rename to interface/resources/qml/stylesUit/Logs.qml diff --git a/interface/resources/qml/styles-uit/OverlayTitle.qml b/interface/resources/qml/stylesUit/OverlayTitle.qml similarity index 100% rename from interface/resources/qml/styles-uit/OverlayTitle.qml rename to interface/resources/qml/stylesUit/OverlayTitle.qml diff --git a/interface/resources/qml/styles-uit/RalewayBold.qml b/interface/resources/qml/stylesUit/RalewayBold.qml similarity index 100% rename from interface/resources/qml/styles-uit/RalewayBold.qml rename to interface/resources/qml/stylesUit/RalewayBold.qml diff --git a/interface/resources/qml/styles-uit/RalewayLight.qml b/interface/resources/qml/stylesUit/RalewayLight.qml similarity index 100% rename from interface/resources/qml/styles-uit/RalewayLight.qml rename to interface/resources/qml/stylesUit/RalewayLight.qml diff --git a/interface/resources/qml/styles-uit/RalewayRegular.qml b/interface/resources/qml/stylesUit/RalewayRegular.qml similarity index 100% rename from interface/resources/qml/styles-uit/RalewayRegular.qml rename to interface/resources/qml/stylesUit/RalewayRegular.qml diff --git a/interface/resources/qml/styles-uit/RalewaySemiBold.qml b/interface/resources/qml/stylesUit/RalewaySemiBold.qml similarity index 100% rename from interface/resources/qml/styles-uit/RalewaySemiBold.qml rename to interface/resources/qml/stylesUit/RalewaySemiBold.qml diff --git a/interface/resources/qml/styles-uit/SectionName.qml b/interface/resources/qml/stylesUit/SectionName.qml similarity index 100% rename from interface/resources/qml/styles-uit/SectionName.qml rename to interface/resources/qml/stylesUit/SectionName.qml diff --git a/interface/resources/qml/styles-uit/Separator.qml b/interface/resources/qml/stylesUit/Separator.qml similarity index 97% rename from interface/resources/qml/styles-uit/Separator.qml rename to interface/resources/qml/stylesUit/Separator.qml index 4134b928a7..d9f11e192c 100644 --- a/interface/resources/qml/styles-uit/Separator.qml +++ b/interface/resources/qml/stylesUit/Separator.qml @@ -9,7 +9,7 @@ // import QtQuick 2.5 -import "../styles-uit" +import "." Item { // Size diff --git a/interface/resources/qml/styles-uit/ShortcutText.qml b/interface/resources/qml/stylesUit/ShortcutText.qml similarity index 100% rename from interface/resources/qml/styles-uit/ShortcutText.qml rename to interface/resources/qml/stylesUit/ShortcutText.qml diff --git a/interface/resources/qml/styles-uit/TabName.qml b/interface/resources/qml/stylesUit/TabName.qml similarity index 100% rename from interface/resources/qml/styles-uit/TabName.qml rename to interface/resources/qml/stylesUit/TabName.qml diff --git a/interface/resources/qml/styles-uit/TextFieldInput.qml b/interface/resources/qml/stylesUit/TextFieldInput.qml similarity index 100% rename from interface/resources/qml/styles-uit/TextFieldInput.qml rename to interface/resources/qml/stylesUit/TextFieldInput.qml diff --git a/interface/resources/qml/styles-uit/qmldir b/interface/resources/qml/stylesUit/qmldir similarity index 100% rename from interface/resources/qml/styles-uit/qmldir rename to interface/resources/qml/stylesUit/qmldir diff --git a/interface/resources/qml/windows/Decoration.qml b/interface/resources/qml/windows/Decoration.qml index f8fd9f4e6c..efaea6be8a 100644 --- a/interface/resources/qml/windows/Decoration.qml +++ b/interface/resources/qml/windows/Decoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" +import stylesUit 1.0 Rectangle { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/DefaultFrame.qml b/interface/resources/qml/windows/DefaultFrame.qml index 60e744bec3..5a366e367b 100644 --- a/interface/resources/qml/windows/DefaultFrame.qml +++ b/interface/resources/qml/windows/DefaultFrame.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import "." -import "../styles-uit" +import stylesUit 1.0 Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/DefaultFrameDecoration.qml b/interface/resources/qml/windows/DefaultFrameDecoration.qml index 1ddd83976e..fb0dd55985 100644 --- a/interface/resources/qml/windows/DefaultFrameDecoration.qml +++ b/interface/resources/qml/windows/DefaultFrameDecoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" +import stylesUit 1.0 Decoration { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/Fadable.qml b/interface/resources/qml/windows/Fadable.qml index 406c6be556..6d88fb067a 100644 --- a/interface/resources/qml/windows/Fadable.qml +++ b/interface/resources/qml/windows/Fadable.qml @@ -10,7 +10,7 @@ import QtQuick 2.5 -import "../styles-uit" +import stylesUit 1.0 // Enable window visibility transitions FocusScope { diff --git a/interface/resources/qml/windows/Frame.qml b/interface/resources/qml/windows/Frame.qml index 271d4f2e07..7b0fbf8d8c 100644 --- a/interface/resources/qml/windows/Frame.qml +++ b/interface/resources/qml/windows/Frame.qml @@ -11,7 +11,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 -import "../styles-uit" +import stylesUit 1.0 import "../js/Utils.js" as Utils Item { diff --git a/interface/resources/qml/windows/ModalFrame.qml b/interface/resources/qml/windows/ModalFrame.qml index cb23ccd5ad..ae149224e3 100644 --- a/interface/resources/qml/windows/ModalFrame.qml +++ b/interface/resources/qml/windows/ModalFrame.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import "." -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/ScrollingWindow.qml b/interface/resources/qml/windows/ScrollingWindow.qml index c156b80388..4cab96701e 100644 --- a/interface/resources/qml/windows/ScrollingWindow.qml +++ b/interface/resources/qml/windows/ScrollingWindow.qml @@ -14,8 +14,8 @@ import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" -import "../controls-uit" as HiFiControls +import stylesUit 1.0 +import controlsUit 1.0 as HiFiControls // FIXME how do I set the initial position of a window without // overriding places where the a individual client of the window diff --git a/interface/resources/qml/windows/TabletModalFrame.qml b/interface/resources/qml/windows/TabletModalFrame.qml index 550eec8357..1e9310eb5a 100644 --- a/interface/resources/qml/windows/TabletModalFrame.qml +++ b/interface/resources/qml/windows/TabletModalFrame.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import "." -import "../controls-uit" -import "../styles-uit" +import controlsUit 1.0 +import stylesUit 1.0 Rectangle { diff --git a/interface/resources/qml/windows/ToolFrame.qml b/interface/resources/qml/windows/ToolFrame.qml index 20c86afb5e..bb2bada498 100644 --- a/interface/resources/qml/windows/ToolFrame.qml +++ b/interface/resources/qml/windows/ToolFrame.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" +import stylesUit 1.0 Frame { HifiConstants { id: hifi } diff --git a/interface/resources/qml/windows/ToolFrameDecoration.qml b/interface/resources/qml/windows/ToolFrameDecoration.qml index ba36a2a38c..4f149037b3 100644 --- a/interface/resources/qml/windows/ToolFrameDecoration.qml +++ b/interface/resources/qml/windows/ToolFrameDecoration.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" +import stylesUit 1.0 Decoration { id: root diff --git a/interface/resources/qml/windows/Window.qml b/interface/resources/qml/windows/Window.qml index 835967c628..9f180af55d 100644 --- a/interface/resources/qml/windows/Window.qml +++ b/interface/resources/qml/windows/Window.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtGraphicalEffects 1.0 import "." -import "../styles-uit" +import stylesUit 1.0 // FIXME how do I set the initial position of a window without // overriding places where the a individual client of the window diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4c580d7de7..242445b0fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3537,6 +3537,7 @@ void Application::setIsInterstitialMode(bool interstitialMode) { if (enableInterstitial) { if (_interstitialMode != interstitialMode) { _interstitialMode = interstitialMode; + emit interstitialModeChanged(_interstitialMode); DependencyManager::get()->setAudioPaused(_interstitialMode); DependencyManager::get()->setMyAvatarDataPacketsPaused(_interstitialMode); @@ -8480,6 +8481,16 @@ QUuid Application::getTabletFrameID() const { return HMD->getCurrentTabletFrameID(); } +QVector Application::getTabletIDs() const { + // Most important overlays first. + QVector result; + auto HMD = DependencyManager::get(); + result << HMD->getCurrentTabletScreenID(); + result << HMD->getCurrentHomeButtonID(); + result << HMD->getCurrentTabletFrameID(); + return result; +} + void Application::setAvatarOverrideUrl(const QUrl& url, bool save) { _avatarOverrideUrl = url; _saveAvatarOverrideUrl = save; diff --git a/interface/src/Application.h b/interface/src/Application.h index d9f9591086..c3896a64e4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -52,7 +52,6 @@ #include #include "avatar/MyAvatar.h" -#include "BandwidthRecorder.h" #include "FancyCamera.h" #include "ConnectionMonitor.h" #include "CursorManager.h" @@ -298,6 +297,7 @@ public: OverlayID getTabletScreenID() const; OverlayID getTabletHomeButtonID() const; QUuid getTabletFrameID() const; // may be an entity or an overlay + QVector getTabletIDs() const; // In order of most important IDs first. void setAvatarOverrideUrl(const QUrl& url, bool save); void clearAvatarOverrideUrl() { _avatarOverrideUrl = QUrl(); _saveAvatarOverrideUrl = false; } @@ -334,6 +334,8 @@ signals: void uploadRequest(QString path); + void interstitialModeChanged(bool isInInterstitialMode); + void loginDialogPoppedUp(); public slots: diff --git a/interface/src/AvatarBookmarks.cpp b/interface/src/AvatarBookmarks.cpp index 5c79bedc9a..ce21c68c3d 100644 --- a/interface/src/AvatarBookmarks.cpp +++ b/interface/src/AvatarBookmarks.cpp @@ -78,8 +78,10 @@ void addAvatarEntities(const QVariantList& avatarEntities) { } entity->setLastBroadcast(usecTimestampNow()); - // since we're creating this object we will immediately volunteer to own its simulation - entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY); + if (entityProperties.getDynamic()) { + // since we're creating a dynamic object we volunteer immediately to own its simulation + entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY); + } entityProperties.setLastEdited(entity->getLastEdited()); } else { qCDebug(entities) << "AvatarEntitiesBookmark failed to add new Entity to local Octree"; @@ -108,6 +110,9 @@ AvatarBookmarks::AvatarBookmarks() { if (!QFile::copy(defaultBookmarksFilename, _bookmarksFilename)) { qDebug() << "failed to copy" << defaultBookmarksFilename << "to" << _bookmarksFilename; + } else { + QFile bookmarksFile(_bookmarksFilename); + bookmarksFile.setPermissions(bookmarksFile.permissions() | QFile::WriteUser); } } readFromFile(); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index d31b201dc7..c9b3449cec 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -55,15 +55,7 @@ static const quint64 MIN_TIME_BETWEEN_MY_AVATAR_DATA_SENDS = USECS_PER_SECOND / // We add _myAvatar into the hash with all the other AvatarData, and we use the default NULL QUid as the key. const QUuid MY_AVATAR_KEY; // NULL key -namespace { - // For an unknown avatar-data packet, wait this long before requesting the identity. - constexpr std::chrono::milliseconds REQUEST_UNKNOWN_IDENTITY_DELAY { 5 * 1000 }; - constexpr int REQUEST_UNKNOWN_IDENTITY_TRANSMITS = 3; -} -using std::chrono::steady_clock; - AvatarManager::AvatarManager(QObject* parent) : - _avatarsToFade(), _myAvatar(new MyAvatar(qApp->thread()), [](MyAvatar* ptr) { ptr->deleteLater(); }) { // register a meta type for the weak pointer we'll use for the owning avatar mixer for each avatar @@ -322,28 +314,6 @@ void AvatarManager::updateOtherAvatars(float deltaTime) { simulateAvatarFades(deltaTime); - // Check on avatars with pending identities: - steady_clock::time_point now = steady_clock::now(); - QWriteLocker writeLock(&_hashLock); - for (auto pendingAvatar = _pendingAvatars.begin(); pendingAvatar != _pendingAvatars.end(); ++pendingAvatar) { - if (now - pendingAvatar->creationTime >= REQUEST_UNKNOWN_IDENTITY_DELAY) { - // Too long without an ID - sendIdentityRequest(pendingAvatar->avatar->getID()); - if (++pendingAvatar->transmits >= REQUEST_UNKNOWN_IDENTITY_TRANSMITS) { - qCDebug(avatars) << "Requesting identity for unknown avatar (final request)" << - pendingAvatar->avatar->getID().toString(); - - pendingAvatar = _pendingAvatars.erase(pendingAvatar); - if (pendingAvatar == _pendingAvatars.end()) { - break; - } - } else { - pendingAvatar->creationTime = now; - qCDebug(avatars) << "Requesting identity for unknown avatar" << pendingAvatar->avatar->getID().toString(); - } - } - } - _avatarSimulationTime = (float)(usecTimestampNow() - startTime) / (float)USECS_PER_MSEC; } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 209b976c44..34aa4f2cc0 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -55,6 +55,7 @@ using SortedAvatar = std::pair>; * @borrows AvatarList.sessionUUIDChanged as sessionUUIDChanged * @borrows AvatarList.processAvatarDataPacket as processAvatarDataPacket * @borrows AvatarList.processAvatarIdentityPacket as processAvatarIdentityPacket + * @borrows AvatarList.processBulkAvatarTraits as processBulkAvatarTraits * @borrows AvatarList.processKillAvatar as processKillAvatar */ @@ -152,6 +153,13 @@ public: const QVector& avatarsToInclude, const QVector& avatarsToDiscard); + /**jsdoc + * @function AvatarManager.findParabolaIntersectionVector + * @param {PickParabola} pick + * @param {Uuid[]} avatarsToInclude + * @param {Uuid[]} avatarsToDiscard + * @returns {ParabolaToAvatarIntersectionResult} + */ Q_INVOKABLE ParabolaToAvatarIntersectionResult findParabolaIntersectionVector(const PickParabola& pick, const QVector& avatarsToInclude, const QVector& avatarsToDiscard); @@ -176,7 +184,7 @@ public: * than iterating over each avatar and obtaining data about them in JavaScript, as that method * locks and unlocks each avatar's data structure potentially hundreds of times per update tick. * @function AvatarManager.getPalData - * @param {string[]} specificAvatarIdentifiers - A list of specific Avatar Identifiers about + * @param {string[]} [specificAvatarIdentifiers] - A list of specific Avatar Identifiers about * which you want to get PAL data * @returns {object} */ diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c61b424bce..a7c8c3e179 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -122,7 +122,6 @@ MyAvatar::MyAvatar(QThread* thread) : _goToOrientation(), _prevShouldDrawHead(true), _audioListenerMode(FROM_HEAD), - _hmdAtRestDetector(glm::vec3(0), glm::quat()), _dominantHandSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "dominantHand", DOMINANT_RIGHT_HAND), _headPitchSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "", 0.0f), _scaleSetting(QStringList() << AVATAR_SETTINGS_GROUP_NAME << "scale", _targetScale), @@ -702,6 +701,46 @@ void MyAvatar::simulate(float deltaTime) { // before we perform rig animations and IK. updateSensorToWorldMatrix(); + // if we detect the hand controller is at rest, i.e. lying on the table, or the hand is too far away from the hmd + // disable the associated hand controller input. + { + // NOTE: all poses are in sensor space. + auto leftHandIter = _controllerPoseMap.find(controller::Action::LEFT_HAND); + if (leftHandIter != _controllerPoseMap.end() && leftHandIter->second.isValid()) { + _leftHandAtRestDetector.update(leftHandIter->second.getTranslation(), leftHandIter->second.getRotation()); + if (_leftHandAtRestDetector.isAtRest()) { + leftHandIter->second.valid = false; + } + } else { + _leftHandAtRestDetector.invalidate(); + } + + auto rightHandIter = _controllerPoseMap.find(controller::Action::RIGHT_HAND); + if (rightHandIter != _controllerPoseMap.end() && rightHandIter->second.isValid()) { + _rightHandAtRestDetector.update(rightHandIter->second.getTranslation(), rightHandIter->second.getRotation()); + if (_rightHandAtRestDetector.isAtRest()) { + rightHandIter->second.valid = false; + } + } else { + _rightHandAtRestDetector.invalidate(); + } + + auto headIter = _controllerPoseMap.find(controller::Action::HEAD); + + // The 99th percentile man has a spine to fingertip to height ratio of 0.45. Lets increase that by about 10% to 0.5 + // then measure the distance the center of the eyes to the finger tips. To come up with this ratio. + // From "The Measure of Man and Woman: Human Factors in Design, Revised Edition" by Alvin R. Tilley, Henry Dreyfuss Associates + const float MAX_HEAD_TO_HAND_DISTANCE_RATIO = 0.52f; + + float maxHeadHandDistance = getUserHeight() * MAX_HEAD_TO_HAND_DISTANCE_RATIO; + if (glm::length(headIter->second.getTranslation() - leftHandIter->second.getTranslation()) > maxHeadHandDistance) { + leftHandIter->second.valid = false; + } + if (glm::length(headIter->second.getTranslation() - rightHandIter->second.getTranslation()) > maxHeadHandDistance) { + rightHandIter->second.valid = false; + } + } + { PerformanceTimer perfTimer("skeleton"); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 16b765711a..08a7c09fa4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -629,8 +629,6 @@ public: const MyHead* getMyHead() const; - Q_INVOKABLE void toggleSmoothPoleVectors() { _skeletonModel->getRig().toggleSmoothPoleVectors(); }; - /**jsdoc * Get the current position of the avatar's "Head" joint. * @function MyAvatar.getHeadPosition @@ -951,50 +949,72 @@ public: void removeWearableAvatarEntities(); /**jsdoc + * Check whether your avatar is flying or not. * @function MyAvatar.isFlying - * @returns {boolean} + * @returns {boolean} true if your avatar is flying and not taking off or falling, otherwise + * false. */ Q_INVOKABLE bool isFlying(); /**jsdoc + * Check whether your avatar is in the air or not. * @function MyAvatar.isInAir - * @returns {boolean} + * @returns {boolean} true if your avatar is taking off, flying, or falling, otherwise false + * because your avatar is on the ground. */ Q_INVOKABLE bool isInAir(); /**jsdoc + * Set your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends + * on whether the domain you're in allows you to fly. * @function MyAvatar.setFlyingEnabled - * @param {boolean} enabled + * @param {boolean} enabled - Set true if you want to enable flying in your current desktop or HMD display + * mode, otherwise set false. */ Q_INVOKABLE void setFlyingEnabled(bool enabled); /**jsdoc + * Get your preference for flying in your current desktop or HMD display mode. Note that your ability to fly also depends + * on whether the domain you're in allows you to fly. * @function MyAvatar.getFlyingEnabled - * @returns {boolean} + * @returns {boolean} true if your preference is to enable flying in your current desktop or HMD display mode, + * otherwise false. */ Q_INVOKABLE bool getFlyingEnabled(); /**jsdoc + * Set your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain + * you're in allows you to fly. * @function MyAvatar.setFlyingDesktopPref - * @param {boolean} enabled + * @param {boolean} enabled - Set true if you want to enable flying in desktop display mode, otherwise set + * false. */ Q_INVOKABLE void setFlyingDesktopPref(bool enabled); /**jsdoc + * Get your preference for flying in desktop display mode. Note that your ability to fly also depends on whether the domain + * you're in allows you to fly. * @function MyAvatar.getFlyingDesktopPref - * @returns {boolean} + * @returns {boolean} true if your preference is to enable flying in desktop display mode, otherwise + * false. */ Q_INVOKABLE bool getFlyingDesktopPref(); /**jsdoc - * @function MyAvatar.setFlyingDesktopPref - * @param {boolean} enabled + * Set your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain + * you're in allows you to fly. + * @function MyAvatar.setFlyingHMDPref + * @param {boolean} enabled - Set true if you want to enable flying in HMD display mode, otherwise set + * false. */ Q_INVOKABLE void setFlyingHMDPref(bool enabled); /**jsdoc - * @function MyAvatar.getFlyingDesktopPref - * @returns {boolean} + * Get your preference for flying in HMD display mode. Note that your ability to fly also depends on whether the domain + * you're in allows you to fly. + * @function MyAvatar.getFlyingHMDPref + * @returns {boolean} true if your preference is to enable flying in HMD display mode, otherwise + * false. */ Q_INVOKABLE bool getFlyingHMDPref(); @@ -1766,8 +1786,8 @@ private: glm::vec3 _customListenPosition; glm::quat _customListenOrientation; - AtRestDetector _hmdAtRestDetector; - bool _lastIsMoving { false }; + AtRestDetector _leftHandAtRestDetector; + AtRestDetector _rightHandAtRestDetector; // all poses are in sensor-frame std::map _controllerPoseMap; diff --git a/interface/src/avatar/MySkeletonModel.cpp b/interface/src/avatar/MySkeletonModel.cpp index 3084542472..c1a49d7a10 100644 --- a/interface/src/avatar/MySkeletonModel.cpp +++ b/interface/src/avatar/MySkeletonModel.cpp @@ -46,7 +46,7 @@ static AnimPose computeHipsInSensorFrame(MyAvatar* myAvatar, bool isFlying) { } glm::mat4 hipsMat; - if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState())) { + if (myAvatar->getCenterOfGravityModelEnabled() && !isFlying && !(myAvatar->getIsInWalkingState()) && myAvatar->getHMDLeanRecenterEnabled()) { // then we use center of gravity model hipsMat = myAvatar->deriveBodyUsingCgModel(); } else { diff --git a/interface/src/octree/OctreePacketProcessor.cpp b/interface/src/octree/OctreePacketProcessor.cpp index 0d991fc9bc..5c8868abdb 100644 --- a/interface/src/octree/OctreePacketProcessor.cpp +++ b/interface/src/octree/OctreePacketProcessor.cpp @@ -91,7 +91,9 @@ void OctreePacketProcessor::processPacket(QSharedPointer messag return; // bail since piggyback version doesn't match } - qApp->trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket); + if (packetType != PacketType::EntityQueryInitialResultsComplete) { + qApp->trackIncomingOctreePacket(*message, sendingNode, wasStatsPacket); + } // seek back to beginning of packet after tracking message->seek(0); diff --git a/interface/src/raypick/CollisionPick.h b/interface/src/raypick/CollisionPick.h index 67e39e4d72..92aa415f9e 100644 --- a/interface/src/raypick/CollisionPick.h +++ b/interface/src/raypick/CollisionPick.h @@ -76,4 +76,4 @@ protected: bool _includeNormals; }; -#endif // hifi_CollisionPick_h \ No newline at end of file +#endif // hifi_CollisionPick_h diff --git a/interface/src/raypick/PathPointer.h b/interface/src/raypick/PathPointer.h index 385753a8e8..1aa4165c87 100644 --- a/interface/src/raypick/PathPointer.h +++ b/interface/src/raypick/PathPointer.h @@ -27,7 +27,7 @@ class StartEndRenderState { public: StartEndRenderState() {} StartEndRenderState(const OverlayID& startID, const OverlayID& endID); - virtual ~StartEndRenderState() {} + virtual ~StartEndRenderState() = default; const OverlayID& getStartID() const { return _startID; } const OverlayID& getEndID() const { return _endID; } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 75f17def20..0f3d859093 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -54,6 +54,9 @@ WindowScriptingInterface::WindowScriptingInterface() { }); connect(qApp->getWindow(), &MainWindow::windowGeometryChanged, this, &WindowScriptingInterface::onWindowGeometryChanged); + connect(qApp, &Application::interstitialModeChanged, [this] (bool interstitialMode) { + emit interstitialModeChanged(interstitialMode); + }); } WindowScriptingInterface::~WindowScriptingInterface() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index f6a5a5ef74..ef3dfcef4b 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -619,6 +619,14 @@ signals: */ void redirectErrorStateChanged(bool isInErrorState); + /**jsdoc + * Triggered when interstitial mode changes. + * @function Window.interstitialModeChanged + * @param {bool} interstitialMode - The mode of the interstitial is changed to. + * @returns {Signal} + */ + void interstitialModeChanged(bool interstitialMode); + /**jsdoc * Triggered when a still snapshot has been taken by calling {@link Window.takeSnapshot|takeSnapshot} with * includeAnimated = false or {@link Window.takeSecondaryCameraSnapshot|takeSecondaryCameraSnapshot}. diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e05c44c264..f4c98bb9e0 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -532,6 +532,8 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay bool visibleOnly, bool collidableOnly) { float bestDistance = std::numeric_limits::max(); bool bestIsFront = false; + bool bestIsTablet = false; + auto tabletIDs = qApp->getTabletIDs(); QMutexLocker locker(&_mutex); RayToOverlayIntersectionResult result; @@ -554,10 +556,11 @@ RayToOverlayIntersectionResult Overlays::findRayIntersectionVector(const PickRay if (thisOverlay->findRayIntersectionExtraInfo(ray.origin, ray.direction, thisDistance, thisFace, thisSurfaceNormal, thisExtraInfo, precisionPicking)) { bool isDrawInFront = thisOverlay->getDrawInFront(); - if ((bestIsFront && isDrawInFront && thisDistance < bestDistance) - || (!bestIsFront && (isDrawInFront || thisDistance < bestDistance))) { - + bool isTablet = tabletIDs.contains(thisID); + if ((isDrawInFront && !bestIsFront && !bestIsTablet) + || ((isTablet || isDrawInFront || !bestIsFront) && thisDistance < bestDistance)) { bestIsFront = isDrawInFront; + bestIsTablet = isTablet; bestDistance = thisDistance; result.intersects = true; result.distance = thisDistance; @@ -828,40 +831,12 @@ PointerEvent Overlays::calculateOverlayPointerEvent(OverlayID overlayID, PickRay } -RayToOverlayIntersectionResult Overlays::findRayIntersectionForMouseEvent(PickRay ray) { - QVector overlaysToInclude; - QVector overlaysToDiscard; - RayToOverlayIntersectionResult rayPickResult; - - // first priority is tablet screen - overlaysToInclude << qApp->getTabletScreenID(); - rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); - if (rayPickResult.intersects) { - return rayPickResult; - } - // then tablet home button - overlaysToInclude.clear(); - overlaysToInclude << qApp->getTabletHomeButtonID(); - rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); - if (rayPickResult.intersects) { - return rayPickResult; - } - // then tablet frame - overlaysToInclude.clear(); - overlaysToInclude << OverlayID(qApp->getTabletFrameID()); - rayPickResult = findRayIntersectionVector(ray, true, overlaysToInclude, overlaysToDiscard); - if (rayPickResult.intersects) { - return rayPickResult; - } - // then whatever - return findRayIntersection(ray); -} - bool Overlays::mousePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mousePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector(), + QVector()); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -901,7 +876,8 @@ bool Overlays::mouseDoublePressEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseDoublePressEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector(), + QVector()); if (rayPickResult.intersects) { _currentClickingOnOverlayID = rayPickResult.overlayID; @@ -964,7 +940,8 @@ bool Overlays::mouseReleaseEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseReleaseEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector(), + QVector()); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Release); mouseReleasePointerEvent(rayPickResult.overlayID, pointerEvent); @@ -993,7 +970,8 @@ bool Overlays::mouseMoveEvent(QMouseEvent* event) { PerformanceTimer perfTimer("Overlays::mouseMoveEvent"); PickRay ray = qApp->computePickRay(event->x(), event->y()); - RayToOverlayIntersectionResult rayPickResult = findRayIntersectionForMouseEvent(ray); + RayToOverlayIntersectionResult rayPickResult = findRayIntersectionVector(ray, true, QVector(), + QVector()); if (rayPickResult.intersects) { auto pointerEvent = calculateOverlayPointerEvent(rayPickResult.overlayID, ray, rayPickResult, event, PointerEvent::Move); mouseMovePointerEvent(rayPickResult.overlayID, pointerEvent); diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 21b9e93648..208fc8d78d 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -44,8 +44,7 @@ void OverlayPropertyResultFromScriptValue(const QScriptValue& object, OverlayPro const OverlayID UNKNOWN_OVERLAY_ID = OverlayID(); /**jsdoc - * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection} or - * {@link Overlays.findRayIntersectionVector|findRayIntersectionVector}. + * The result of a {@link PickRay} search using {@link Overlays.findRayIntersection|findRayIntersection}. * @typedef {object} Overlays.RayToOverlayIntersectionResult * @property {boolean} intersects - true if the {@link PickRay} intersected with a 3D overlay, otherwise * false. @@ -383,7 +382,11 @@ public slots: OverlayPropertyResult getOverlaysProperties(const QVariant& overlaysProperties); /**jsdoc - * Find the closest 3D overlay intersected by a {@link PickRay}. + * Find the closest 3D overlay intersected by a {@link PickRay}. Overlays with their drawInFront property set + * to true have priority over overlays that don't, except that tablet overlays have priority over any + * drawInFront overlays behind them. I.e., if a drawInFront overlay is behind one that isn't + * drawInFront, the drawInFront overlay is returned, but if a tablet overlay is in front of a + * drawInFront overlay, the tablet overlay is returned. * @function Overlays.findRayIntersection * @param {PickRay} pickRay - The PickRay to use for finding overlays. * @param {boolean} [precisionPicking=false] - Unused; exists to match Entity API. @@ -750,8 +753,6 @@ private: OverlayID _currentClickingOnOverlayID { UNKNOWN_OVERLAY_ID }; OverlayID _currentHoverOverOverlayID { UNKNOWN_OVERLAY_ID }; - RayToOverlayIntersectionResult findRayIntersectionForMouseEvent(PickRay ray); - private slots: void mousePressPointerEvent(const OverlayID& overlayID, const PointerEvent& event); void mouseMovePointerEvent(const OverlayID& overlayID, const PointerEvent& event); diff --git a/libraries/animation/src/AnimVariant.cpp b/libraries/animation/src/AnimVariant.cpp index fe43fd8855..cf7228b27b 100644 --- a/libraries/animation/src/AnimVariant.cpp +++ b/libraries/animation/src/AnimVariant.cpp @@ -169,7 +169,8 @@ std::map AnimVariantMap::toDebugMap() const { break; */ default: - assert(("invalid AnimVariant::Type", false)); + // invalid AnimVariant::Type + assert(false); } } return result; diff --git a/libraries/animation/src/AnimationCache.h b/libraries/animation/src/AnimationCache.h index ca5ea5b072..483350e2b5 100644 --- a/libraries/animation/src/AnimationCache.h +++ b/libraries/animation/src/AnimationCache.h @@ -22,7 +22,7 @@ class Animation; -typedef QSharedPointer AnimationPointer; +using AnimationPointer = QSharedPointer; class AnimationCache : public ResourceCache, public Dependency { Q_OBJECT diff --git a/libraries/animation/src/Rig.cpp b/libraries/animation/src/Rig.cpp index 91d4e0f9d3..341b554949 100644 --- a/libraries/animation/src/Rig.cpp +++ b/libraries/animation/src/Rig.cpp @@ -1253,7 +1253,6 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab const glm::mat4& rigToSensorMatrix, const glm::mat4& sensorToRigMatrix) { const bool ENABLE_POLE_VECTORS = true; - const float ELBOW_POLE_VECTOR_BLEND_FACTOR = 0.95f; if (leftHandEnabled) { @@ -1279,33 +1278,16 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab bool usePoleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, oppositeArmJointIndex, poleVector); if (usePoleVector) { glm::vec3 sensorPoleVector = transformVectorFast(rigToSensorMatrix, poleVector); - - if (_smoothPoleVectors) { - // smooth toward desired pole vector from previous pole vector... to reduce jitter - if (!_prevLeftHandPoleVectorValid) { - _prevLeftHandPoleVectorValid = true; - _prevLeftHandPoleVector = sensorPoleVector; - } - glm::quat deltaRot = rotationBetween(_prevLeftHandPoleVector, sensorPoleVector); - glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR); - _prevLeftHandPoleVector = smoothDeltaRot * _prevLeftHandPoleVector; - } else { - _prevLeftHandPoleVector = sensorPoleVector; - } _animVars.set("leftHandPoleVectorEnabled", true); _animVars.set("leftHandPoleReferenceVector", Vectors::UNIT_X); - _animVars.set("leftHandPoleVector", transformVectorFast(sensorToRigMatrix, _prevLeftHandPoleVector)); + _animVars.set("leftHandPoleVector", transformVectorFast(sensorToRigMatrix, sensorPoleVector)); } else { - _prevLeftHandPoleVectorValid = false; _animVars.set("leftHandPoleVectorEnabled", false); } - } else { - _prevLeftHandPoleVectorValid = false; _animVars.set("leftHandPoleVectorEnabled", false); } } else { - _prevLeftHandPoleVectorValid = false; _animVars.set("leftHandPoleVectorEnabled", false); _animVars.unset("leftHandPosition"); @@ -1344,33 +1326,16 @@ void Rig::updateHands(bool leftHandEnabled, bool rightHandEnabled, bool hipsEnab bool usePoleVector = calculateElbowPoleVector(handJointIndex, elbowJointIndex, armJointIndex, oppositeArmJointIndex, poleVector); if (usePoleVector) { glm::vec3 sensorPoleVector = transformVectorFast(rigToSensorMatrix, poleVector); - - if (_smoothPoleVectors) { - // smooth toward desired pole vector from previous pole vector... to reduce jitter - if (!_prevRightHandPoleVectorValid) { - _prevRightHandPoleVectorValid = true; - _prevRightHandPoleVector = sensorPoleVector; - } - glm::quat deltaRot = rotationBetween(_prevRightHandPoleVector, sensorPoleVector); - glm::quat smoothDeltaRot = safeMix(deltaRot, Quaternions::IDENTITY, ELBOW_POLE_VECTOR_BLEND_FACTOR); - _prevRightHandPoleVector = smoothDeltaRot * _prevRightHandPoleVector; - } else { - _prevRightHandPoleVector = sensorPoleVector; - } - _animVars.set("rightHandPoleVectorEnabled", true); _animVars.set("rightHandPoleReferenceVector", -Vectors::UNIT_X); - _animVars.set("rightHandPoleVector", transformVectorFast(sensorToRigMatrix, _prevRightHandPoleVector)); + _animVars.set("rightHandPoleVector", transformVectorFast(sensorToRigMatrix, sensorPoleVector)); } else { - _prevRightHandPoleVectorValid = false; _animVars.set("rightHandPoleVectorEnabled", false); } } else { - _prevRightHandPoleVectorValid = false; _animVars.set("rightHandPoleVectorEnabled", false); } } else { - _prevRightHandPoleVectorValid = false; _animVars.set("rightHandPoleVectorEnabled", false); _animVars.unset("rightHandPosition"); diff --git a/libraries/animation/src/Rig.h b/libraries/animation/src/Rig.h index 48f00d4e5d..ed0b70d4b6 100644 --- a/libraries/animation/src/Rig.h +++ b/libraries/animation/src/Rig.h @@ -227,7 +227,6 @@ public: const AnimVariantMap& getAnimVars() const { return _lastAnimVars; } const AnimContext::DebugStateMachineMap& getStateMachineMap() const { return _lastContext.getStateMachineMap(); } - void toggleSmoothPoleVectors() { _smoothPoleVectors = !_smoothPoleVectors; }; signals: void onLoadComplete(); @@ -381,14 +380,6 @@ protected: glm::vec3 _prevLeftFootPoleVector { Vectors::UNIT_Z }; // sensor space bool _prevLeftFootPoleVectorValid { false }; - glm::vec3 _prevRightHandPoleVector{ -Vectors::UNIT_Z }; // sensor space - bool _prevRightHandPoleVectorValid{ false }; - - glm::vec3 _prevLeftHandPoleVector{ -Vectors::UNIT_Z }; // sensor space - bool _prevLeftHandPoleVectorValid{ false }; - - bool _smoothPoleVectors { false }; - int _rigId; bool _headEnabled { false }; diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index f154746707..6770cd7f96 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -173,7 +173,6 @@ AvatarTransit::Status AvatarTransit::updatePosition(float deltaTime) { Status status = Status::IDLE; if (_isTransiting) { float nextTime = _currentTime + deltaTime; - glm::vec3 newPosition; if (nextTime >= _totalTime) { _currentPosition = _endPosition; _isTransiting = false; @@ -704,6 +703,19 @@ static TextRenderer3D* textRenderer(TextRendererType type) { return displayNameRenderer; } +void Avatar::metaBlendshapeOperator(int blendshapeNumber, const QVector& blendshapeOffsets, const QVector& blendedMeshSizes, + const render::ItemIDs& subItemIDs) { + render::Transaction transaction; + transaction.updateItem(_renderItemID, [blendshapeNumber, blendshapeOffsets, blendedMeshSizes, + subItemIDs](AvatarData& avatar) { + auto avatarPtr = dynamic_cast(&avatar); + if (avatarPtr) { + avatarPtr->setBlendedVertices(blendshapeNumber, blendshapeOffsets, blendedMeshSizes, subItemIDs); + } + }); + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +} + void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) { auto avatarPayload = new render::Payload(self); auto avatarPayloadPointer = std::shared_ptr>(avatarPayload); @@ -713,7 +725,8 @@ void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& sc // INitialize the _render bound as we are creating the avatar render item _renderBound = getBounds(); transaction.resetItem(_renderItemID, avatarPayloadPointer); - _skeletonModel->addToScene(scene, transaction); + using namespace std::placeholders; + _skeletonModel->addToScene(scene, transaction, std::bind(&Avatar::metaBlendshapeOperator, this, _1, _2, _3, _4)); _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); _skeletonModel->setGroupCulled(true); _skeletonModel->setCanCastShadow(true); @@ -792,7 +805,7 @@ void Avatar::updateRenderItem(render::Transaction& transaction) { avatarPtr->_renderBound = renderBound; } } - ); + ); } } @@ -936,7 +949,8 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { render::Transaction transaction; if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { _skeletonModel->removeFromScene(scene, transaction); - _skeletonModel->addToScene(scene, transaction); + using namespace std::placeholders; + _skeletonModel->addToScene(scene, transaction, std::bind(&Avatar::metaBlendshapeOperator, this, _1, _2, _3, _4)); _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); _skeletonModel->setGroupCulled(true); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 1087f74c07..3f4cf7b8c2 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -28,6 +28,8 @@ #include "Rig.h" #include +#include "MetaModelPayload.h" + namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar); template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar); @@ -108,7 +110,7 @@ private: float _scale { 1.0f }; }; -class Avatar : public AvatarData, public scriptable::ModelProvider { +class Avatar : public AvatarData, public scriptable::ModelProvider, public MetaModelPayload { Q_OBJECT // This property has JSDoc in MyAvatar.h. @@ -620,6 +622,9 @@ protected: static const float ATTACHMENT_LOADING_PRIORITY; LoadingStatus _loadingStatus { LoadingStatus::NoModel }; + + void metaBlendshapeOperator(int blendshapeNumber, const QVector& blendshapeOffsets, const QVector& blendedMeshSizes, + const render::ItemIDs& subItemIDs); }; #endif // hifi_Avatar_h diff --git a/libraries/avatars/src/AvatarHashMap.cpp b/libraries/avatars/src/AvatarHashMap.cpp index b9c6899e09..162dc86c37 100644 --- a/libraries/avatars/src/AvatarHashMap.cpp +++ b/libraries/avatars/src/AvatarHashMap.cpp @@ -258,7 +258,6 @@ AvatarSharedPointer AvatarHashMap::parseAvatarData(QSharedPointersetIsNewAvatar(true); auto replicaIDs = _replicas.getReplicaIDs(sessionUUID); for (auto replicaID : replicaIDs) { @@ -300,7 +299,6 @@ void AvatarHashMap::processAvatarIdentityPacket(QSharedPointer { QReadLocker locker(&_hashLock); - _pendingAvatars.remove(identityUUID); auto me = _avatarHash.find(EMPTY); if ((me != _avatarHash.end()) && (identityUUID == me.value()->getSessionUUID())) { // We add MyAvatar to _avatarHash with an empty UUID. Code relies on this. In order to correctly handle an @@ -419,7 +417,6 @@ void AvatarHashMap::removeAvatar(const QUuid& sessionUUID, KillAvatarReason remo } } - _pendingAvatars.remove(sessionUUID); auto removedAvatar = _avatarHash.take(sessionUUID); if (removedAvatar) { diff --git a/libraries/avatars/src/AvatarHashMap.h b/libraries/avatars/src/AvatarHashMap.h index c2cb448e52..3bb38dd081 100644 --- a/libraries/avatars/src/AvatarHashMap.h +++ b/libraries/avatars/src/AvatarHashMap.h @@ -161,6 +161,11 @@ protected slots: */ void processAvatarIdentityPacket(QSharedPointer message, SharedNodePointer sendingNode); + /**jsdoc + * @function AvatarList.processBulkAvatarTraits + * @param {} message + * @param {} sendingNode + */ void processBulkAvatarTraits(QSharedPointer message, SharedNodePointer sendingNode); /**jsdoc @@ -183,15 +188,8 @@ protected: virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar, KillAvatarReason removalReason = KillAvatarReason::NoReason); - AvatarHash _avatarHash; - struct PendingAvatar { - std::chrono::steady_clock::time_point creationTime; - int transmits; - AvatarSharedPointer avatar; - }; - using AvatarPendingHash = QHash; - AvatarPendingHash _pendingAvatars; mutable QReadWriteLock _hashLock; + AvatarHash _avatarHash; std::unordered_map _processedTraitVersions; AvatarReplicas _replicas; diff --git a/libraries/controllers/src/controllers/InputDevice.h b/libraries/controllers/src/controllers/InputDevice.h index 6c5cc3a065..7479ef7b75 100644 --- a/libraries/controllers/src/controllers/InputDevice.h +++ b/libraries/controllers/src/controllers/InputDevice.h @@ -98,7 +98,7 @@ enum Hand { class InputDevice { public: InputDevice(const QString& name) : _name(name) {} - virtual ~InputDevice() {} + virtual ~InputDevice() = default; using Pointer = std::shared_ptr; diff --git a/libraries/controllers/src/controllers/impl/Conditional.h b/libraries/controllers/src/controllers/impl/Conditional.h index a216c8789f..844a6037be 100644 --- a/libraries/controllers/src/controllers/impl/Conditional.h +++ b/libraries/controllers/src/controllers/impl/Conditional.h @@ -30,6 +30,8 @@ namespace controller { using Factory = hifi::SimpleFactory; using Lambda = std::function; + virtual ~Conditional() = default; + virtual bool satisfied() = 0; virtual bool parseParameters(const QJsonValue& parameters) { return true; } diff --git a/libraries/controllers/src/controllers/impl/Filter.h b/libraries/controllers/src/controllers/impl/Filter.h index cde8f991b7..7afabb4bcb 100644 --- a/libraries/controllers/src/controllers/impl/Filter.h +++ b/libraries/controllers/src/controllers/impl/Filter.h @@ -35,6 +35,8 @@ namespace controller { using Lambda = std::function; using Factory = hifi::SimpleFactory; + virtual ~Filter() = default; + virtual float apply(float value) const = 0; virtual Pose apply(Pose value) const = 0; diff --git a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h index 7d8f08ca1c..2299843a24 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h +++ b/libraries/controllers/src/controllers/impl/conditionals/AndConditional.h @@ -24,8 +24,6 @@ public: AndConditional(Conditional::Pointer& first, Conditional::Pointer& second) : _children({ first, second }) {} - virtual ~AndConditional() {} - virtual bool satisfied() override; private: diff --git a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h index a6bd7d468d..0ba1347087 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h +++ b/libraries/controllers/src/controllers/impl/conditionals/EndpointConditional.h @@ -18,7 +18,6 @@ namespace controller { class EndpointConditional : public Conditional { public: EndpointConditional(Endpoint::Pointer endpoint) : _endpoint(endpoint) {} - virtual ~EndpointConditional() {} virtual bool satisfied() override { return _endpoint && _endpoint->peek() != 0.0f; } private: Endpoint::Pointer _endpoint; diff --git a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h index 3fcd5f49fc..6b19cf9505 100644 --- a/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h +++ b/libraries/controllers/src/controllers/impl/conditionals/NotConditional.h @@ -19,7 +19,6 @@ namespace controller { using Pointer = std::shared_ptr; NotConditional(Conditional::Pointer operand) : _operand(operand) { } - virtual ~NotConditional() {} virtual bool satisfied() override; diff --git a/libraries/controllers/src/controllers/impl/filters/ClampFilter.h b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h index 6eca00fbe2..b06a43515f 100644 --- a/libraries/controllers/src/controllers/impl/filters/ClampFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ClampFilter.h @@ -18,7 +18,6 @@ class ClampFilter : public Filter { REGISTER_FILTER_CLASS(ClampFilter); public: ClampFilter(float min = 0.0, float max = 1.0) : _min(min), _max(max) {}; - virtual ~ClampFilter() {} virtual float apply(float value) const override { return glm::clamp(value, _min, _max); } diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h index bc90121ab0..129e08741d 100644 --- a/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToIntegerFilter.h @@ -17,16 +17,13 @@ namespace controller { class ConstrainToIntegerFilter : public Filter { REGISTER_FILTER_CLASS(ConstrainToIntegerFilter); public: - ConstrainToIntegerFilter() {}; - virtual ~ConstrainToIntegerFilter() {} + ConstrainToIntegerFilter() = default; virtual float apply(float value) const override { return glm::sign(value); } virtual Pose apply(Pose value) const override { return value; } - -protected: }; } diff --git a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h index accebef851..8f2140721a 100644 --- a/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ConstrainToPositiveIntegerFilter.h @@ -17,16 +17,13 @@ namespace controller { class ConstrainToPositiveIntegerFilter : public Filter { REGISTER_FILTER_CLASS(ConstrainToPositiveIntegerFilter); public: - ConstrainToPositiveIntegerFilter() {}; - virtual ~ConstrainToPositiveIntegerFilter() {}; + ConstrainToPositiveIntegerFilter() = default; virtual float apply(float value) const override { return (value <= 0.0f) ? 0.0f : 1.0f; } virtual Pose apply(Pose value) const override { return value; } - -protected: }; } diff --git a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h index 96c60198e2..d898647126 100644 --- a/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/DeadZoneFilter.h @@ -18,7 +18,6 @@ class DeadZoneFilter : public Filter { REGISTER_FILTER_CLASS(DeadZoneFilter); public: DeadZoneFilter(float min = 0.0) : _min(min) {}; - virtual ~DeadZoneFilter() {} virtual float apply(float value) const override; diff --git a/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h b/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h index 5b29b6681a..134f57243e 100644 --- a/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ExponentialSmoothingFilter.h @@ -20,7 +20,6 @@ namespace controller { ExponentialSmoothingFilter() {} ExponentialSmoothingFilter(float rotationConstant, float translationConstant) : _translationConstant(translationConstant), _rotationConstant(rotationConstant) {} - virtual ~ExponentialSmoothingFilter() {} float apply(float value) const override { return value; } Pose apply(Pose value) const override; diff --git a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h index 4a607d0d5f..4eb563754f 100644 --- a/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/HysteresisFilter.h @@ -18,7 +18,6 @@ class HysteresisFilter : public Filter { REGISTER_FILTER_CLASS(HysteresisFilter); public: HysteresisFilter(float min = 0.25, float max = 0.75); - virtual ~HysteresisFilter() {} virtual float apply(float value) const override; virtual Pose apply(Pose value) const override { return value; } diff --git a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h index 03b6e9fcb0..9361dfc60b 100644 --- a/libraries/controllers/src/controllers/impl/filters/InvertFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/InvertFilter.h @@ -19,11 +19,8 @@ class InvertFilter : public ScaleFilter { public: using ScaleFilter::parseParameters; InvertFilter() : ScaleFilter(-1.0f) {} - virtual ~InvertFilter() {} virtual bool parseParameters(const QJsonArray& parameters) { return true; } - -private: }; } diff --git a/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h b/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h index fa75473edf..ac5299dc6f 100644 --- a/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/LowVelocityFilter.h @@ -17,10 +17,9 @@ namespace controller { REGISTER_FILTER_CLASS(LowVelocityFilter); public: - LowVelocityFilter() {} + LowVelocityFilter() = default; LowVelocityFilter(float rotationConstant, float translationConstant) : _translationConstant(translationConstant), _rotationConstant(rotationConstant) {} - virtual ~LowVelocityFilter() {} float apply(float value) const override { return value; } Pose apply(Pose newPose) const override; diff --git a/libraries/controllers/src/controllers/impl/filters/NotFilter.h b/libraries/controllers/src/controllers/impl/filters/NotFilter.h index fa52b8e212..ceb7d29de3 100644 --- a/libraries/controllers/src/controllers/impl/filters/NotFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/NotFilter.h @@ -10,7 +10,6 @@ class NotFilter : public Filter { REGISTER_FILTER_CLASS(NotFilter); public: NotFilter(); - virtual ~NotFilter() {} virtual float apply(float value) const override; virtual Pose apply(Pose value) const override { return value; } diff --git a/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h b/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h index 1cb9c0a1bd..3c1cb4f80c 100644 --- a/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/PostTransformFilter.h @@ -19,9 +19,8 @@ namespace controller { class PostTransformFilter : public Filter { REGISTER_FILTER_CLASS(PostTransformFilter); public: - PostTransformFilter() { } + PostTransformFilter() = default; PostTransformFilter(glm::mat4 transform) : _transform(transform) {} - virtual ~PostTransformFilter() {} virtual float apply(float value) const override { return value; } virtual Pose apply(Pose value) const override { return value.postTransform(_transform); } virtual bool parseParameters(const QJsonValue& parameters) override { return parseMat4Parameter(parameters, _transform); } diff --git a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h index 37cfe34b86..2e0da0efa9 100644 --- a/libraries/controllers/src/controllers/impl/filters/PulseFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/PulseFilter.h @@ -18,9 +18,8 @@ namespace controller { class PulseFilter : public Filter { REGISTER_FILTER_CLASS(PulseFilter); public: - PulseFilter() {} + PulseFilter() = default; PulseFilter(float interval) : _interval(interval) {} - virtual ~PulseFilter() {} virtual float apply(float value) const override; diff --git a/libraries/controllers/src/controllers/impl/filters/RotateFilter.h b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h index aecf4f7b7c..c6735f6aa9 100644 --- a/libraries/controllers/src/controllers/impl/filters/RotateFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/RotateFilter.h @@ -19,9 +19,8 @@ namespace controller { class RotateFilter : public Filter { REGISTER_FILTER_CLASS(RotateFilter); public: - RotateFilter() { } + RotateFilter() = default; RotateFilter(glm::quat rotation) : _rotation(rotation) {} - virtual ~RotateFilter() {} virtual float apply(float value) const override { return value; } diff --git a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h index 84f7cb7e47..936498a7a1 100644 --- a/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/ScaleFilter.h @@ -19,9 +19,8 @@ namespace controller { class ScaleFilter : public Filter { REGISTER_FILTER_CLASS(ScaleFilter); public: - ScaleFilter() {} + ScaleFilter() = default; ScaleFilter(float scale) : _scale(scale) {} - virtual ~ScaleFilter() {} virtual float apply(float value) const override { return value * _scale; diff --git a/libraries/controllers/src/controllers/impl/filters/TransformFilter.h b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h index ccfa9c6c25..a34edaa337 100644 --- a/libraries/controllers/src/controllers/impl/filters/TransformFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/TransformFilter.h @@ -19,9 +19,8 @@ namespace controller { class TransformFilter : public Filter { REGISTER_FILTER_CLASS(TransformFilter); public: - TransformFilter() { } + TransformFilter() = default; TransformFilter(glm::mat4 transform) : _transform(transform) {} - virtual ~TransformFilter() {} virtual float apply(float value) const override { return value; } virtual Pose apply(Pose value) const override { return value.transform(_transform); } diff --git a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h index a66e1eb4a4..ced9cbc689 100644 --- a/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h +++ b/libraries/controllers/src/controllers/impl/filters/TranslateFilter.h @@ -19,9 +19,8 @@ namespace controller { class TranslateFilter : public Filter { REGISTER_FILTER_CLASS(TranslateFilter); public: - TranslateFilter() { } + TranslateFilter() = default; TranslateFilter(glm::vec3 translate) : _translate(translate) {} - virtual ~TranslateFilter() {} virtual float apply(float value) const override { return value; } virtual Pose apply(Pose value) const override { return value.transform(glm::translate(_translate)); } diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp index d7a0cfd18d..c607f678b6 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.cpp @@ -24,12 +24,18 @@ bool MaterialEntityRenderer::needsRenderUpdateFromTypedEntity(const TypedEntityP if (entity->getMaterialMappingPos() != _materialMappingPos || entity->getMaterialMappingScale() != _materialMappingScale || entity->getMaterialMappingRot() != _materialMappingRot) { return true; } + if (!_texturesLoaded) { + return true; + } return false; } void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) { withWriteLock([&] { - _drawMaterial = entity->getMaterial(); + if (_drawMaterial != entity->getMaterial()) { + _texturesLoaded = false; + _drawMaterial = entity->getMaterial(); + } _parentID = entity->getParentID(); _materialMappingPos = entity->getMaterialMappingPos(); _materialMappingScale = entity->getMaterialMappingScale(); @@ -38,6 +44,12 @@ void MaterialEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& const float MATERIAL_ENTITY_SCALE = 0.5f; _renderTransform.postScale(MATERIAL_ENTITY_SCALE); _renderTransform.postScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); + + bool newTexturesLoaded = _drawMaterial ? !_drawMaterial->isMissingTexture() : false; + if (!_texturesLoaded && newTexturesLoaded) { + _drawMaterial->checkResetOpacityMap(); + } + _texturesLoaded = newTexturesLoaded; }); } diff --git a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h index 168041a842..c90048ecf5 100644 --- a/libraries/entities-renderer/src/RenderableMaterialEntityItem.h +++ b/libraries/entities-renderer/src/RenderableMaterialEntityItem.h @@ -35,6 +35,7 @@ private: glm::vec2 _materialMappingPos; glm::vec2 _materialMappingScale; float _materialMappingRot; + bool _texturesLoaded { false }; std::shared_ptr _drawMaterial; }; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0452587439..c6337dc872 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -975,14 +975,21 @@ QStringList RenderableModelEntityItem::getJointNames() const { return result; } -// FIXME: deprecated; remove >= RC67 -bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) { - auto model = getModel(); - if (!model || !model->isLoaded()) { - return false; +void RenderableModelEntityItem::setAnimationURL(const QString& url) { + QString oldURL = getAnimationURL(); + ModelEntityItem::setAnimationURL(url); + if (oldURL != getAnimationURL()) { + _needsAnimationReset = true; } - BLOCKING_INVOKE_METHOD(model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result)); - return !result.isEmpty(); +} + +bool RenderableModelEntityItem::needsAnimationReset() const { + return _needsAnimationReset; +} + +QString RenderableModelEntityItem::getAnimationURLAndReset() { + _needsAnimationReset = false; + return getAnimationURL(); } scriptable::ScriptableModelBase render::entities::ModelEntityRenderer::getScriptableModel() { @@ -1068,6 +1075,13 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() { } } +bool RenderableModelEntityItem::readyToAnimate() const { + return resultWithReadLock([&] { + float firstFrame = _animationProperties.getFirstFrame(); + return (firstFrame >= 0.0f) && (firstFrame <= _animationProperties.getLastFrame()); + }); +} + using namespace render; using namespace render::entities; @@ -1155,7 +1169,7 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { const QVector& rotations = frames[_lastKnownCurrentFrame].rotations; const QVector& translations = frames[_lastKnownCurrentFrame].translations; - + jointsData.resize(_jointMapping.size()); for (int j = 0; j < _jointMapping.size(); j++) { int index = _jointMapping[j]; @@ -1169,13 +1183,12 @@ void ModelEntityRenderer::animate(const TypedEntityPointer& entity) { } } else if (index < animationJointNames.size()) { QString jointName = fbxJoints[index].name; // Pushing this here so its not done on every entity, with the exceptions of those allowing for translation - if (originalFbxIndices.contains(jointName)) { // Making sure the joint names exist in the original model the animation is trying to apply onto. If they do, then remap and get it's translation. int remappedIndex = originalFbxIndices[jointName] - 1; // JointIndeces seem to always start from 1 and the found index is always 1 higher than actual. translationMat = glm::translate(originalFbxJoints[remappedIndex].translation); } - } + } glm::mat4 rotationMat; if (index < rotations.size()) { rotationMat = glm::mat4_cast(fbxJoints[index].preRotation * rotations[index] * fbxJoints[index].postRotation); @@ -1477,14 +1490,17 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce if (_animating) { DETAILED_PROFILE_RANGE(simulation_physics, "Animate"); - if (!jointsMapped()) { - mapJoints(entity, model->getJointNames()); - //else the joint have been mapped before but we have a new animation to load - } else if (_animation && (_animation->getURL().toString() != entity->getAnimationURL())) { + if (_animation && entity->needsAnimationReset()) { + //(_animation->getURL().toString() != entity->getAnimationURL())) { // bad check + // the joints have been mapped before but we have a new animation to load + _animation.reset(); _jointMappingCompleted = false; - mapJoints(entity, model->getJointNames()); } - if (!(entity->getAnimationFirstFrame() < 0) && !(entity->getAnimationFirstFrame() > entity->getAnimationLastFrame())) { + + if (!_jointMappingCompleted) { + mapJoints(entity, model); + } + if (entity->readyToAnimate()) { animate(entity); } emit requestRenderUpdate(); @@ -1518,19 +1534,20 @@ void ModelEntityRenderer::doRender(RenderArgs* args) { #endif } -void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames) { +void ModelEntityRenderer::mapJoints(const TypedEntityPointer& entity, const ModelPointer& model) { // if we don't have animation, or we're already joint mapped then bail early - if (!entity->hasAnimation() || jointsMapped()) { + if (!entity->hasAnimation()) { return; } - if (!_animation || _animation->getURL().toString() != entity->getAnimationURL()) { - _animation = DependencyManager::get()->getAnimation(entity->getAnimationURL()); + if (!_animation) { + _animation = DependencyManager::get()->getAnimation(entity->getAnimationURLAndReset()); } if (_animation && _animation->isLoaded()) { QStringList animationJointNames = _animation->getJointNames(); + auto modelJointNames = model->getJointNames(); if (modelJointNames.size() > 0 && animationJointNames.size() > 0) { _jointMapping.resize(modelJointNames.size()); for (int i = 0; i < modelJointNames.size(); i++) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index b5f9d9f833..79e56d7a76 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -24,8 +24,6 @@ #include "RenderableEntityItem.h" - - class Model; class EntityTreeRenderer; @@ -114,21 +112,25 @@ public: virtual int getJointIndex(const QString& name) const override; virtual QStringList getJointNames() const override; - bool getMeshes(MeshProxyList& result) override; // deprecated + void setAnimationURL(const QString& url) override; + bool needsAnimationReset() const; + QString getAnimationURLAndReset(); private: bool needsUpdateModelBounds() const; void autoResizeJointArrays(); void copyAnimationJointDataToModel(); - + bool readyToAnimate() const; void getCollisionGeometryResource(); + GeometryResource::Pointer _compoundShapeResource; - bool _jointMapCompleted { false }; - bool _originalTexturesRead { false }; std::vector _jointMap; QVariantMap _originalTextures; + bool _jointMapCompleted { false }; + bool _originalTexturesRead { false }; bool _dimensionsInitialized { true }; bool _needsJointSimulation { false }; + bool _needsAnimationReset { false }; }; namespace render { namespace entities { @@ -169,8 +171,7 @@ protected: private: void animate(const TypedEntityPointer& entity); - void mapJoints(const TypedEntityPointer& entity, const QStringList& modelJointNames); - bool jointsMapped() const { return _jointMappingCompleted; } + void mapJoints(const TypedEntityPointer& entity, const ModelPointer& model); // Transparency is handled in ModelMeshPartPayload virtual bool isTransparent() const override { return false; } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 6279f0bae0..36ffc68fd3 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -673,7 +673,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef const QUuid& myNodeID = nodeList->getSessionUUID(); bool weOwnSimulation = _simulationOwner.matchesValidID(myNodeID); - // pack SimulationOwner and terse update properties near each other + // pack SimulationOwner, transform, and velocity properties near each other // NOTE: the server is authoritative for changes to simOwnerID so we always unpack ownership data // even when we would otherwise ignore the rest of the packet. @@ -1358,8 +1358,7 @@ EntityItemProperties EntityItem::getProperties(const EntityPropertyFlags& desire return properties; } -void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) const { - // a TerseUpdate includes the transform and its derivatives +void EntityItem::getTransformAndVelocityProperties(EntityItemProperties& properties) const { if (!properties._positionChanged) { properties._position = getLocalPosition(); } @@ -1383,8 +1382,11 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c properties._accelerationChanged = true; } -void EntityItem::setScriptSimulationPriority(uint8_t priority) { - uint8_t newPriority = stillHasGrabActions() ? glm::max(priority, SCRIPT_GRAB_SIMULATION_PRIORITY) : priority; +void EntityItem::upgradeScriptSimulationPriority(uint8_t priority) { + uint8_t newPriority = glm::max(priority, _scriptSimulationPriority); + if (newPriority < SCRIPT_GRAB_SIMULATION_PRIORITY && stillHasGrabActions()) { + newPriority = SCRIPT_GRAB_SIMULATION_PRIORITY; + } if (newPriority != _scriptSimulationPriority) { // set the dirty flag to trigger a bid or ownership update markDirtyFlags(Simulation::DIRTY_SIMULATION_OWNERSHIP_PRIORITY); @@ -1419,7 +1421,7 @@ bool EntityItem::stillWaitingToTakeOwnership(uint64_t timestamp) const { bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - // these affect TerseUpdate properties + // these affect transform and velocity properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); SET_ENTITY_PROPERTY_FROM_PROPERTIES(position, setPosition); SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotation, setRotation); @@ -3256,3 +3258,26 @@ void EntityItem::setScriptHasFinishedPreload(bool value) { bool EntityItem::isScriptPreloadFinished() { return _scriptPreloadFinished; } + +void EntityItem::prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority) { + if (dynamicDataNeedsTransmit()) { + setDynamicDataNeedsTransmit(false); + properties.setActionData(getDynamicData()); + } + + if (updateQueryAACube()) { + // due to parenting, the server may not know where something is in world-space, so include the bounding cube. + properties.setQueryAACube(getQueryAACube()); + } + + // set the LastEdited of the properties but NOT the entity itself + properties.setLastEdited(now); + + clearScriptSimulationPriority(); + properties.setSimulationOwner(Physics::getSessionUUID(), priority); + setPendingOwnershipPriority(priority); + + properties.setClientOnly(getClientOnly()); + properties.setOwningAvatarID(getOwningAvatarID()); + setLastBroadcast(now); // for debug/physics status icons +} diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index e4063eac3b..c49017b2e0 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -325,7 +325,7 @@ public: // TODO: move this "ScriptSimulationPriority" and "PendingOwnership" stuff into EntityMotionState // but first would need to do some other cleanup. In the meantime these live here as "scratch space" // to allow libs that don't know about each other to communicate. - void setScriptSimulationPriority(uint8_t priority); + void upgradeScriptSimulationPriority(uint8_t priority); void clearScriptSimulationPriority(); uint8_t getScriptSimulationPriority() const { return _scriptSimulationPriority; } void setPendingOwnershipPriority(uint8_t priority); @@ -420,7 +420,7 @@ public: quint64 getLastEditedFromRemote() const { return _lastEditedFromRemote; } void updateLastEditedFromRemote() { _lastEditedFromRemote = usecTimestampNow(); } - void getAllTerseUpdateProperties(EntityItemProperties& properties) const; + void getTransformAndVelocityProperties(EntityItemProperties& properties) const; void flagForMotionStateChange() { _flags |= Simulation::DIRTY_MOTION_TYPE; } @@ -535,6 +535,8 @@ public: const GrabPropertyGroup& getGrabProperties() const { return _grabProperties; } + void prepareForSimulationOwnershipBid(EntityItemProperties& properties, uint64_t now, uint8_t priority); + signals: void requestRenderUpdate(); void spaceUpdate(std::pair data); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index dd5c2020c8..37d8dc0bdc 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -2387,8 +2387,8 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy } if (properties.getType() == EntityTypes::Light) { - APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight()); + APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor()); APPEND_ENTITY_PROPERTY(PROP_INTENSITY, properties.getIntensity()); APPEND_ENTITY_PROPERTY(PROP_FALLOFF_RADIUS, properties.getFalloffRadius()); APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent()); @@ -3244,9 +3244,12 @@ AABox EntityItemProperties::getAABox() const { return AABox(rotatedExtentsRelativeToRegistrationPoint); } -bool EntityItemProperties::hasTerseUpdateChanges() const { - // a TerseUpdate includes the transform and its derivatives - return _positionChanged || _velocityChanged || _rotationChanged || _angularVelocityChanged || _accelerationChanged; +bool EntityItemProperties::hasTransformOrVelocityChanges() const { + return _positionChanged ||_localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _angularVelocityChanged || _localAngularVelocityChanged + || _accelerationChanged; } bool EntityItemProperties::hasMiscPhysicsChanges() const { @@ -3255,6 +3258,56 @@ bool EntityItemProperties::hasMiscPhysicsChanges() const { _compoundShapeURLChanged || _dynamicChanged || _collisionlessChanged || _collisionMaskChanged; } +bool EntityItemProperties::hasSimulationRestrictedChanges() const { + return _positionChanged || _localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _angularVelocityChanged || _localAngularVelocityChanged + || _accelerationChanged + || _parentIDChanged || _parentJointIndexChanged; +} + +void EntityItemProperties::copySimulationRestrictedProperties(const EntityItemPointer& entity) { + if (!_parentIDChanged) { + setParentID(entity->getParentID()); + } + if (!_parentJointIndexChanged) { + setParentJointIndex(entity->getParentJointIndex()); + } + if (!_localPositionChanged && !_positionChanged) { + setPosition(entity->getWorldPosition()); + } + if (!_localRotationChanged && !_rotationChanged) { + setRotation(entity->getWorldOrientation()); + } + if (!_localVelocityChanged && !_velocityChanged) { + setVelocity(entity->getWorldVelocity()); + } + if (!_localAngularVelocityChanged && !_angularVelocityChanged) { + setAngularVelocity(entity->getWorldAngularVelocity()); + } + if (!_accelerationChanged) { + setAcceleration(entity->getAcceleration()); + } + if (!_localDimensionsChanged && !_dimensionsChanged) { + setDimensions(entity->getScaledDimensions()); + } +} + +void EntityItemProperties::clearSimulationRestrictedProperties() { + _positionChanged = false; + _localPositionChanged = false; + _rotationChanged = false; + _localRotationChanged = false; + _velocityChanged = false; + _localVelocityChanged = false; + _angularVelocityChanged = false; + _localAngularVelocityChanged = false; + _accelerationChanged = false; + _parentIDChanged = false; + _parentJointIndexChanged = false; +} + void EntityItemProperties::clearSimulationOwner() { _simulationOwner.clear(); _simulationOwnerChanged = true; @@ -3273,6 +3326,20 @@ void EntityItemProperties::setSimulationOwner(const QByteArray& data) { } } +uint8_t EntityItemProperties::computeSimulationBidPriority() const { + uint8_t priority = 0; + if (_parentIDChanged || _parentJointIndexChanged) { + // we need higher simulation ownership priority to chang parenting info + priority = SCRIPT_GRAB_SIMULATION_PRIORITY; + } else if ( _positionChanged || _localPositionChanged + || _rotationChanged || _localRotationChanged + || _velocityChanged || _localVelocityChanged + || _angularVelocityChanged || _localAngularVelocityChanged) { + priority = SCRIPT_POKE_SIMULATION_PRIORITY; + } + return priority; +} + QList EntityItemProperties::listChangedProperties() { QList out; if (containsPositionChange()) { diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 8527b471c3..ae2c402d22 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -349,13 +349,18 @@ public: void setCreated(QDateTime& v); - bool hasTerseUpdateChanges() const; + bool hasTransformOrVelocityChanges() const; bool hasMiscPhysicsChanges() const; + bool hasSimulationRestrictedChanges() const; + void copySimulationRestrictedProperties(const EntityItemPointer& entity); + void clearSimulationRestrictedProperties(); + void clearSimulationOwner(); void setSimulationOwner(const QUuid& id, uint8_t priority); void setSimulationOwner(const QByteArray& data); void setSimulationPriority(uint8_t priority) { _simulationOwner.setPriority(priority); } + uint8_t computeSimulationBidPriority() const; void setActionDataDirty() { _actionDataChanged = true; } diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index a8fce0d5fb..f8b22fdbae 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -174,6 +174,7 @@ EntityItemProperties convertPropertiesToScriptSemantics(const EntityItemProperti } +// TODO: this method looks expensive and should take properties by reference, update it, and return void EntityItemProperties convertPropertiesFromScriptSemantics(const EntityItemProperties& scriptSideProperties, bool scalesWithParent) { // convert position and rotation properties from world-space to local, unless localPosition and localRotation @@ -242,13 +243,12 @@ QUuid EntityScriptingInterface::addEntity(const EntityItemProperties& properties _activityTracking.addedEntityCount++; auto nodeList = DependencyManager::get(); - auto sessionID = nodeList->getSessionUUID(); + const auto sessionID = nodeList->getSessionUUID(); EntityItemProperties propertiesWithSimID = properties; if (clientOnly) { - const QUuid myNodeID = sessionID; propertiesWithSimID.setClientOnly(clientOnly); - propertiesWithSimID.setOwningAvatarID(myNodeID); + propertiesWithSimID.setOwningAvatarID(sessionID); } propertiesWithSimID.setLastEditedBy(sessionID); @@ -290,7 +290,7 @@ bool EntityScriptingInterface::addLocalEntityCopy(EntityItemProperties& properti entity->setLastBroadcast(usecTimestampNow()); // since we're creating this object we will immediately volunteer to own its simulation - entity->setScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY); + entity->upgradeScriptSimulationPriority(VOLUNTEER_SIMULATION_PRIORITY); properties.setLastEdited(entity->getLastEdited()); } else { qCDebug(entities) << "script failed to add new Entity to local Octree"; @@ -530,54 +530,86 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& _activityTracking.editedEntityCount++; - auto nodeList = DependencyManager::get(); - auto sessionID = nodeList->getSessionUUID(); + const auto sessionID = DependencyManager::get()->getSessionUUID(); EntityItemProperties properties = scriptSideProperties; - properties.setLastEditedBy(sessionID); EntityItemID entityID(id); if (!_entityTree) { + properties.setLastEditedBy(sessionID); queueEntityMessage(PacketType::EntityEdit, entityID, properties); return id; } - // If we have a local entity tree set, then also update it. - bool updatedEntity = false; - _entityTree->withWriteLock([&] { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + EntityItemPointer entity(nullptr); + SimulationOwner simulationOwner; + _entityTree->withReadLock([&] { + // make a copy of entity for local logic outside of tree lock + entity = _entityTree->findEntityByEntityItemID(entityID); if (!entity) { return; } - if (entity->getClientOnly() && entity->getOwningAvatarID() != nodeList->getSessionUUID()) { + if (entity->getClientOnly() && entity->getOwningAvatarID() != sessionID) { // don't edit other avatar's avatarEntities + properties = EntityItemProperties(); return; } + // make a copy of simulationOwner for local logic outside of tree lock + simulationOwner = entity->getSimulationOwner(); + }); - if (scriptSideProperties.parentRelatedPropertyChanged()) { - // All of parentID, parentJointIndex, position, rotation are needed to make sense of any of them. - // If any of these changed, pull any missing properties from the entity. + if (entity) { + if (properties.hasSimulationRestrictedChanges()) { + if (_bidOnSimulationOwnership) { + // flag for simulation ownership, or upgrade existing ownership priority + // (actual bids for simulation ownership are sent by the PhysicalEntitySimulation) + entity->upgradeScriptSimulationPriority(properties.computeSimulationBidPriority()); + if (simulationOwner.getID() == sessionID) { + // we own the simulation --> copy ALL restricted properties + properties.copySimulationRestrictedProperties(entity); + } else { + // we don't own the simulation but think we would like to - if (!scriptSideProperties.parentIDChanged()) { - properties.setParentID(entity->getParentID()); - } - if (!scriptSideProperties.parentJointIndexChanged()) { - properties.setParentJointIndex(entity->getParentJointIndex()); - } - if (!scriptSideProperties.localPositionChanged() && !scriptSideProperties.positionChanged()) { - properties.setPosition(entity->getWorldPosition()); - } - if (!scriptSideProperties.localRotationChanged() && !scriptSideProperties.rotationChanged()) { - properties.setRotation(entity->getWorldOrientation()); - } - if (!scriptSideProperties.localDimensionsChanged() && !scriptSideProperties.dimensionsChanged()) { - properties.setDimensions(entity->getScaledDimensions()); + uint8_t desiredPriority = entity->getScriptSimulationPriority(); + if (desiredPriority < simulationOwner.getPriority()) { + // the priority at which we'd like to own it is not high enough + // --> assume failure and clear all restricted property changes + properties.clearSimulationRestrictedProperties(); + } else { + // the priority at which we'd like to own it is high enough to win. + // --> assume success and copy ALL restricted properties + properties.copySimulationRestrictedProperties(entity); + } + } + } else if (!simulationOwner.getID().isNull()) { + // someone owns this but not us + // clear restricted properties + properties.clearSimulationRestrictedProperties(); } + // clear the cached simulationPriority level + entity->upgradeScriptSimulationPriority(0); } + + // set these to make EntityItemProperties::getScalesWithParent() work correctly properties.setClientOnly(entity->getClientOnly()); properties.setOwningAvatarID(entity->getOwningAvatarID()); - properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent()); + + // make sure the properties has a type, so that the encode can know which properties to include + properties.setType(entity->getType()); + } else if (_bidOnSimulationOwnership) { + // bail when simulation participants don't know about entity + return QUuid(); + } + // TODO: it is possible there is no remaining useful changes in properties and we should bail early. + // How to check for this cheaply? + + properties = convertPropertiesFromScriptSemantics(properties, properties.getScalesWithParent()); + properties.setLastEditedBy(sessionID); + + // done reading and modifying properties --> start write + bool updatedEntity = false; + _entityTree->withWriteLock([&] { updatedEntity = _entityTree->updateEntity(entityID, properties); }); @@ -590,63 +622,37 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& // return QUuid(); // } - bool entityFound { false }; + bool hasQueryAACubeRelatedChanges = properties.queryAACubeRelatedPropertyChanged(); + // done writing, send update _entityTree->withReadLock([&] { - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(entityID); + // find the entity again: maybe it was removed since we last found it + entity = _entityTree->findEntityByEntityItemID(entityID); if (entity) { - entityFound = true; - // make sure the properties has a type, so that the encode can know which properties to include - properties.setType(entity->getType()); - bool hasTerseUpdateChanges = properties.hasTerseUpdateChanges(); - bool hasPhysicsChanges = properties.hasMiscPhysicsChanges() || hasTerseUpdateChanges; - if (_bidOnSimulationOwnership && hasPhysicsChanges) { - auto nodeList = DependencyManager::get(); - const QUuid myNodeID = nodeList->getSessionUUID(); + uint64_t now = usecTimestampNow(); + entity->setLastBroadcast(now); - if (entity->getSimulatorID() == myNodeID) { - // we think we already own the simulation, so make sure to send ALL TerseUpdate properties - if (hasTerseUpdateChanges) { - entity->getAllTerseUpdateProperties(properties); - } - // TODO: if we knew that ONLY TerseUpdate properties have changed in properties AND the object - // is dynamic AND it is active in the physics simulation then we could chose to NOT queue an update - // and instead let the physics simulation decide when to send a terse update. This would remove - // the "slide-no-rotate" glitch (and typical double-update) that we see during the "poke rolling - // balls" test. However, even if we solve this problem we still need to provide a "slerp the visible - // proxy toward the true physical position" feature to hide the final glitches in the remote watcher's - // simulation. - - if (entity->getSimulationPriority() < SCRIPT_POKE_SIMULATION_PRIORITY) { - // we re-assert our simulation ownership at a higher priority - properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY); - } - } else { - // we make a bid for simulation ownership - properties.setSimulationOwner(myNodeID, SCRIPT_POKE_SIMULATION_PRIORITY); - entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY); - } - } - if (properties.queryAACubeRelatedPropertyChanged()) { + if (hasQueryAACubeRelatedChanges) { properties.setQueryAACube(entity->getQueryAACube()); - } - entity->setLastBroadcast(usecTimestampNow()); - properties.setLastEdited(entity->getLastEdited()); - // if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server - // if they've changed. - entity->forEachDescendant([&](SpatiallyNestablePointer descendant) { - if (descendant->getNestableType() == NestableType::Entity) { - if (descendant->updateQueryAACube()) { - EntityItemPointer entityDescendant = std::static_pointer_cast(descendant); - EntityItemProperties newQueryCubeProperties; - newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube()); - newQueryCubeProperties.setLastEdited(properties.getLastEdited()); - queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties); - entityDescendant->setLastBroadcast(usecTimestampNow()); + // if we've moved an entity with children, check/update the queryAACube of all descendents and tell the server + // if they've changed. + entity->forEachDescendant([&](SpatiallyNestablePointer descendant) { + if (descendant->getNestableType() == NestableType::Entity) { + if (descendant->updateQueryAACube()) { + EntityItemPointer entityDescendant = std::static_pointer_cast(descendant); + EntityItemProperties newQueryCubeProperties; + newQueryCubeProperties.setQueryAACube(descendant->getQueryAACube()); + newQueryCubeProperties.setLastEdited(properties.getLastEdited()); + queueEntityMessage(PacketType::EntityEdit, descendant->getID(), newQueryCubeProperties); + entityDescendant->setLastBroadcast(now); + } } - } - }); - } else { + }); + } + } + }); + if (!entity) { + if (hasQueryAACubeRelatedChanges) { // Sometimes ESS don't have the entity they are trying to edit in their local tree. In this case, // convertPropertiesFromScriptSemantics doesn't get called and local* edits will get dropped. // This is because, on the script side, "position" is in world frame, but in the network @@ -668,8 +674,6 @@ QUuid EntityScriptingInterface::editEntity(QUuid id, const EntityItemProperties& properties.setDimensions(properties.getLocalDimensions()); } } - }); - if (!entityFound) { // we've made an edit to an entity we don't know about, or to a non-entity. If it's a known non-entity, // print a warning and don't send an edit packet to the entity-server. QSharedPointer parentFinder = DependencyManager::get(); @@ -1449,7 +1453,7 @@ QUuid EntityScriptingInterface::addAction(const QString& actionTypeString, } action->setIsMine(true); success = entity->addAction(simulation, action); - entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY); + entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY); return false; // Physics will cause a packet to be sent, so don't send from here. }); if (success) { @@ -1465,7 +1469,7 @@ bool EntityScriptingInterface::updateAction(const QUuid& entityID, const QUuid& return actionWorker(entityID, [&](EntitySimulationPointer simulation, EntityItemPointer entity) { bool success = entity->updateAction(simulation, actionID, arguments); if (success) { - entity->setScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY); + entity->upgradeScriptSimulationPriority(SCRIPT_GRAB_SIMULATION_PRIORITY); } return success; }); @@ -1479,7 +1483,7 @@ bool EntityScriptingInterface::deleteAction(const QUuid& entityID, const QUuid& success = entity->removeAction(simulation, actionID); if (success) { // reduce from grab to poke - entity->setScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY); + entity->upgradeScriptSimulationPriority(SCRIPT_POKE_SIMULATION_PRIORITY); } return false; // Physics will cause a packet to be sent, so don't send from here. }); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 72192c8702..b4b00e57a7 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -629,30 +629,6 @@ bool ModelEntityItem::getAnimationHold() const { }); } -void ModelEntityItem::setAnimationFirstFrame(float firstFrame) { - withWriteLock([&] { - _animationProperties.setFirstFrame(firstFrame); - }); -} - -float ModelEntityItem::getAnimationFirstFrame() const { - return resultWithReadLock([&] { - return _animationProperties.getFirstFrame(); - }); -} - -void ModelEntityItem::setAnimationLastFrame(float lastFrame) { - withWriteLock([&] { - _animationProperties.setLastFrame(lastFrame); - }); -} - -float ModelEntityItem::getAnimationLastFrame() const { - return resultWithReadLock([&] { - return _animationProperties.getLastFrame(); - }); -} - bool ModelEntityItem::getAnimationIsPlaying() const { return resultWithReadLock([&] { return _animationProperties.getRunning(); diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 91d2d81b88..5ca3e2caa1 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -79,9 +79,10 @@ public: // Animation related items... AnimationPropertyGroup getAnimationProperties() const; + // TODO: audit and remove unused Animation accessors bool hasAnimation() const; QString getAnimationURL() const; - void setAnimationURL(const QString& url); + virtual void setAnimationURL(const QString& url); void setAnimationCurrentFrame(float value); void setAnimationIsPlaying(bool value); @@ -99,12 +100,6 @@ public: void setRelayParentJoints(bool relayJoints); bool getRelayParentJoints() const; - void setAnimationFirstFrame(float firstFrame); - float getAnimationFirstFrame() const; - - void setAnimationLastFrame(float lastFrame); - float getAnimationLastFrame() const; - bool getAnimationIsPlaying() const; float getAnimationCurrentFrame() const; float getAnimationFPS() const; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp index 13c21d89e7..1203e65685 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.cpp @@ -67,6 +67,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] = (&::gpu::gl::GLBackend::do_clearFramebuffer), (&::gpu::gl::GLBackend::do_blit), (&::gpu::gl::GLBackend::do_generateTextureMips), + (&::gpu::gl::GLBackend::do_generateTextureMipsWithPipeline), (&::gpu::gl::GLBackend::do_advance), @@ -166,6 +167,10 @@ GLBackend::GLBackend() { GLBackend::~GLBackend() {} void GLBackend::shutdown() { + if (_mipGenerationFramebufferId) { + glDeleteFramebuffers(1, &_mipGenerationFramebufferId); + _mipGenerationFramebufferId = 0; + } killInput(); killTransform(); killTextureManagementStage(); diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h index 0b76ef17de..267c2a97ad 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackend.h @@ -288,6 +288,7 @@ public: virtual void do_setIndexBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_setIndirectBuffer(const Batch& batch, size_t paramOffset) final; virtual void do_generateTextureMips(const Batch& batch, size_t paramOffset) final; + virtual void do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) final; // Transform Stage virtual void do_setModelTransform(const Batch& batch, size_t paramOffset) final; @@ -407,6 +408,8 @@ public: protected: virtual GLint getRealUniformLocation(GLint location) const; + virtual void draw(GLenum mode, uint32 numVertices, uint32 startVertex) = 0; + void recycle() const override; // FIXME instead of a single flag, create a features struct similar to @@ -696,6 +699,8 @@ protected: virtual void initTextureManagementStage(); virtual void killTextureManagementStage(); + GLuint _mipGenerationFramebufferId{ 0 }; + typedef void (GLBackend::*CommandCall)(const Batch&, size_t); static CommandCall _commandCalls[Batch::NUM_COMMANDS]; friend class GLState; diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp index f4fb3fcf2c..b74ff079d7 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp +++ b/libraries/gpu-gl-common/src/gpu/gl/GLBackendTexture.cpp @@ -79,3 +79,55 @@ void GLBackend::do_generateTextureMips(const Batch& batch, size_t paramOffset) { object->generateMips(); } + +void GLBackend::do_generateTextureMipsWithPipeline(const Batch& batch, size_t paramOffset) { + TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint); + if (!resourceTexture) { + return; + } + + // Always make sure the GLObject is in sync + GLTexture* object = syncGPUObject(resourceTexture); + if (object) { + GLuint to = object->_texture; + glActiveTexture(GL_TEXTURE0 + gpu::slot::texture::MipCreationInput); + glBindTexture(object->_target, to); + (void)CHECK_GL_ERROR(); + } else { + return; + } + + auto numMips = batch._params[paramOffset + 1]._int; + if (numMips < 0) { + numMips = resourceTexture->getNumMips(); + } else { + numMips = std::min(numMips, (int)resourceTexture->getNumMips()); + } + + if (_mipGenerationFramebufferId == 0) { + glGenFramebuffers(1, &_mipGenerationFramebufferId); + Q_ASSERT(_mipGenerationFramebufferId > 0); + } + + glBindFramebuffer(GL_FRAMEBUFFER, _mipGenerationFramebufferId); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0); + + for (int level = 1; level < numMips; level++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, object->_id, level); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, level - 1); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level - 1); + + const auto mipDimensions = resourceTexture->evalMipDimensions(level); + glViewport(0, 0, mipDimensions.x, mipDimensions.y); + draw(GL_TRIANGLE_STRIP, 4, 0); + } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMips - 1); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + resetOutputStage(); + // Restore viewport + ivec4& vp = _transform._viewport; + glViewport(vp.x, vp.y, vp.z, vp.w); +} diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLShared.h b/libraries/gpu-gl-common/src/gpu/gl/GLShared.h index f67439f96a..1f40f7b7da 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLShared.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLShared.h @@ -19,7 +19,11 @@ Q_DECLARE_LOGGING_CATEGORY(gpugllogging) Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl) Q_DECLARE_LOGGING_CATEGORY(trace_render_gpu_gl_detail) +#if defined(__clang__) +#define BUFFER_OFFSET(bytes) (reinterpret_cast(bytes)) +#else #define BUFFER_OFFSET(bytes) ((GLubyte*) nullptr + (bytes)) +#endif namespace gpu { namespace gl { diff --git a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h index e9a55ad8e2..d3e8f386de 100644 --- a/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h +++ b/libraries/gpu-gl-common/src/gpu/gl/GLTexture.h @@ -25,8 +25,10 @@ struct GLFilterMode { class GLTextureTransferEngine { public: - virtual ~GLTextureTransferEngine() {} using Pointer = std::shared_ptr; + + virtual ~GLTextureTransferEngine() = default; + /// Called once per frame to perform any require memory management or transfer work virtual void manageMemory() = 0; virtual void shutdown() = 0; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp index 88cf89ad99..43ae4691b9 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.cpp @@ -20,6 +20,29 @@ using namespace gpu::gl41; const std::string GL41Backend::GL41_VERSION { "GL41" }; +void GL41Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, 2); +#else + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); +#endif + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + void GL41Backend::do_draw(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h index e5f7415107..5d691d032a 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h +++ b/libraries/gpu-gl/src/gpu/gl41/GL41Backend.h @@ -130,6 +130,9 @@ public: }; protected: + + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp index bbe011d237..e86eae2c2d 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.cpp @@ -42,6 +42,30 @@ void GL45Backend::recycle() const { Parent::recycle(); } +void GL45Backend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, 2); +#else + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); +#endif + + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + void GL45Backend::do_draw(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h index 30656b47c7..77095375af 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h +++ b/libraries/gpu-gl/src/gpu/gl45/GL45Backend.h @@ -229,6 +229,7 @@ public: protected: + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; void recycle() const override; GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp index b277889771..cb40b4fc9b 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.cpp @@ -20,6 +20,29 @@ using namespace gpu::gles; const std::string GLESBackend::GLES_VERSION { "GLES" }; +void GLESBackend::draw(GLenum mode, uint32 numVertices, uint32 startVertex) { + if (isStereo()) { +#ifdef GPU_STEREO_DRAWCALL_INSTANCED + glDrawArraysInstanced(mode, startVertex, numVertices, 2); +#else + setupStereoSide(0); + glDrawArrays(mode, startVertex, numVertices); + setupStereoSide(1); + glDrawArrays(mode, startVertex, numVertices); +#endif + _stats._DSNumTriangles += 2 * numVertices / 3; + _stats._DSNumDrawcalls += 2; + + } else { + glDrawArrays(mode, startVertex, numVertices); + _stats._DSNumTriangles += numVertices / 3; + _stats._DSNumDrawcalls++; + } + _stats._DSNumAPIDrawcalls++; + + (void)CHECK_GL_ERROR(); +} + void GLESBackend::do_draw(const Batch& batch, size_t paramOffset) { Primitive primitiveType = (Primitive)batch._params[paramOffset + 2]._uint; GLenum mode = gl::PRIMITIVE_TO_GL[primitiveType]; diff --git a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h index 56ae41da31..7f6765c129 100644 --- a/libraries/gpu-gles/src/gpu/gles/GLESBackend.h +++ b/libraries/gpu-gles/src/gpu/gles/GLESBackend.h @@ -126,6 +126,9 @@ public: }; protected: + + void draw(GLenum mode, uint32 numVertices, uint32 startVertex) override; + GLuint getFramebufferID(const FramebufferPointer& framebuffer) override; GLFramebuffer* syncGPUObject(const Framebuffer& framebuffer) override; diff --git a/libraries/gpu/src/gpu/Batch.cpp b/libraries/gpu/src/gpu/Batch.cpp index 018ca8f02f..e3ea210ecb 100644 --- a/libraries/gpu/src/gpu/Batch.cpp +++ b/libraries/gpu/src/gpu/Batch.cpp @@ -426,6 +426,13 @@ void Batch::generateTextureMips(const TexturePointer& texture) { _params.emplace_back(_textures.cache(texture)); } +void Batch::generateTextureMipsWithPipeline(const TexturePointer& texture, int numMips) { + ADD_COMMAND(generateTextureMipsWithPipeline); + + _params.emplace_back(_textures.cache(texture)); + _params.emplace_back(numMips); +} + void Batch::beginQuery(const QueryPointer& query) { ADD_COMMAND(beginQuery); diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 0f9c2f554b..96a45d3111 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -226,6 +226,8 @@ public: // Generate the mips for a texture void generateTextureMips(const TexturePointer& texture); + // Generate the mips for a texture using the current pipeline + void generateTextureMipsWithPipeline(const TexturePointer& destTexture, int numMips = -1); // Query Section void beginQuery(const QueryPointer& query); @@ -326,6 +328,7 @@ public: COMMAND_clearFramebuffer, COMMAND_blit, COMMAND_generateTextureMips, + COMMAND_generateTextureMipsWithPipeline, COMMAND_advance, diff --git a/libraries/gpu/src/gpu/MipGeneration.slh b/libraries/gpu/src/gpu/MipGeneration.slh new file mode 100644 index 0000000000..bc8dd39042 --- /dev/null +++ b/libraries/gpu/src/gpu/MipGeneration.slh @@ -0,0 +1,20 @@ + +<@if not MIP_GENERATION_SLH@> +<@def MIP_GENERATION_SLH@> + +<@include gpu/ShaderConstants.h@> + +layout(binding=GPU_TEXTURE_MIP_CREATION_INPUT) uniform sampler2D texMap; + +in vec2 varTexCoord0; + +<@endif@> \ No newline at end of file diff --git a/libraries/gpu/src/gpu/ShaderConstants.h b/libraries/gpu/src/gpu/ShaderConstants.h index 13dfd1be9c..0724b4eb40 100644 --- a/libraries/gpu/src/gpu/ShaderConstants.h +++ b/libraries/gpu/src/gpu/ShaderConstants.h @@ -21,6 +21,9 @@ #define GPU_TEXTURE_TRANSFORM_OBJECT 31 +// Mip creation +#define GPU_TEXTURE_MIP_CREATION_INPUT 30 + #define GPU_STORAGE_TRANSFORM_OBJECT 7 #define GPU_ATTR_POSITION 0 @@ -67,7 +70,8 @@ enum Buffer { namespace texture { enum Texture { ObjectTransforms = GPU_TEXTURE_TRANSFORM_OBJECT, -}; + MipCreationInput = GPU_TEXTURE_MIP_CREATION_INPUT, +}; } // namespace texture namespace storage { diff --git a/libraries/gpu/src/gpu/State.h b/libraries/gpu/src/gpu/State.h index 9bcd69dcdb..e68e829fb5 100755 --- a/libraries/gpu/src/gpu/State.h +++ b/libraries/gpu/src/gpu/State.h @@ -118,11 +118,13 @@ public: uint8 _function = LESS; uint8 _writeMask = true; uint8 _enabled = false; - uint8 _spare = 0; // _spare is here to to affect alignment +#if defined(__clang__) + __attribute__((unused)) +#endif + uint8 _spare = 0; // Padding public: DepthTest(bool enabled = false, bool writeMask = true, ComparisonFunction func = LESS) : _function(func), _writeMask(writeMask), _enabled(enabled) { - (void)_spare; // to avoid unusued variable warning } bool isEnabled() const { return _enabled != 0; } diff --git a/libraries/graphics/src/graphics/Material.h b/libraries/graphics/src/graphics/Material.h index 63481e0f5e..0db78ab349 100755 --- a/libraries/graphics/src/graphics/Material.h +++ b/libraries/graphics/src/graphics/Material.h @@ -320,7 +320,10 @@ public: float _scattering{ 0.0f }; // Scattering info - glm::vec2 _spare{ 0.0f }; +#if defined(__clang__) + __attribute__((unused)) +#endif + glm::vec2 _spare{ 0.0f }; // Padding uint32_t _key{ 0 }; // a copy of the materialKey diff --git a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h index ce2bea0853..b94acb8b71 100644 --- a/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h +++ b/libraries/input-plugins/src/input-plugins/KeyboardMouseDevice.h @@ -96,7 +96,6 @@ protected: class InputDevice : public controller::InputDevice { public: InputDevice() : controller::InputDevice("Keyboard") {} - virtual ~InputDevice() {} private: // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 4d6297303b..e96815d391 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -414,33 +414,13 @@ bool Geometry::areTexturesLoaded() const { if (!_areTexturesLoaded) { for (auto& material : _materials) { // Check if material textures are loaded - bool materialMissingTexture = std::any_of(material->_textures.cbegin(), material->_textures.cend(), - [](const NetworkMaterial::Textures::value_type& it) { - auto texture = it.texture; - if (!texture) { - return false; - } - // Failed texture downloads need to be considered as 'loaded' - // or the object will never fade in - bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined()); - if (!finished) { - return true; - } - return false; - }); + bool materialMissingTexture = material->isMissingTexture(); if (materialMissingTexture) { return false; } - // If material textures are loaded, check the material translucency - // FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap. - // However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail. - // Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now - const auto albedoTexture = material->_textures[NetworkMaterial::MapChannel::ALBEDO_MAP]; - if (albedoTexture.texture) { - material->resetOpacityMap(); - } + material->checkResetOpacityMap(); } _areTexturesLoaded = true; @@ -783,4 +763,31 @@ void NetworkMaterial::setTextures(const QVariantMap& textureMap) { } } +bool NetworkMaterial::isMissingTexture() { + for (auto& networkTexture : _textures) { + auto& texture = networkTexture.texture; + if (!texture) { + continue; + } + // Failed texture downloads need to be considered as 'loaded' + // or the object will never fade in + bool finished = texture->isFailed() || (texture->isLoaded() && texture->getGPUTexture() && texture->getGPUTexture()->isDefined()); + if (!finished) { + return true; + } + } + return false; +} + +void NetworkMaterial::checkResetOpacityMap() { + // If material textures are loaded, check the material translucency + // FIXME: This should not be done here. The opacity map should already be reset in Material::setTextureMap. + // However, currently that code can be called before the albedo map is defined, so resetOpacityMap will fail. + // Geometry::areTexturesLoaded() is called repeatedly until it returns true, so we do the check here for now + const auto& albedoTexture = _textures[NetworkMaterial::MapChannel::ALBEDO_MAP]; + if (albedoTexture.texture) { + resetOpacityMap(); + } +} + #include "ModelCache.moc" diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index dfe26788f2..5cbe96ea03 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -36,7 +36,7 @@ public: Geometry() = default; Geometry(const Geometry& geometry); - virtual ~Geometry() {} + virtual ~Geometry() = default; // Immutable over lifetime using GeometryMeshes = std::vector>; @@ -177,6 +177,9 @@ public: void setScatteringMap(const QUrl& url); void setLightmapMap(const QUrl& url); + bool isMissingTexture(); + void checkResetOpacityMap(); + protected: friend class Geometry; diff --git a/libraries/networking/src/BandwidthRecorder.cpp b/libraries/networking/src/BandwidthRecorder.cpp index 5ad3494017..80276dba5a 100644 --- a/libraries/networking/src/BandwidthRecorder.cpp +++ b/libraries/networking/src/BandwidthRecorder.cpp @@ -18,7 +18,7 @@ BandwidthRecorder::Channel::Channel() { } -float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { +float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() const { float averageTimeBetweenPackets = _input.getEventDeltaAverage(); if (averageTimeBetweenPackets > 0.0f) { return (1.0f / averageTimeBetweenPackets); @@ -26,7 +26,7 @@ float BandwidthRecorder::Channel::getAverageInputPacketsPerSecond() { return 0.0f; } -float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() { +float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() const { float averageTimeBetweenPackets = _output.getEventDeltaAverage(); if (averageTimeBetweenPackets > 0.0f) { return (1.0f / averageTimeBetweenPackets); @@ -34,11 +34,11 @@ float BandwidthRecorder::Channel::getAverageOutputPacketsPerSecond() { return 0.0f; } -float BandwidthRecorder::Channel::getAverageInputKilobitsPerSecond() { +float BandwidthRecorder::Channel::getAverageInputKilobitsPerSecond() const { return (_input.getAverageSampleValuePerSecond() * (8.0f / 1000)); } -float BandwidthRecorder::Channel::getAverageOutputKilobitsPerSecond() { +float BandwidthRecorder::Channel::getAverageOutputKilobitsPerSecond() const { return (_output.getAverageSampleValuePerSecond() * (8.0f / 1000)); } @@ -77,35 +77,35 @@ void BandwidthRecorder::updateOutboundData(const quint8 channelType, const int s _channels[channelType]->updateOutputAverage(sample); } -float BandwidthRecorder::getAverageInputPacketsPerSecond(const quint8 channelType) { +float BandwidthRecorder::getAverageInputPacketsPerSecond(const quint8 channelType) const { if (! _channels[channelType]) { return 0.0f; } return _channels[channelType]->getAverageInputPacketsPerSecond(); } -float BandwidthRecorder::getAverageOutputPacketsPerSecond(const quint8 channelType) { +float BandwidthRecorder::getAverageOutputPacketsPerSecond(const quint8 channelType) const { if (! _channels[channelType]) { return 0.0f; } return _channels[channelType]->getAverageOutputPacketsPerSecond(); } -float BandwidthRecorder::getAverageInputKilobitsPerSecond(const quint8 channelType) { +float BandwidthRecorder::getAverageInputKilobitsPerSecond(const quint8 channelType) const { if (! _channels[channelType]) { return 0.0f; } return _channels[channelType]->getAverageInputKilobitsPerSecond(); } -float BandwidthRecorder::getAverageOutputKilobitsPerSecond(const quint8 channelType) { +float BandwidthRecorder::getAverageOutputKilobitsPerSecond(const quint8 channelType) const { if (! _channels[channelType]) { return 0.0f; } return _channels[channelType]->getAverageOutputKilobitsPerSecond(); } -float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() { +float BandwidthRecorder::getTotalAverageInputPacketsPerSecond() const { float result = 0.0f; for (uint i=0; i #include -#include "BandwidthRecorder.h" #include "NetworkLogging.h" #include #include "NodeType.h" @@ -230,35 +229,18 @@ QDebug operator<<(QDebug debug, const NetworkPeer &peer) { return debug; } - -// FIXME this is a temporary implementation to determine if this is the right approach. -// If so, migrate the BandwidthRecorder into the NetworkPeer class -using BandwidthRecorderPtr = QSharedPointer; -static QHash PEER_BANDWIDTH; - -BandwidthRecorder& getBandwidthRecorder(const QUuid & uuid) { - if (!PEER_BANDWIDTH.count(uuid)) { - PEER_BANDWIDTH.insert(uuid, QSharedPointer::create()); - } - return *PEER_BANDWIDTH[uuid].data(); -} - void NetworkPeer::recordBytesSent(int count) const { - auto& bw = getBandwidthRecorder(_uuid); - bw.updateOutboundData(0, count); + _bandwidthRecorder.updateOutboundData(0, count); } void NetworkPeer::recordBytesReceived(int count) const { - auto& bw = getBandwidthRecorder(_uuid); - bw.updateInboundData(0, count); + _bandwidthRecorder.updateInboundData(0, count); } float NetworkPeer::getOutboundBandwidth() const { - auto& bw = getBandwidthRecorder(_uuid); - return bw.getAverageOutputKilobitsPerSecond(0); + return _bandwidthRecorder.getAverageOutputKilobitsPerSecond(0); } float NetworkPeer::getInboundBandwidth() const { - auto& bw = getBandwidthRecorder(_uuid); - return bw.getAverageInputKilobitsPerSecond(0); + return _bandwidthRecorder.getAverageInputKilobitsPerSecond(0); } diff --git a/libraries/networking/src/NetworkPeer.h b/libraries/networking/src/NetworkPeer.h index 462daa1ed2..4688498a96 100644 --- a/libraries/networking/src/NetworkPeer.h +++ b/libraries/networking/src/NetworkPeer.h @@ -18,8 +18,9 @@ #include #include -#include "UUID.h" +#include "BandwidthRecorder.h" #include "HifiSockAddr.h" +#include "UUID.h" const QString ICE_SERVER_HOSTNAME = "localhost"; const quint16 ICE_SERVER_DEFAULT_PORT = 7337; @@ -113,6 +114,8 @@ protected: HifiSockAddr _symmetricSocket; HifiSockAddr* _activeSocket; + mutable BandwidthRecorder _bandwidthRecorder; + quint64 _wakeTimestamp; std::atomic_ullong _lastHeardMicrostamp; diff --git a/libraries/networking/src/NodeList.cpp b/libraries/networking/src/NodeList.cpp index 917a4ca791..5e8909db2b 100644 --- a/libraries/networking/src/NodeList.cpp +++ b/libraries/networking/src/NodeList.cpp @@ -427,8 +427,10 @@ void NodeList::sendDomainServerCheckIn() { flagTimeForConnectionStep(LimitedNodeList::ConnectionStep::SendDSCheckIn); // Send duplicate check-ins in the exponentially increasing sequence 1, 1, 2, 4, ... + static const int MAX_CHECKINS_TOGETHER = 20; int outstandingCheckins = _domainHandler.getCheckInPacketsSinceLastReply(); int checkinCount = outstandingCheckins > 1 ? std::pow(2, outstandingCheckins - 2) : 1; + checkinCount = std::min(checkinCount, MAX_CHECKINS_TOGETHER); for (int i = 1; i < checkinCount; ++i) { auto packetCopy = domainPacket->createCopy(*domainPacket); sendPacket(std::move(packetCopy), _domainHandler.getSockAddr()); diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 7cd2330753..9eed463d2d 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) { case PacketType::EntityEdit: case PacketType::EntityData: case PacketType::EntityPhysics: - return static_cast(EntityVersion::ScriptGlmVectors); + return static_cast(EntityVersion::FixedLightSerialization); case PacketType::EntityQuery: return static_cast(EntityQueryPacketVersion::ConicalFrustums); case PacketType::AvatarIdentity: diff --git a/libraries/networking/src/udt/PacketHeaders.h b/libraries/networking/src/udt/PacketHeaders.h index c40ee69c08..37a4b32940 100644 --- a/libraries/networking/src/udt/PacketHeaders.h +++ b/libraries/networking/src/udt/PacketHeaders.h @@ -244,7 +244,8 @@ enum class EntityVersion : PacketVersion { ParticleSpin, BloomEffect, GrabProperties, - ScriptGlmVectors + ScriptGlmVectors, + FixedLightSerialization }; enum class EntityScriptCallMethodVersion : PacketVersion { diff --git a/libraries/networking/src/udt/Socket.cpp b/libraries/networking/src/udt/Socket.cpp index 44220df8f8..6de43219e5 100644 --- a/libraries/networking/src/udt/Socket.cpp +++ b/libraries/networking/src/udt/Socket.cpp @@ -37,7 +37,6 @@ Socket::Socket(QObject* parent, bool shouldChangeSocketOptions) : _shouldChangeSocketOptions(shouldChangeSocketOptions) { connect(&_udpSocket, &QUdpSocket::readyRead, this, &Socket::readPendingDatagrams); - connect(this, &Socket::pendingDatagrams, this, &Socket::processPendingDatagrams, Qt::QueuedConnection); // make sure we hear about errors and state changes from the underlying socket connect(&_udpSocket, SIGNAL(error(QAbstractSocket::SocketError)), @@ -316,85 +315,64 @@ void Socket::checkForReadyReadBackup() { } void Socket::readPendingDatagrams() { - int packetsRead = 0; - + using namespace std::chrono; + static const auto MAX_PROCESS_TIME { 100ms }; + const auto abortTime = system_clock::now() + MAX_PROCESS_TIME; int packetSizeWithHeader = -1; - // Max datagrams to read before processing: - static const int MAX_DATAGRAMS_CONSECUTIVELY = 10000; - while (_udpSocket.hasPendingDatagrams() - && (packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1 - && packetsRead <= MAX_DATAGRAMS_CONSECUTIVELY) { - // grab a time point we can mark as the receive time of this packet - auto receiveTime = p_high_resolution_clock::now(); - - // setup a buffer to read the packet into - auto buffer = std::unique_ptr(new char[packetSizeWithHeader]); - - QHostAddress senderAddress; - quint16 senderPort; - - // pull the datagram - auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, - &senderAddress, &senderPort); - - // we either didn't pull anything for this packet or there was an error reading (this seems to trigger - // on windows even if there's not a packet available) - if (sizeRead < 0) { - continue; + while (_udpSocket.hasPendingDatagrams() && + (packetSizeWithHeader = _udpSocket.pendingDatagramSize()) != -1) { + if (system_clock::now() > abortTime) { + // We've been running for too long, stop processing packets for now + // Once we've processed the event queue, we'll come back to packet processing + break; } - _incomingDatagrams.push_back({ senderAddress, senderPort, packetSizeWithHeader, - std::move(buffer), receiveTime }); - ++packetsRead; - - } - - if (packetsRead > _maxDatagramsRead) { - _maxDatagramsRead = packetsRead; - qCDebug(networking) << "readPendingDatagrams: Datagrams read:" << packetsRead; - } - emit pendingDatagrams(packetsRead); -} - -void Socket::processPendingDatagrams(int) { - // setup a HifiSockAddr to read into - HifiSockAddr senderSockAddr; - - while (!_incomingDatagrams.empty()) { - auto& datagram = _incomingDatagrams.front(); - senderSockAddr.setAddress(datagram._senderAddress); - senderSockAddr.setPort(datagram._senderPort); - int datagramSize = datagram._datagramLength; - auto receiveTime = datagram._receiveTime; - // we're reading a packet so re-start the readyRead backup timer _readyReadBackupTimer->start(); + // grab a time point we can mark as the receive time of this packet + auto receiveTime = p_high_resolution_clock::now(); + + // setup a HifiSockAddr to read into + HifiSockAddr senderSockAddr; + + // setup a buffer to read the packet into + auto buffer = std::unique_ptr(new char[packetSizeWithHeader]); + + // pull the datagram + auto sizeRead = _udpSocket.readDatagram(buffer.get(), packetSizeWithHeader, + senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); + // save information for this packet, in case it is the one that sticks readyRead - _lastPacketSizeRead = datagramSize; + _lastPacketSizeRead = sizeRead; _lastPacketSockAddr = senderSockAddr; - // Process unfiltered packets first. + if (sizeRead <= 0) { + // we either didn't pull anything for this packet or there was an error reading (this seems to trigger + // on windows even if there's not a packet available) + continue; + } + auto it = _unfilteredHandlers.find(senderSockAddr); + if (it != _unfilteredHandlers.end()) { - // we have a registered unfiltered handler for this HifiSockAddr (eg. STUN packet) - call that and return + // we have a registered unfiltered handler for this HifiSockAddr - call that and return if (it->second) { - auto basePacket = BasePacket::fromReceivedPacket(std::move(datagram._datagram), - datagramSize, senderSockAddr); + auto basePacket = BasePacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); basePacket->setReceiveTime(receiveTime); it->second(std::move(basePacket)); } - _incomingDatagrams.pop_front(); + continue; } // check if this was a control packet or a data packet - bool isControlPacket = *reinterpret_cast(datagram._datagram.get()) & CONTROL_BIT_MASK; + bool isControlPacket = *reinterpret_cast(buffer.get()) & CONTROL_BIT_MASK; if (isControlPacket) { // setup a control packet from the data we just read - auto controlPacket = ControlPacket::fromReceivedPacket(std::move(datagram._datagram), datagramSize, senderSockAddr); + auto controlPacket = ControlPacket::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); controlPacket->setReceiveTime(receiveTime); // move this control packet to the matching connection, if there is one @@ -406,13 +384,13 @@ void Socket::processPendingDatagrams(int) { } else { // setup a Packet from the data we just read - auto packet = Packet::fromReceivedPacket(std::move(datagram._datagram), datagramSize, senderSockAddr); + auto packet = Packet::fromReceivedPacket(std::move(buffer), packetSizeWithHeader, senderSockAddr); packet->setReceiveTime(receiveTime); // save the sequence number in case this is the packet that sticks readyRead _lastReceivedSequenceNumber = packet->getSequenceNumber(); - // call our hash verification operator to see if this packet is verified + // call our verification operator to see if this packet is verified if (!_packetFilterOperator || _packetFilterOperator(*packet)) { if (packet->isReliable()) { // if this was a reliable packet then signal the matching connection with the sequence number @@ -426,7 +404,6 @@ void Socket::processPendingDatagrams(int) { qCDebug(networking) << "Can't process packet: version" << (unsigned int)NLPacket::versionInHeader(*packet) << ", type" << NLPacket::typeInHeader(*packet); #endif - _incomingDatagrams.pop_front(); continue; } } @@ -442,8 +419,6 @@ void Socket::processPendingDatagrams(int) { } } } - - _incomingDatagrams.pop_front(); } } diff --git a/libraries/networking/src/udt/Socket.h b/libraries/networking/src/udt/Socket.h index ef4a457116..30058e1d23 100644 --- a/libraries/networking/src/udt/Socket.h +++ b/libraries/networking/src/udt/Socket.h @@ -95,7 +95,6 @@ public: signals: void clientHandshakeRequestComplete(const HifiSockAddr& sockAddr); - void pendingDatagrams(int datagramCount); public slots: void cleanupConnection(HifiSockAddr sockAddr); @@ -103,7 +102,6 @@ public slots: private slots: void readPendingDatagrams(); - void processPendingDatagrams(int datagramCount); void checkForReadyReadBackup(); void handleSocketError(QAbstractSocket::SocketError socketError); @@ -147,17 +145,6 @@ private: int _lastPacketSizeRead { 0 }; SequenceNumber _lastReceivedSequenceNumber; HifiSockAddr _lastPacketSockAddr; - - struct Datagram { - QHostAddress _senderAddress; - int _senderPort; - int _datagramLength; - std::unique_ptr _datagram; - p_high_resolution_clock::time_point _receiveTime; - }; - - std::list _incomingDatagrams; - int _maxDatagramsRead { 0 }; friend UDTTest; }; diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 8162bf4e18..c920665279 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -502,36 +502,18 @@ void EntityMotionState::sendBid(OctreeEditPacketSender* packetSender, uint32_t s properties.setVelocity(linearVelocity); properties.setAcceleration(_entity->getAcceleration()); properties.setAngularVelocity(angularVelocity); - if (_entity->dynamicDataNeedsTransmit()) { - _entity->setDynamicDataNeedsTransmit(false); - properties.setActionData(_entity->getDynamicData()); - } - - if (_entity->updateQueryAACube()) { - // due to parenting, the server may not know where something is in world-space, so include the bounding cube. - properties.setQueryAACube(_entity->getQueryAACube()); - } - - // set the LastEdited of the properties but NOT the entity itself - quint64 now = usecTimestampNow(); - properties.setLastEdited(now); // we don't own the simulation for this entity yet, but we're sending a bid for it + quint64 now = usecTimestampNow(); uint8_t finalBidPriority = computeFinalBidPriority(); - _entity->clearScriptSimulationPriority(); - properties.setSimulationOwner(Physics::getSessionUUID(), finalBidPriority); - _entity->setPendingOwnershipPriority(finalBidPriority); + _entity->prepareForSimulationOwnershipBid(properties, now, finalBidPriority); EntityTreeElementPointer element = _entity->getElement(); EntityTreePointer tree = element ? element->getTree() : nullptr; - properties.setClientOnly(_entity->getClientOnly()); - properties.setOwningAvatarID(_entity->getOwningAvatarID()); - EntityItemID id(_entity->getID()); EntityEditPacketSender* entityPacketSender = static_cast(packetSender); entityPacketSender->queueEditEntityMessage(PacketType::EntityPhysics, tree, id, properties); - _entity->setLastBroadcast(now); // for debug/physics status icons // NOTE: we don't descend to children for ownership bid. Instead, if we win ownership of the parent // then in sendUpdate() we'll walk descendents and send updates for their QueryAACubes if necessary. diff --git a/libraries/plugins/src/plugins/InputPlugin.h b/libraries/plugins/src/plugins/InputPlugin.h index 344f07d64c..23fbb6cac6 100644 --- a/libraries/plugins/src/plugins/InputPlugin.h +++ b/libraries/plugins/src/plugins/InputPlugin.h @@ -19,7 +19,6 @@ namespace controller { class InputPlugin : public Plugin { public: - virtual ~InputPlugin() {} virtual void pluginFocusOutEvent() = 0; virtual void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) = 0; diff --git a/libraries/pointers/src/Pick.h b/libraries/pointers/src/Pick.h index bde38575ee..9ca0f14c5f 100644 --- a/libraries/pointers/src/Pick.h +++ b/libraries/pointers/src/Pick.h @@ -109,7 +109,7 @@ class PickResult { public: PickResult() {} PickResult(const QVariantMap& pickVariant) : pickVariant(pickVariant) {} - virtual ~PickResult() {} + virtual ~PickResult() = default; virtual QVariantMap toVariantMap() const { return pickVariant; @@ -135,6 +135,7 @@ class PickQuery : protected ReadWriteLockable { Q_GADGET public: PickQuery(const PickFilter& filter, const float maxDistance, const bool enabled); + virtual ~PickQuery() = default; /**jsdoc * Enum for different types of Picks and Pointers. @@ -145,9 +146,11 @@ public: * @hifi-interface * @hifi-client-entity * - * @property {number} Ray Ray Picks intersect a ray with the nearest object in front of them, along a given direction. - * @property {number} Stylus Stylus Picks provide "tapping" functionality on/into flat surfaces. - * @property {number} Parabola Parabola Picks intersect a parabola with the nearest object in front of them, with a given initial velocity and acceleration. + * @property {number} Ray Ray picks intersect a ray with the nearest object in front of them, along a given direction. + * @property {number} Stylus Stylus picks provide "tapping" functionality on/into flat surfaces. + * @property {number} Parabola Parabola picks intersect a parabola with the nearest object in front of them, with a given + * initial velocity and acceleration. + * @property {number} Collision Collision picks intersect a collision volume with avatars and entities that have collisions. */ /**jsdoc * @@ -158,6 +161,7 @@ public: * * * + * * *
{@link PickType(0)|PickType.Ray}
{@link PickType(0)|PickType.Stylus}
{@link PickType(0)|PickType.Parabola}
{@link PickType(0)|PickType.Collision}
* @typedef {number} PickType @@ -245,7 +249,6 @@ template class Pick : public PickQuery { public: Pick(const T& mathPick, const PickFilter& filter, const float maxDistance, const bool enabled) : PickQuery(filter, maxDistance, enabled), _mathPick(mathPick) {} - virtual ~Pick() {} virtual T getMathematicalPick() const = 0; virtual PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const = 0; diff --git a/libraries/pointers/src/PickManager.cpp b/libraries/pointers/src/PickManager.cpp index caa62f3397..d3326ea8b4 100644 --- a/libraries/pointers/src/PickManager.cpp +++ b/libraries/pointers/src/PickManager.cpp @@ -38,11 +38,11 @@ std::shared_ptr PickManager::findPick(unsigned int uid) const { void PickManager::removePick(unsigned int uid) { withWriteLock([&] { - auto type = _typeMap.find(uid); - if (type != _typeMap.end()) { - _picks[type->second].erase(uid); - _typeMap.erase(uid); - _totalPickCounts[type->second]--; + auto typeIt = _typeMap.find(uid); + if (typeIt != _typeMap.end()) { + _picks[typeIt->second].erase(uid); + _totalPickCounts[typeIt->second]--; + _typeMap.erase(typeIt); } }); } diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 8ea4cdcd60..81a017a46d 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -96,7 +96,7 @@ void CauterizedModel::createRenderItemSet() { shapeID++; } } - _blendshapeBuffersInitialized = true; + _blendshapeOffsetsInitialized = true; } else { Model::createRenderItemSet(); } @@ -175,7 +175,7 @@ void CauterizedModel::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (_blendshapeBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2fe811c97b..1215c9abea 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -2175,7 +2175,10 @@ public: bool isAntiAliased() const { return isFlag(IS_ANTIALIASED); } Flags _flags = 0; - short _spare = 0; +#if defined(__clang__) + __attribute__((unused)) +#endif + short _spare = 0; // Padding int getRaw() const { return *reinterpret_cast(this); } diff --git a/libraries/render-utils/src/HighlightEffect.cpp b/libraries/render-utils/src/HighlightEffect.cpp index 2e51013bc5..2d4aee7880 100644 --- a/libraries/render-utils/src/HighlightEffect.cpp +++ b/libraries/render-utils/src/HighlightEffect.cpp @@ -39,10 +39,10 @@ namespace gr { extern void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state); -HighlightRessources::HighlightRessources() { +HighlightResources::HighlightResources() { } -void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightResources::update(const gpu::FramebufferPointer& primaryFrameBuffer) { auto newFrameSize = glm::ivec2(primaryFrameBuffer->getSize()); // If the buffer size changed, we need to delete our FBOs and recreate them at the @@ -58,32 +58,37 @@ void HighlightRessources::update(const gpu::FramebufferPointer& primaryFrameBuff if (!_colorFrameBuffer) { allocateColorBuffer(primaryFrameBuffer); } + + // The primaryFrameBuffer render buffer can change + if (_colorFrameBuffer->getRenderBuffer(0) != primaryFrameBuffer->getRenderBuffer(0)) { + _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); + } } } -void HighlightRessources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightResources::allocateColorBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { _colorFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("primaryWithStencil")); _colorFrameBuffer->setRenderBuffer(0, primaryFrameBuffer->getRenderBuffer(0)); _colorFrameBuffer->setStencilBuffer(_depthStencilTexture, _depthStencilTexture->getTexelFormat()); } -void HighlightRessources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { +void HighlightResources::allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer) { auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); _depthStencilTexture = gpu::TexturePointer(gpu::Texture::createRenderBuffer(depthFormat, _frameSize.x, _frameSize.y)); _depthFrameBuffer = gpu::FramebufferPointer(gpu::Framebuffer::create("highlightDepth")); _depthFrameBuffer->setDepthStencilBuffer(_depthStencilTexture, depthFormat); } -gpu::FramebufferPointer HighlightRessources::getDepthFramebuffer() { +gpu::FramebufferPointer HighlightResources::getDepthFramebuffer() { assert(_depthFrameBuffer); return _depthFrameBuffer; } -gpu::TexturePointer HighlightRessources::getDepthTexture() { +gpu::TexturePointer HighlightResources::getDepthTexture() { return _depthStencilTexture; } -gpu::FramebufferPointer HighlightRessources::getColorFramebuffer() { +gpu::FramebufferPointer HighlightResources::getColorFramebuffer() { assert(_colorFrameBuffer); return _colorFrameBuffer; } @@ -97,25 +102,21 @@ float HighlightSharedParameters::getBlurPixelWidth(const render::HighlightStyle& } PrepareDrawHighlight::PrepareDrawHighlight() { - _ressources = std::make_shared(); + _resources = std::make_shared(); } void PrepareDrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { auto destinationFrameBuffer = inputs; - _ressources->update(destinationFrameBuffer); - outputs = _ressources; + _resources->update(destinationFrameBuffer); + outputs = _resources; } gpu::PipelinePointer DrawHighlightMask::_stencilMaskPipeline; gpu::PipelinePointer DrawHighlightMask::_stencilMaskFillPipeline; -DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex, - render::ShapePlumberPointer shapePlumber, HighlightSharedParametersPointer parameters) : - _highlightPassIndex{ highlightIndex }, - _shapePlumber { shapePlumber }, - _sharedParameters{ parameters } { -} +DrawHighlightMask::DrawHighlightMask(unsigned int highlightIndex, render::ShapePlumberPointer shapePlumber, + HighlightSharedParametersPointer parameters) : _highlightPassIndex(highlightIndex), _shapePlumber(shapePlumber), _sharedParameters(parameters) {} void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs) { assert(renderContext->args); @@ -126,13 +127,13 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c const int PARAMETERS_SLOT = 0; if (!_stencilMaskPipeline || !_stencilMaskFillPipeline) { - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + gpu::StatePointer state = std::make_shared(); state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_ZERO, gpu::State::STENCIL_OP_REPLACE)); + state->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); state->setColorWriteMask(false, false, false, false); state->setCullMode(gpu::State::CULL_FRONT); - gpu::StatePointer fillState = gpu::StatePointer(new gpu::State()); + gpu::StatePointer fillState = std::make_shared(); fillState->setDepthTest(false, false, gpu::LESS_EQUAL); fillState->setStencilTest(true, 0xFF, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_REPLACE)); fillState->setColorWriteMask(false, false, false, false); @@ -151,7 +152,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c auto highlightId = _sharedParameters->_highlightIds[_highlightPassIndex]; if (!inShapes.empty() && !render::HighlightStage::isIndexInvalid(highlightId)) { - auto ressources = inputs.get1(); + auto resources = inputs.get1(); auto& highlight = highlightStage->getHighlight(highlightId); RenderArgs* args = renderContext->args; @@ -165,15 +166,11 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c // while stereo is enabled triggers a warning gpu::doInBatch("DrawHighlightMask::run::begin", args->_context, [&](gpu::Batch& batch) { batch.enableStereo(false); - batch.setFramebuffer(ressources->getDepthFramebuffer()); + batch.setFramebuffer(resources->getDepthFramebuffer()); batch.clearDepthStencilFramebuffer(1.0f, 0); }); - glm::mat4 projMat; - Transform viewMat; const auto jitter = inputs.get2(); - args->getViewFrustum().evalProjectionMatrix(projMat); - args->getViewFrustum().evalViewTransform(viewMat); render::ItemBounds itemBounds; @@ -185,6 +182,10 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c auto maskDeformedDQPipeline = _shapePlumber->pickPipeline(args, defaultKeyBuilder.withDeformed().withDualQuatSkinned()); // Setup camera, projection and viewport for all items + glm::mat4 projMat; + Transform viewMat; + args->getViewFrustum().evalProjectionMatrix(projMat); + args->getViewFrustum().evalViewTransform(viewMat); batch.setViewportTransform(args->_viewport); batch.setProjectionTransform(projMat); batch.setProjectionJitter(jitter.x, jitter.y); @@ -233,7 +234,7 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c const auto securityMargin = 2.0f; const float blurPixelWidth = 2.0f * securityMargin * HighlightSharedParameters::getBlurPixelWidth(highlight._style, args->_viewport.w); - const auto framebufferSize = ressources->getSourceFrameSize(); + const auto framebufferSize = resources->getSourceFrameSize(); const glm::vec2 highlightWidth = { blurPixelWidth / framebufferSize.x, blurPixelWidth / framebufferSize.y }; if (highlightWidth != _outlineWidth.get()) { @@ -241,11 +242,6 @@ void DrawHighlightMask::run(const render::RenderContextPointer& renderContext, c } gpu::doInBatch("DrawHighlightMask::run::end", args->_context, [&](gpu::Batch& batch) { - // Setup camera, projection and viewport for all items - batch.setViewportTransform(args->_viewport); - batch.setProjectionTransform(projMat); - batch.setViewTransform(viewMat); - // Draw stencil mask with object bounding boxes auto stencilPipeline = highlight._style.isFilled() ? _stencilMaskFillPipeline : _stencilMaskPipeline; batch.setPipeline(stencilPipeline); @@ -264,15 +260,14 @@ gpu::PipelinePointer DrawHighlight::_pipeline; gpu::PipelinePointer DrawHighlight::_pipelineFilled; DrawHighlight::DrawHighlight(unsigned int highlightIndex, HighlightSharedParametersPointer parameters) : - _highlightPassIndex{ highlightIndex }, - _sharedParameters{ parameters } { + _highlightPassIndex(highlightIndex), _sharedParameters(parameters) { } void DrawHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& inputs) { auto highlightFrameBuffer = inputs.get1(); auto highlightRect = inputs.get3(); - if (highlightFrameBuffer && highlightRect.z>0 && highlightRect.w>0) { + if (highlightFrameBuffer && highlightRect.z > 0 && highlightRect.w > 0) { auto sceneDepthBuffer = inputs.get2(); const auto frameTransform = inputs.get0(); auto highlightedDepthTexture = highlightFrameBuffer->getDepthTexture(); @@ -334,10 +329,11 @@ void DrawHighlight::run(const render::RenderContextPointer& renderContext, const const gpu::PipelinePointer& DrawHighlight::getPipeline(const render::HighlightStyle& style) { if (!_pipeline) { - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + gpu::StatePointer state = std::make_shared(); state->setDepthTest(gpu::State::DepthTest(false, false)); state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); + state->setColorWriteMask(true, true, true, true); auto program = gpu::Shader::createProgram(shader::render_utils::program::highlight); _pipeline = gpu::Pipeline::create(program, state); @@ -364,10 +360,10 @@ void DebugHighlight::configure(const Config& config) { } void DebugHighlight::run(const render::RenderContextPointer& renderContext, const Inputs& input) { - const auto highlightRessources = input.get0(); + const auto highlightResources = input.get0(); const auto highlightRect = input.get1(); - if (_isDisplayEnabled && highlightRessources && highlightRect.z>0 && highlightRect.w>0) { + if (_isDisplayEnabled && highlightResources && highlightRect.z > 0 && highlightRect.w > 0) { assert(renderContext->args); assert(renderContext->args->hasViewFrustum()); RenderArgs* args = renderContext->args; @@ -376,7 +372,7 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons auto primaryFramebuffer = input.get3(); gpu::doInBatch("DebugHighlight::run", args->_context, [&](gpu::Batch& batch) { batch.setViewportTransform(args->_viewport); - batch.setFramebuffer(highlightRessources->getColorFramebuffer()); + batch.setFramebuffer(highlightResources->getColorFramebuffer()); const auto geometryBuffer = DependencyManager::get(); @@ -386,13 +382,13 @@ void DebugHighlight::run(const render::RenderContextPointer& renderContext, cons args->getViewFrustum().evalViewTransform(viewMat); batch.setProjectionTransform(projMat); batch.setProjectionJitter(jitter.x, jitter.y); - batch.setViewTransform(viewMat, true); + batch.setViewTransform(viewMat); batch.setModelTransform(Transform()); const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f); batch.setPipeline(getDepthPipeline()); - batch.setResourceTexture(0, highlightRessources->getDepthTexture()); + batch.setResourceTexture(0, highlightResources->getDepthTexture()); const glm::vec2 bottomLeft(-1.0f, -1.0f); const glm::vec2 topRight(1.0f, 1.0f); geometryBuffer->renderQuad(batch, bottomLeft, topRight, color, _geometryDepthId); @@ -415,6 +411,7 @@ void DebugHighlight::initializePipelines() { auto state = std::make_shared(); state->setDepthTest(gpu::State::DepthTest(false, false)); state->setStencilTest(true, 0, gpu::State::StencilTest(OUTLINE_STENCIL_MASK, 0xFF, gpu::EQUAL)); + state->setColorWriteMask(true, true, true, true); const auto vs = gpu::Shader::createVertex(shader::render_utils::vertex::debug_deferred_buffer); @@ -512,7 +509,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren const auto highlightSelectionNames = task.addJob("SelectionToHighlight", sharedParameters); // Prepare for highlight group rendering. - const auto highlightRessources = task.addJob("PrepareHighlight", primaryFramebuffer); + const auto highlightResources = task.addJob("PrepareHighlight", primaryFramebuffer); render::Varying highlight0Rect; for (auto i = 0; i < HighlightSharedParameters::MAX_PASS_COUNT; i++) { @@ -532,7 +529,7 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren stream << "HighlightMask" << i; name = stream.str(); } - const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightRessources, jitter).asVarying(); + const auto drawMaskInputs = DrawHighlightMask::Inputs(sortedBounds, highlightResources, jitter).asVarying(); const auto highlightedRect = task.addJob(name, drawMaskInputs, i, shapePlumber, sharedParameters); if (i == 0) { highlight0Rect = highlightedRect; @@ -544,12 +541,12 @@ void DrawHighlightTask::build(JobModel& task, const render::Varying& inputs, ren stream << "HighlightEffect" << i; name = stream.str(); } - const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightRessources, sceneFrameBuffer, highlightedRect, primaryFramebuffer).asVarying(); + const auto drawHighlightInputs = DrawHighlight::Inputs(deferredFrameTransform, highlightResources, sceneFrameBuffer, highlightedRect, primaryFramebuffer).asVarying(); task.addJob(name, drawHighlightInputs, i, sharedParameters); } // Debug highlight - const auto debugInputs = DebugHighlight::Inputs(highlightRessources, const_cast(highlight0Rect), jitter, primaryFramebuffer).asVarying(); + const auto debugInputs = DebugHighlight::Inputs(highlightResources, const_cast(highlight0Rect), jitter, primaryFramebuffer).asVarying(); task.addJob("HighlightDebug", debugInputs); } diff --git a/libraries/render-utils/src/HighlightEffect.h b/libraries/render-utils/src/HighlightEffect.h index 32668c1ab6..933503fdb5 100644 --- a/libraries/render-utils/src/HighlightEffect.h +++ b/libraries/render-utils/src/HighlightEffect.h @@ -19,9 +19,9 @@ #include "DeferredFramebuffer.h" #include "DeferredFrameTransform.h" -class HighlightRessources { +class HighlightResources { public: - HighlightRessources(); + HighlightResources(); gpu::FramebufferPointer getDepthFramebuffer(); gpu::TexturePointer getDepthTexture(); @@ -44,7 +44,7 @@ protected: void allocateDepthBuffer(const gpu::FramebufferPointer& primaryFrameBuffer); }; -using HighlightRessourcesPointer = std::shared_ptr; +using HighlightResourcesPointer = std::shared_ptr; class HighlightSharedParameters { public: @@ -65,7 +65,7 @@ using HighlightSharedParametersPointer = std::shared_ptr; PrepareDrawHighlight(); @@ -74,7 +74,7 @@ public: private: - HighlightRessourcesPointer _ressources; + HighlightResourcesPointer _resources; }; @@ -112,8 +112,7 @@ private: class DrawHighlightMask { public: - - using Inputs = render::VaryingSet3; + using Inputs = render::VaryingSet3; using Outputs = glm::ivec4; using JobModel = render::Job::ModelIO; @@ -122,7 +121,6 @@ public: void run(const render::RenderContextPointer& renderContext, const Inputs& inputs, Outputs& outputs); protected: - unsigned int _highlightPassIndex; render::ShapePlumberPointer _shapePlumber; HighlightSharedParametersPointer _sharedParameters; @@ -136,7 +134,7 @@ protected: class DrawHighlight { public: - using Inputs = render::VaryingSet5; + using Inputs = render::VaryingSet5; using Config = render::Job::Config; using JobModel = render::Job::ModelI; @@ -163,11 +161,10 @@ private: class DebugHighlightConfig : public render::Job::Config { Q_OBJECT - Q_PROPERTY(bool viewMask MEMBER viewMask NOTIFY dirty) + Q_PROPERTY(bool viewMask MEMBER viewMask NOTIFY dirty) public: - - bool viewMask{ false }; + bool viewMask { false }; signals: void dirty(); @@ -175,7 +172,7 @@ signals: class DebugHighlight { public: - using Inputs = render::VaryingSet4; + using Inputs = render::VaryingSet4; using Config = DebugHighlightConfig; using JobModel = render::Job::ModelI; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index c5df2c3e01..2fe0368db2 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -209,6 +209,7 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in bool useDualQuaternionSkinning = model->getUseDualQuaternionSkinning(); auto& modelMesh = model->getGeometry()->getMeshes().at(_meshIndex); + _meshNumVertices = (int)modelMesh->getNumVertices(); const Model::MeshState& state = model->getMeshState(_meshIndex); updateMeshPart(modelMesh, partIndex); @@ -238,19 +239,12 @@ ModelMeshPartPayload::ModelMeshPartPayload(ModelPointer model, int meshIndex, in initCache(model); - if (_isBlendShaped) { - auto buffer = model->_blendshapeBuffers.find(meshIndex); - if (buffer != model->_blendshapeBuffers.end()) { - _blendshapeBuffer = buffer->second; - } - } - #ifdef Q_OS_MAC - // On mac AMD, we specifically need to have a _blendshapeBuffer bound when using a deformed mesh pipeline + // On mac AMD, we specifically need to have a _meshBlendshapeBuffer bound when using a deformed mesh pipeline // it cannot be null otherwise we crash in the drawcall using a deformed pipeline with a skinned only (not blendshaped) mesh - if ((_isBlendShaped || _isSkinned) && !_blendshapeBuffer) { + if ((_isBlendShaped || _isSkinned)) { glm::vec4 data; - _blendshapeBuffer = std::make_shared(sizeof(glm::vec4), reinterpret_cast(&data)); + _meshBlendshapeBuffer = std::make_shared(sizeof(glm::vec4), reinterpret_cast(&data)); } #endif @@ -292,8 +286,7 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector& clu if (!_clusterBuffer) { _clusterBuffer = std::make_shared(clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) clusterMatrices.data()); - } - else { + } else { _clusterBuffer->setSubData(0, clusterMatrices.size() * sizeof(glm::mat4), (const gpu::Byte*) clusterMatrices.data()); } @@ -313,8 +306,7 @@ void ModelMeshPartPayload::updateClusterBuffer(const std::vector(clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion), (const gpu::Byte*) clusterDualQuaternions.data()); - } - else { + } else { _clusterBuffer->setSubData(0, clusterDualQuaternions.size() * sizeof(Model::TransformDualQuaternion), (const gpu::Byte*) clusterDualQuaternions.data()); } @@ -403,8 +395,8 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) { batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0); batch.setInputFormat((_drawMesh->getVertexFormat())); - if (_blendshapeBuffer) { - batch.setResourceBuffer(0, _blendshapeBuffer); + if (_meshBlendshapeBuffer) { + batch.setResourceBuffer(0, _meshBlendshapeBuffer); } batch.setInputStream(0, _drawMesh->getVertexStream()); } @@ -431,7 +423,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) { bindMesh(batch); // IF deformed pass the mesh key - auto drawcallInfo = (uint16_t) (((_isBlendShaped && args->_enableBlendshape) << 0) | ((_isSkinned && args->_enableSkinning) << 1)); + auto drawcallInfo = (uint16_t) (((_isBlendShaped && _meshBlendshapeBuffer && args->_enableBlendshape) << 0) | ((_isSkinned && args->_enableSkinning) << 1)); if (drawcallInfo) { batch.setDrawcallUniform(drawcallInfo); } @@ -483,3 +475,12 @@ void ModelMeshPartPayload::computeAdjustedLocalBound(const std::vector& blendshapeBuffers, const QVector& blendedMeshSizes) { + if (_meshIndex < blendedMeshSizes.length() && blendedMeshSizes.at(_meshIndex) == _meshNumVertices) { + auto blendshapeBuffer = blendshapeBuffers.find(_meshIndex); + if (blendshapeBuffer != blendshapeBuffers.end()) { + _meshBlendshapeBuffer = blendshapeBuffer->second; + } + } +} diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index ceed4b330b..29c0091f11 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -26,10 +26,9 @@ class Model; class MeshPartPayload { public: - - MeshPartPayload() {} + MeshPartPayload() = default; MeshPartPayload(const std::shared_ptr& mesh, int partIndex, graphics::MaterialPointer material); - virtual ~MeshPartPayload() {} + virtual ~MeshPartPayload() = default; typedef render::Payload Payload; typedef Payload::DataPointer Pointer; @@ -134,10 +133,13 @@ public: bool _isBlendShaped { false }; bool _hasTangents { false }; + void setBlendshapeBuffer(const std::unordered_map& blendshapeBuffers, const QVector& blendedMeshSizes); + private: void initCache(const ModelPointer& model); - gpu::BufferPointer _blendshapeBuffer; + gpu::BufferPointer _meshBlendshapeBuffer; + int _meshNumVertices; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; }; diff --git a/libraries/render-utils/src/MetaModelPayload.cpp b/libraries/render-utils/src/MetaModelPayload.cpp new file mode 100644 index 0000000000..510972d86a --- /dev/null +++ b/libraries/render-utils/src/MetaModelPayload.cpp @@ -0,0 +1,55 @@ +// +// MetaModelPayload.cpp +// +// Created by Sam Gondelman on 10/9/18. +// Copyright 2018 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 "MetaModelPayload.h" + +#include "AbstractViewStateInterface.h" +#include "MeshPartPayload.h" + +void MetaModelPayload::setBlendedVertices(int blendNumber, const QVector& blendshapeOffsets, const QVector& blendedMeshSizes, const render::ItemIDs& subRenderItems) { + PROFILE_RANGE(render, __FUNCTION__); + if (blendNumber < _appliedBlendNumber) { + return; + } + _appliedBlendNumber = blendNumber; + + // We have fewer meshes than before. Invalidate everything + if (blendedMeshSizes.length() < (int)_blendshapeBuffers.size()) { + _blendshapeBuffers.clear(); + } + + int index = 0; + for (int i = 0; i < blendedMeshSizes.size(); i++) { + int numVertices = blendedMeshSizes.at(i); + + // This mesh isn't blendshaped + if (numVertices == 0) { + _blendshapeBuffers.erase(i); + continue; + } + + const auto& buffer = _blendshapeBuffers.find(i); + const auto blendShapeBufferSize = numVertices * sizeof(BlendshapeOffset); + if (buffer == _blendshapeBuffers.end()) { + _blendshapeBuffers[i] = std::make_shared(blendShapeBufferSize, (gpu::Byte*) blendshapeOffsets.constData() + index * sizeof(BlendshapeOffset), blendShapeBufferSize); + } else { + buffer->second->setData(blendShapeBufferSize, (gpu::Byte*) blendshapeOffsets.constData() + index * sizeof(BlendshapeOffset)); + } + + index += numVertices; + } + + render::Transaction transaction; + for (auto& id : subRenderItems) { + transaction.updateItem(id, [this, blendedMeshSizes](ModelMeshPartPayload& data) { + data.setBlendshapeBuffer(_blendshapeBuffers, blendedMeshSizes); + }); + } + AbstractViewStateInterface::instance()->getMain3DScene()->enqueueTransaction(transaction); +} diff --git a/libraries/render-utils/src/MetaModelPayload.h b/libraries/render-utils/src/MetaModelPayload.h new file mode 100644 index 0000000000..83731f3039 --- /dev/null +++ b/libraries/render-utils/src/MetaModelPayload.h @@ -0,0 +1,30 @@ +// +// MetaModelPayload.h +// +// Created by Sam Gondelman on 10/9/18. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_MetaModelPayload_h +#define hifi_MetaModelPayload_h + +#include + +#include "Model.h" + +#include "gpu/Buffer.h" + +class MetaModelPayload { +public: + void setBlendedVertices(int blendNumber, const QVector& blendshapeOffsets, const QVector& blendedMeshSizes, const render::ItemIDs& subRenderItems); + +private: + std::unordered_map _blendshapeBuffers; + int _appliedBlendNumber { 0 }; + +}; + +#endif \ No newline at end of file diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index a700c200f8..53009e8bfa 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -62,8 +62,6 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : _snapModelToRegistrationPoint(false), _snappedToRegistrationPoint(false), _url(HTTP_INVALID_COM), - _blendNumber(0), - _appliedBlendNumber(0), _isWireframe(false), _renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build()) { @@ -311,7 +309,7 @@ bool Model::updateGeometry() { initializeBlendshapes(mesh, i); i++; } - _blendshapeBuffersInitialized = true; + _blendshapeOffsetsInitialized = true; needFullUpdate = true; emit rigReady(); } @@ -979,7 +977,8 @@ const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { bool Model::addToScene(const render::ScenePointer& scene, render::Transaction& transaction, - render::Item::Status::Getters& statusGetters) { + render::Item::Status::Getters& statusGetters, + BlendShapeOperator modelBlendshapeOperator) { if (!_addedToScene && isLoaded()) { updateClusterMatrices(); if (_modelMeshRenderItems.empty()) { @@ -987,10 +986,11 @@ bool Model::addToScene(const render::ScenePointer& scene, } } + _modelBlendshapeOperator = modelBlendshapeOperator; + bool somethingAdded = false; if (_modelMeshRenderItemsMap.empty()) { - bool hasTransparent = false; size_t verticesCount = 0; foreach(auto renderItem, _modelMeshRenderItems) { @@ -1032,9 +1032,8 @@ void Model::removeFromScene(const render::ScenePointer& scene, render::Transacti _modelMeshMaterialNames.clear(); _modelMeshRenderItemShapes.clear(); - _blendshapeBuffers.clear(); _blendshapeOffsets.clear(); - _blendshapeBuffersInitialized = false; + _blendshapeOffsetsInitialized = false; _addedToScene = false; @@ -1437,7 +1436,7 @@ void Model::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (_blendshapeBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } @@ -1445,9 +1444,8 @@ void Model::updateClusterMatrices() { void Model::deleteGeometry() { _deleteGeometryCounter++; - _blendshapeBuffers.clear(); _blendshapeOffsets.clear(); - _blendshapeBuffersInitialized = false; + _blendshapeOffsetsInitialized = false; _meshStates.clear(); _rig.destroyAnimGraph(); _blendedBlendshapeCoefficients.clear(); @@ -1525,7 +1523,7 @@ void Model::createRenderItemSet() { shapeID++; } } - _blendshapeBuffersInitialized = true; + _blendshapeOffsetsInitialized = true; } bool Model::isRenderable() const { @@ -1654,6 +1652,7 @@ Blender::Blender(ModelPointer model, int blendNumber, const Geometry::WeakPointe void Blender::run() { QVector blendshapeOffsets; + QVector blendedMeshSizes; if (_model && _model->isLoaded()) { DETAILED_PROFILE_RANGE_EX(simulation_animation, __FUNCTION__, 0xFFFF0000, 0, { { "url", _model->getURL().toString() } }); int offset = 0; @@ -1662,12 +1661,22 @@ void Blender::run() { foreach(const FBXMesh& mesh, meshes) { auto modelMeshBlendshapeOffsets = _model->_blendshapeOffsets.find(meshIndex++); if (mesh.blendshapes.isEmpty() || modelMeshBlendshapeOffsets == _model->_blendshapeOffsets.end()) { + // Not blendshaped or not initialized + blendedMeshSizes.push_back(0); + continue; + } + + if (mesh.vertices.size() != modelMeshBlendshapeOffsets->second.size()) { + // Mesh sizes don't match. Something has gone wrong + blendedMeshSizes.push_back(0); continue; } blendshapeOffsets += modelMeshBlendshapeOffsets->second; BlendshapeOffset* meshBlendshapeOffsets = blendshapeOffsets.data() + offset; - offset += modelMeshBlendshapeOffsets->second.size(); + int numVertices = modelMeshBlendshapeOffsets->second.size(); + blendedMeshSizes.push_back(numVertices); + offset += numVertices; std::vector unpackedBlendshapeOffsets(modelMeshBlendshapeOffsets->second.size()); const float NORMAL_COEFFICIENT_SCALE = 0.01f; @@ -1711,7 +1720,7 @@ void Blender::run() { } // post the result to the ModelBlender, which will dispatch to the model if still alive QMetaObject::invokeMethod(DependencyManager::get().data(), "setBlendedVertices", - Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(QVector, blendshapeOffsets)); + Q_ARG(ModelPointer, _model), Q_ARG(int, _blendNumber), Q_ARG(QVector, blendshapeOffsets), Q_ARG(QVector, blendedMeshSizes)); } bool Model::maybeStartBlender() { @@ -1722,43 +1731,18 @@ bool Model::maybeStartBlender() { return false; } -void Model::setBlendedVertices(int blendNumber, const QVector& blendshapeOffsets) { - PROFILE_RANGE(render, __FUNCTION__); - if (!isLoaded() || blendNumber < _appliedBlendNumber || !_blendshapeBuffersInitialized) { - return; - } - _appliedBlendNumber = blendNumber; - const FBXGeometry& fbxGeometry = getFBXGeometry(); - int index = 0; - for (int i = 0; i < fbxGeometry.meshes.size(); i++) { - const FBXMesh& mesh = fbxGeometry.meshes.at(i); - auto meshBlendshapeOffsets = _blendshapeOffsets.find(i); - const auto& buffer = _blendshapeBuffers.find(i); - if (mesh.blendshapes.isEmpty() || meshBlendshapeOffsets == _blendshapeOffsets.end() || buffer == _blendshapeBuffers.end()) { - continue; - } - - const auto blendshapeOffsetSize = meshBlendshapeOffsets->second.size() * sizeof(BlendshapeOffset); - buffer->second->setSubData(0, blendshapeOffsetSize, (gpu::Byte*) blendshapeOffsets.constData() + index * sizeof(BlendshapeOffset)); - - index += meshBlendshapeOffsets->second.size(); - } -} - void Model::initializeBlendshapes(const FBXMesh& mesh, int index) { if (mesh.blendshapes.empty()) { // mesh doesn't have blendshape, did we allocate one though ? - if (_blendshapeBuffers.find(index) != _blendshapeBuffers.end()) { - qWarning() << "Mesh does not have Blendshape yet a blendshapeOffset buffer is allocated ?"; + if (_blendshapeOffsets.find(index) != _blendshapeOffsets.end()) { + qWarning() << "Mesh does not have Blendshape yet the blendshapeOffsets are allocated ?"; } return; } // Mesh has blendshape, let s allocate the local buffer if not done yet - if (_blendshapeBuffers.find(index) == _blendshapeBuffers.end()) { + if (_blendshapeOffsets.find(index) == _blendshapeOffsets.end()) { QVector blendshapeOffset; blendshapeOffset.fill(BlendshapeOffset(), mesh.vertices.size()); - const auto blendshapeOffsetsSize = blendshapeOffset.size() * sizeof(BlendshapeOffset); - _blendshapeBuffers[index] = std::make_shared(blendshapeOffsetsSize, (const gpu::Byte*) blendshapeOffset.constData(), blendshapeOffsetsSize); _blendshapeOffsets[index] = blendshapeOffset; } } @@ -1791,10 +1775,14 @@ void ModelBlender::noteRequiresBlend(ModelPointer model) { } } -void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, QVector blendshapeOffsets) { +void ModelBlender::setBlendedVertices(ModelPointer model, int blendNumber, QVector blendshapeOffsets, QVector blendedMeshSizes) { if (model) { - model->setBlendedVertices(blendNumber, blendshapeOffsets); + auto blendshapeOperator = model->getModelBlendshapeOperator(); + if (blendshapeOperator) { + blendshapeOperator(blendNumber, blendshapeOffsets, blendedMeshSizes, model->fetchRenderItemIDs()); + } } + { Lock lock(_mutex); _pendingBlenders--; diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e42da4ecb1..71809821eb 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -86,6 +86,7 @@ struct BlendshapeOffsetUnpacked { }; using BlendshapeOffset = BlendshapeOffsetPacked; +using BlendShapeOperator = std::function&, const QVector&, const render::ItemIDs&)>; /// A generic 3D model displaying geometry loaded from a URL. class Model : public QObject, public std::enable_shared_from_this, public scriptable::ModelProvider { @@ -141,7 +142,14 @@ public: } bool addToScene(const render::ScenePointer& scene, render::Transaction& transaction, - render::Item::Status::Getters& statusGetters); + BlendShapeOperator modelBlendshapeOperator) { + auto getters = render::Item::Status::Getters(0); + return addToScene(scene, transaction, getters, modelBlendshapeOperator); + } + bool addToScene(const render::ScenePointer& scene, + render::Transaction& transaction, + render::Item::Status::Getters& statusGetters, + BlendShapeOperator modelBlendshapeOperator = nullptr); void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction); bool isRenderable() const; @@ -155,9 +163,6 @@ public: bool maybeStartBlender(); - /// Sets blended vertices computed in a separate thread. - void setBlendedVertices(int blendNumber, const QVector& blendshapeOffsets); - bool isLoaded() const { return (bool)_renderGeometry && _renderGeometry->isGeometryLoaded(); } bool isAddedToScene() const { return _addedToScene; } @@ -339,6 +344,7 @@ public: uint32_t getGeometryCounter() const { return _deleteGeometryCounter; } const QMap& getRenderItems() const { return _modelMeshRenderItemsMap; } + BlendShapeOperator getModelBlendshapeOperator() const { return _modelBlendshapeOperator; } void renderDebugMeshBoxes(gpu::Batch& batch); @@ -432,18 +438,13 @@ protected: virtual void deleteGeometry(); - QVector _blendshapeCoefficients; - QUrl _url; - std::unordered_map _blendshapeBuffers; - bool _blendshapeBuffersInitialized{ false }; - - QVector>> _dilatedTextures; - + BlendShapeOperator _modelBlendshapeOperator { nullptr }; + QVector _blendshapeCoefficients; QVector _blendedBlendshapeCoefficients; - int _blendNumber; - int _appliedBlendNumber; + int _blendNumber { 0 }; + bool _blendshapeOffsetsInitialized { false }; mutable QMutex _mutex{ QMutex::Recursive }; @@ -460,7 +461,6 @@ protected: // debug rendering support int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID; - static AbstractViewStateInterface* _viewState; QVector> _modelMeshRenderItems; @@ -533,7 +533,7 @@ public: bool shouldComputeBlendshapes() { return _computeBlendshapes; } public slots: - void setBlendedVertices(ModelPointer model, int blendNumber, QVector blendshapeOffsets); + void setBlendedVertices(ModelPointer model, int blendNumber, QVector blendshapeOffsets, QVector blendedMeshSizes); void setComputeBlendshapes(bool computeBlendshapes) { _computeBlendshapes = computeBlendshapes; } private: diff --git a/libraries/render-utils/src/SoftAttachmentModel.cpp b/libraries/render-utils/src/SoftAttachmentModel.cpp index 114ccab712..90015768d0 100644 --- a/libraries/render-utils/src/SoftAttachmentModel.cpp +++ b/libraries/render-utils/src/SoftAttachmentModel.cpp @@ -78,7 +78,7 @@ void SoftAttachmentModel::updateClusterMatrices() { // post the blender if we're not currently waiting for one to finish auto modelBlender = DependencyManager::get(); - if (_blendshapeBuffersInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { + if (_blendshapeOffsetsInitialized && modelBlender->shouldComputeBlendshapes() && geometry.hasBlendedMeshes() && _blendshapeCoefficients != _blendedBlendshapeCoefficients) { _blendedBlendshapeCoefficients = _blendshapeCoefficients; modelBlender->noteRequiresBlend(getThisPointer()); } diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index 88e85c604a..a87e2031f9 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -531,7 +531,7 @@ public: typedef UpdateFunctor Updater; Payload(const DataPointer& data) : _data(data) {} - virtual ~Payload() {} + virtual ~Payload() = default; // Payload general interface virtual const ItemKey getKey() const override { return payloadGetKey(_data); } diff --git a/libraries/shared/src/AtRestDetector.cpp b/libraries/shared/src/AtRestDetector.cpp index 4c08b30dcd..4b4356d641 100644 --- a/libraries/shared/src/AtRestDetector.cpp +++ b/libraries/shared/src/AtRestDetector.cpp @@ -30,32 +30,37 @@ void AtRestDetector::reset(const glm::vec3& startPosition, const glm::quat& star _isAtRest = false; } -bool AtRestDetector::update(const glm::vec3& position, const glm::quat& rotation) { - uint64_t now = usecTimestampNow(); - float dt = (float)(now - _lastUpdateTime) / (float)USECS_PER_SECOND; - _lastUpdateTime = now; - const float TAU = 1.0f; - float delta = glm::min(dt / TAU, 1.0f); +void AtRestDetector::update(const glm::vec3& position, const glm::quat& rotation) { + _lastIsAtRest = _isAtRest; + if (_isValid) { + uint64_t now = usecTimestampNow(); + float dt = (float)(now - _lastUpdateTime) / (float)USECS_PER_SECOND; + _lastUpdateTime = now; + const float TAU = 1.0f; + float delta = glm::min(dt / TAU, 1.0f); - // keep a running average of position. - _positionAverage = position * delta + _positionAverage * (1 - delta); + // keep a running average of position. + _positionAverage = position * delta + _positionAverage * (1 - delta); - // keep a running average of position variances. - glm::vec3 dx = position - _positionAverage; - _positionVariance = glm::dot(dx, dx) * delta + _positionVariance * (1 - delta); + // keep a running average of position variances. + glm::vec3 dx = position - _positionAverage; + _positionVariance = glm::dot(dx, dx) * delta + _positionVariance * (1 - delta); - // keep a running average of quaternion logarithms. - glm::quat quatLogAsQuat = glm::log(rotation); - glm::vec3 quatLog(quatLogAsQuat.x, quatLogAsQuat.y, quatLogAsQuat.z); - _quatLogAverage = quatLog * delta + _quatLogAverage * (1 - delta); + // keep a running average of quaternion logarithms. + glm::quat quatLogAsQuat = glm::log(rotation); + glm::vec3 quatLog(quatLogAsQuat.x, quatLogAsQuat.y, quatLogAsQuat.z); + _quatLogAverage = quatLog * delta + _quatLogAverage * (1 - delta); - // keep a running average of quatLog variances. - glm::vec3 dql = quatLog - _quatLogAverage; - _quatLogVariance = glm::dot(dql, dql) * delta + _quatLogVariance * (1 - delta); + // keep a running average of quatLog variances. + glm::vec3 dql = quatLog - _quatLogAverage; + _quatLogVariance = glm::dot(dql, dql) * delta + _quatLogVariance * (1 - delta); - const float POSITION_VARIANCE_THRESHOLD = 0.001f; - const float QUAT_LOG_VARIANCE_THRESHOLD = 0.00002f; + const float POSITION_VARIANCE_THRESHOLD = 0.001f; + const float QUAT_LOG_VARIANCE_THRESHOLD = 0.00002f; - _isAtRest = _positionVariance < POSITION_VARIANCE_THRESHOLD && _quatLogVariance < QUAT_LOG_VARIANCE_THRESHOLD; - return _isAtRest; + _isAtRest = _positionVariance < POSITION_VARIANCE_THRESHOLD && _quatLogVariance < QUAT_LOG_VARIANCE_THRESHOLD; + } else { + reset(position, rotation); + _isValid = true; + } } diff --git a/libraries/shared/src/AtRestDetector.h b/libraries/shared/src/AtRestDetector.h index 525156de65..eb8e5f53f9 100644 --- a/libraries/shared/src/AtRestDetector.h +++ b/libraries/shared/src/AtRestDetector.h @@ -17,21 +17,27 @@ class AtRestDetector { public: + AtRestDetector() {}; AtRestDetector(const glm::vec3& startPosition, const glm::quat& startRotation); void reset(const glm::vec3& startPosition, const glm::quat& startRotation); // returns true if object is at rest, dt in assumed to be seconds. - bool update(const glm::vec3& position, const glm::quat& startRotation); + void update(const glm::vec3& position, const glm::quat& startRotation); + void invalidate() { _isValid = false; } bool isAtRest() const { return _isAtRest; } + bool onRest() const { return !_lastIsAtRest && _isAtRest; } + bool onWake() const { return _lastIsAtRest && !_isAtRest; } protected: + bool _isValid { false }; glm::vec3 _positionAverage; glm::vec3 _quatLogAverage; uint64_t _lastUpdateTime { 0 }; float _positionVariance { 0.0f }; float _quatLogVariance { 0.0f }; bool _isAtRest { false }; + bool _lastIsAtRest { false }; }; #endif diff --git a/libraries/shared/src/NestableTransformNode.h b/libraries/shared/src/NestableTransformNode.h index 2f9bc2e985..be017a696d 100644 --- a/libraries/shared/src/NestableTransformNode.h +++ b/libraries/shared/src/NestableTransformNode.h @@ -56,4 +56,4 @@ public: NestableTransformNode(std::weak_ptr spatiallyNestable, int jointIndex) : BaseNestableTransformNode(spatiallyNestable, jointIndex) {}; }; -#endif // hifi_NestableTransformNode_h \ No newline at end of file +#endif // hifi_NestableTransformNode_h diff --git a/libraries/shared/src/PrioritySortUtil.h b/libraries/shared/src/PrioritySortUtil.h index 4a74c5d212..b11021c48f 100644 --- a/libraries/shared/src/PrioritySortUtil.h +++ b/libraries/shared/src/PrioritySortUtil.h @@ -29,7 +29,8 @@ namespace PrioritySortUtil { class Sortable { public: - virtual ~Sortable() {} + virtual ~Sortable() = default; + virtual glm::vec3 getPosition() const = 0; virtual float getRadius() const = 0; virtual uint64_t getTimestamp() const = 0; diff --git a/libraries/shared/src/TransformNode.h b/libraries/shared/src/TransformNode.h index 1c10bed1c0..c9340bddf0 100644 --- a/libraries/shared/src/TransformNode.h +++ b/libraries/shared/src/TransformNode.h @@ -12,7 +12,8 @@ class TransformNode { public: - virtual ~TransformNode() {} + virtual ~TransformNode() = default; + virtual Transform getTransform() = 0; }; diff --git a/libraries/task/src/task/Task.h b/libraries/task/src/task/Task.h index ee5483d5cb..e8e95b4df4 100644 --- a/libraries/task/src/task/Task.h +++ b/libraries/task/src/task/Task.h @@ -175,7 +175,7 @@ public: template using ModelIO = Model; Job(const ConceptPointer& concept) : _concept(concept) {} - virtual ~Job() {} + virtual ~Job() = default; const std::string& getName() const { return _concept->getName(); } const Varying getInput() const { return _concept->getInput(); } diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 74098f69c7..f67a356078 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -250,6 +250,7 @@ void OffscreenQmlSurface::initializeEngine(QQmlEngine* engine) { engine->setNetworkAccessManagerFactory(new QmlNetworkAccessManagerFactory); auto importList = engine->importPathList(); + importList.insert(importList.begin(), PathUtils::resourcesPath() + "qml/"); importList.insert(importList.begin(), PathUtils::resourcesPath()); engine->setImportPathList(importList); for (const auto& path : importList) { diff --git a/plugins/hifiNeuron/src/NeuronPlugin.h b/plugins/hifiNeuron/src/NeuronPlugin.h index c2909c54fb..c99908d5b7 100644 --- a/plugins/hifiNeuron/src/NeuronPlugin.h +++ b/plugins/hifiNeuron/src/NeuronPlugin.h @@ -52,6 +52,7 @@ protected: friend class NeuronPlugin; InputDevice() : controller::InputDevice("Neuron") {} + virtual ~InputDevice() = default; // Device functions virtual controller::Input::NamedVector getAvailableInputs() const override; diff --git a/scripts/developer/tests/ControlsGallery.qml b/scripts/developer/tests/ControlsGallery.qml index ceb8a26dc9..9685fa6fe8 100644 --- a/scripts/developer/tests/ControlsGallery.qml +++ b/scripts/developer/tests/ControlsGallery.qml @@ -2,16 +2,9 @@ import QtQuick 2.10 import QtQuick.Window 2.10 import QtQuick.Controls 2.2 import QtQuick.Layouts 1.3 -import "qrc:////qml//styles-uit" as HifiStylesUit -import "qrc:////qml//controls-uit" as HifiControlsUit -//uncomment to use from qmlscratch tool -//import '../../../interface/resources/qml/controls-uit' as HifiControlsUit -//import '../../../interface/resources/qml/styles-uit' - -//uncomment to use with HIFI_USE_SOURCE_TREE_RESOURCES=1 -//import '../../../resources/qml/controls-uit' as HifiControlsUit -//import '../../../resources/qml/styles-uit' +import stylesUit 1.0 as HifiStylesUit +import controlsUit 1.0 as HifiControlsUit Item { visible: true diff --git a/scripts/developer/utilities/audio/Stats.qml b/scripts/developer/utilities/audio/Stats.qml index f359e9b04c..e2291e485d 100644 --- a/scripts/developer/utilities/audio/Stats.qml +++ b/scripts/developer/utilities/audio/Stats.qml @@ -12,7 +12,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:////qml//controls-uit" as HifiControls +import controlsUit 1.0 as HifiControls Column { id: stats diff --git a/scripts/developer/utilities/audio/TabletStats.qml b/scripts/developer/utilities/audio/TabletStats.qml index 2f8d212a2a..b50acabec4 100644 --- a/scripts/developer/utilities/audio/TabletStats.qml +++ b/scripts/developer/utilities/audio/TabletStats.qml @@ -11,8 +11,7 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 - -import "qrc:////qml//styles-uit" +import stylesUit 1.0 Item { id: dialog diff --git a/scripts/developer/utilities/lib/jet/qml/TaskList.qml b/scripts/developer/utilities/lib/jet/qml/TaskList.qml index 5b1aa0afb5..166f604666 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskList.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskList.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../jet.js" as Jet diff --git a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml index 2c75865698..0f083aa72c 100644 --- a/scripts/developer/utilities/lib/jet/qml/TaskListView.qml +++ b/scripts/developer/utilities/lib/jet/qml/TaskListView.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../jet.js" as Jet diff --git a/scripts/developer/utilities/lib/plotperf/Color.qml b/scripts/developer/utilities/lib/plotperf/Color.qml index 15d7f9fcc9..1ad72fe2e6 100644 --- a/scripts/developer/utilities/lib/plotperf/Color.qml +++ b/scripts/developer/utilities/lib/plotperf/Color.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { diff --git a/scripts/developer/utilities/render/antialiasing.qml b/scripts/developer/utilities/render/antialiasing.qml index 1a8f9dac2d..5abfd30935 100644 --- a/scripts/developer/utilities/render/antialiasing.qml +++ b/scripts/developer/utilities/render/antialiasing.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "configSlider" import "../lib/plotperf" diff --git a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml index 41de77fb09..bf9089d82c 100644 --- a/scripts/developer/utilities/render/configSlider/ConfigSlider.qml +++ b/scripts/developer/utilities/render/configSlider/ConfigSlider.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { diff --git a/scripts/developer/utilities/render/configSlider/RichSlider.qml b/scripts/developer/utilities/render/configSlider/RichSlider.qml index 01b14f3d48..ff16cb32ad 100644 --- a/scripts/developer/utilities/render/configSlider/RichSlider.qml +++ b/scripts/developer/utilities/render/configSlider/RichSlider.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 as Original import QtQuick.Controls.Styles 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { diff --git a/scripts/developer/utilities/render/deferredLighting.qml b/scripts/developer/utilities/render/deferredLighting.qml index a9479b2935..64e00acdac 100644 --- a/scripts/developer/utilities/render/deferredLighting.qml +++ b/scripts/developer/utilities/render/deferredLighting.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "configSlider" import "../lib/jet/qml" as Jet diff --git a/scripts/developer/utilities/render/engineInspector.qml b/scripts/developer/utilities/render/engineInspector.qml index 1b9941e64e..16dd8eb985 100644 --- a/scripts/developer/utilities/render/engineInspector.qml +++ b/scripts/developer/utilities/render/engineInspector.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../lib/jet/qml" as Jet diff --git a/scripts/developer/utilities/render/highlight.qml b/scripts/developer/utilities/render/highlight.qml index 88d6a807ae..d8af2a828e 100644 --- a/scripts/developer/utilities/render/highlight.qml +++ b/scripts/developer/utilities/render/highlight.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "configSlider" import "../lib/plotperf" import "highlight" diff --git a/scripts/developer/utilities/render/highlight/HighlightStyle.qml b/scripts/developer/utilities/render/highlight/HighlightStyle.qml index 371b7e81f7..475aadfdce 100644 --- a/scripts/developer/utilities/render/highlight/HighlightStyle.qml +++ b/scripts/developer/utilities/render/highlight/HighlightStyle.qml @@ -12,8 +12,8 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import "../configSlider" import "../../lib/plotperf" -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls Item { id: root diff --git a/scripts/developer/utilities/render/lod.qml b/scripts/developer/utilities/render/lod.qml index 889d8db836..892b43d8be 100644 --- a/scripts/developer/utilities/render/lod.qml +++ b/scripts/developer/utilities/render/lod.qml @@ -11,8 +11,8 @@ import QtQuick 2.5 import QtQuick.Controls 1.4 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../lib/plotperf" import "configSlider" diff --git a/scripts/developer/utilities/render/shadow.qml b/scripts/developer/utilities/render/shadow.qml index 464fe00eb9..a1d6777a68 100644 --- a/scripts/developer/utilities/render/shadow.qml +++ b/scripts/developer/utilities/render/shadow.qml @@ -12,8 +12,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "configSlider" diff --git a/scripts/developer/utilities/render/transition.qml b/scripts/developer/utilities/render/transition.qml index f74468a273..c150c523f9 100644 --- a/scripts/developer/utilities/render/transition.qml +++ b/scripts/developer/utilities/render/transition.qml @@ -13,8 +13,8 @@ import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 import QtQuick.Dialogs 1.0 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "configSlider" import "../lib/plotperf" diff --git a/scripts/developer/utilities/workload/workloadInspector.qml b/scripts/developer/utilities/workload/workloadInspector.qml index 2eaa9d8133..746a572f29 100644 --- a/scripts/developer/utilities/workload/workloadInspector.qml +++ b/scripts/developer/utilities/workload/workloadInspector.qml @@ -11,8 +11,8 @@ import QtQuick 2.7 import QtQuick.Controls 1.4 import QtQuick.Layouts 1.3 -import "qrc:///qml/styles-uit" -import "qrc:///qml/controls-uit" as HifiControls +import stylesUit 1.0 +import controlsUit 1.0 as HifiControls import "../render/configSlider" import "../lib/jet/qml" as Jet import "../lib/plotperf" diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index 6181414084..efbca66d72 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -24,7 +24,7 @@ this.reticleMinY = MARGIN; this.reticleMaxY; this.parameters = ControllerDispatcherUtils.makeDispatcherModuleParameters( - 540, + 160, // Same as webSurfaceLaserInput. this.hand === RIGHT_HAND ? ["rightHand"] : ["leftHand"], [], 100, @@ -63,7 +63,6 @@ this.processLaser = function(controllerData) { var controllerLocation = controllerData.controllerLocations[this.hand]; - // var otherModuleRunning = this.getOtherModule().running; if ((controllerData.triggerValues[this.hand] < ControllerDispatcherUtils.TRIGGER_ON_VALUE || !controllerLocation.valid) || this.pointingAtTablet(controllerData)) { return false; diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 4b6eb7e313..1917505bd8 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -28,7 +28,7 @@ Script.include("/~/system/libraries/utils.js"); this.reticleMaxY = null; this.parameters = makeDispatcherModuleParameters( - 160, + 165, // Lower priority than webSurfaceLaserInput and hudOverlayPointer. this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"], [], 100, @@ -127,29 +127,41 @@ Script.include("/~/system/libraries/utils.js"); }; this.run = function(controllerData) { - var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightTabletStylusInput" : "LeftTabletStylusInput"); + var tabletStylusInput = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightTabletStylusInput" : "LeftTabletStylusInput"); if (tabletStylusInput) { var tabletReady = tabletStylusInput.isReady(controllerData); - if (tabletReady.active) { return this.exitModule(); } } - var overlayLaser = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); - if (overlayLaser) { - var overlayLaserReady = overlayLaser.isReady(controllerData); + var webLaser = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightWebSurfaceLaserInput" : "LeftWebSurfaceLaserInput"); + if (webLaser) { + var webLaserReady = webLaser.isReady(controllerData); var target = controllerData.rayPicks[this.hand].objectID; this.sendPointingAtData(controllerData); - if (overlayLaserReady.active && this.pointingAtTablet(target)) { + if (webLaserReady.active && this.pointingAtTablet(target)) { return this.exitModule(); } } - var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); + if (!controllerData.triggerClicks[this.hand]) { // Don't grab if trigger pressed when laser starts intersecting. + var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHudOverlayPointer" : "LeftHudOverlayPointer"); + if (hudLaser) { + var hudLaserReady = hudLaser.isReady(controllerData); + if (hudLaserReady.active) { + return this.exitModule(); + } + } + } + + var nearOverlay = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightNearParentingGrabOverlay" : "LeftNearParentingGrabOverlay"); if (nearOverlay) { var nearOverlayReady = nearOverlay.isReady(controllerData); - if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { return this.exitModule(); } diff --git a/scripts/system/controllers/controllerModules/inVREditMode.js b/scripts/system/controllers/controllerModules/inVREditMode.js index ef02e41ef3..65b6744646 100644 --- a/scripts/system/controllers/controllerModules/inVREditMode.js +++ b/scripts/system/controllers/controllerModules/inVREditMode.js @@ -19,12 +19,13 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); function InVREditMode(hand) { this.hand = hand; this.disableModules = false; - var NO_HAND_LASER = -1; // Invalid hand parameter so that default laser is not displayed. + this.running = false; + var NO_HAND_LASER = -1; // Invalid hand parameter so that standard laser is not displayed. this.parameters = makeDispatcherModuleParameters( - 200, // Not too high otherwise the tablet laser doesn't work. - this.hand === RIGHT_HAND ? - ["rightHand", "rightHandEquip", "rightHandTrigger"] : - ["leftHand", "leftHandEquip", "leftHandTrigger"], + 166, // Slightly lower priority than inEditMode. + this.hand === RIGHT_HAND + ? ["rightHand", "rightHandEquip", "rightHandTrigger"] + : ["leftHand", "leftHandEquip", "leftHandTrigger"], [], 100, makeLaserParams(NO_HAND_LASER, false) @@ -35,6 +36,35 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); (HMD.homeButtonID && objectID === HMD.homeButtonID); }; + // The Shapes app has a non-standard laser: in particular, the laser end dot displays on its own when the laser is + // pointing at the Shapes UI. The laser on/off is controlled by this module but the laser is implemented in the Shapes + // app. + // If, in the future, the Shapes app laser interaction is adopted as a standard UI style then the laser could be + // implemented in the controller modules along side the other laser styles. + var INVREDIT_MODULE_RUNNING = "Hifi-InVREdit-Module-Running"; + + this.runModule = function () { + if (!this.running) { + Messages.sendLocalMessage(INVREDIT_MODULE_RUNNING, JSON.stringify({ + hand: this.hand, + running: true + })); + this.running = true; + } + return makeRunningValues(true, [], []); + }; + + this.exitModule = function () { + if (this.running) { + Messages.sendLocalMessage(INVREDIT_MODULE_RUNNING, JSON.stringify({ + hand: this.hand, + running: false + })); + this.running = false; + } + return makeRunningValues(false, [], []); + }; + this.isReady = function (controllerData) { if (this.disableModules) { return makeRunningValues(true, [], []); @@ -45,7 +75,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); this.run = function (controllerData) { // Default behavior if disabling is not enabled. if (!this.disableModules) { - return makeRunningValues(false, [], []); + return this.exitModule(); } // Tablet stylus. @@ -55,7 +85,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (tabletStylusInput) { var tabletReady = tabletStylusInput.isReady(controllerData); if (tabletReady.active) { - return makeRunningValues(false, [], []); + return this.exitModule(); } } @@ -67,7 +97,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); var overlayLaserReady = overlayLaser.isReady(controllerData); var target = controllerData.rayPicks[this.hand].objectID; if (overlayLaserReady.active && this.pointingAtTablet(target)) { - return makeRunningValues(false, [], []); + return this.exitModule(); } } @@ -78,7 +108,20 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (nearOverlay) { var nearOverlayReady = nearOverlay.isReady(controllerData); if (nearOverlayReady.active && HMD.tabletID && nearOverlay.grabbedThingID === HMD.tabletID) { - return makeRunningValues(false, [], []); + return this.exitModule(); + } + } + + // HUD overlay. + if (!controllerData.triggerClicks[this.hand]) { + var hudLaser = getEnabledModuleByName(this.hand === RIGHT_HAND + ? "RightHudOverlayPointer" + : "LeftHudOverlayPointer"); + if (hudLaser) { + var hudLaserReady = hudLaser.isReady(controllerData); + if (hudLaserReady.active) { + return this.exitModule(); + } } } @@ -89,12 +132,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); if (teleporter) { var teleporterReady = teleporter.isReady(controllerData); if (teleporterReady.active) { - return makeRunningValues(false, [], []); + return this.exitModule(); } } // Other behaviors are disabled. - return makeRunningValues(true, [], []); + return this.runModule(); }; } diff --git a/scripts/system/edit.js b/scripts/system/edit.js index b4684a0fd4..1720cb8278 100644 --- a/scripts/system/edit.js +++ b/scripts/system/edit.js @@ -348,12 +348,12 @@ var toolBar = (function () { if (!properties.grab) { properties.grab = {}; - } - if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) && - !(properties.type === "Zone" || properties.type === "Light" || properties.type === "ParticleEffect")) { - properties.grab.grabbable = true; - } else { - properties.grab.grabbable = false; + if (Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE) && + !(properties.type === "Zone" || properties.type === "Light" || properties.type === "ParticleEffect")) { + properties.grab.grabbable = true; + } else { + properties.grab.grabbable = false; + } } SelectionManager.saveProperties(); @@ -442,9 +442,9 @@ var toolBar = (function () { function handleNewModelDialogResult(result) { if (result) { - var url = result.textInput; + var url = result.url; var shapeType; - switch (result.comboBox) { + switch (result.collisionShapeIndex) { case SHAPE_TYPE_SIMPLE_HULL: shapeType = "simple-hull"; break; @@ -464,7 +464,7 @@ var toolBar = (function () { shapeType = "none"; } - var dynamic = result.checkBox !== null ? result.checkBox : DYNAMIC_DEFAULT; + var dynamic = result.dynamic !== null ? result.dynamic : DYNAMIC_DEFAULT; if (shapeType === "static-mesh" && dynamic) { // The prompt should prevent this case print("Error: model cannot be both static mesh and dynamic. This should never happen."); @@ -473,6 +473,9 @@ var toolBar = (function () { type: "Model", modelURL: url, shapeType: shapeType, + grab: { + grabbable: result.grabbable + }, dynamic: dynamic, gravity: dynamic ? { x: 0, y: -10, z: 0 } : { x: 0, y: 0, z: 0 } }); @@ -1409,7 +1412,6 @@ Script.scriptEnding.connect(function () { Settings.setValue(SETTING_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); - Settings.setValue(SETTING_EDIT_PREFIX + MENU_CREATE_ENTITIES_GRABBABLE, Menu.isOptionChecked(MENU_CREATE_ENTITIES_GRABBABLE)); Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LARGE, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LARGE)); Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_SMALL, Menu.isOptionChecked(MENU_ALLOW_SELECTION_SMALL)); Settings.setValue(SETTING_EDIT_PREFIX + MENU_ALLOW_SELECTION_LIGHTS, Menu.isOptionChecked(MENU_ALLOW_SELECTION_LIGHTS)); @@ -1710,7 +1712,7 @@ function onPromptTextChanged(prompt) { } } -function handeMenuEvent(menuItem) { +function handleMenuEvent(menuItem) { if (menuItem === "Allow Selecting of Small Models") { allowSmallModels = Menu.isOptionChecked("Allow Selecting of Small Models"); } else if (menuItem === "Allow Selecting of Large Models") { @@ -1750,6 +1752,8 @@ function handeMenuEvent(menuItem) { entityIconOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_AND_PARTICLES_IN_EDIT_MODE)); } else if (menuItem === MENU_SHOW_ZONES_IN_EDIT_MODE) { Entities.setDrawZoneBoundaries(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE)); + } else if (menuItem === MENU_CREATE_ENTITIES_GRABBABLE) { + Settings.setValue(SETTING_EDIT_PREFIX + menuItem, Menu.isOptionChecked(menuItem)); } tooltip.show(false); } @@ -1875,7 +1879,7 @@ function importSVO(importURL) { } Window.svoImportRequested.connect(importSVO); -Menu.menuItemEvent.connect(handeMenuEvent); +Menu.menuItemEvent.connect(handleMenuEvent); var keyPressEvent = function (event) { if (isActive) { diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index 19e603b4ab..4f73d8e598 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -14,6 +14,7 @@ (function() { Script.include("/~/system/libraries/Xform.js"); + Script.include("/~/system/libraries/globals.js"); var DEBUG = false; var MIN_LOADING_PROGRESS = 3.6; var TOTAL_LOADING_PROGRESS = 3.8; @@ -379,6 +380,12 @@ var currentProgress = 0.1; function updateOverlays(physicsEnabled) { + + if (isInterstitialOverlaysVisible !== !physicsEnabled && !physicsEnabled === true) { + // visible changed to true. + isInterstitialOverlaysVisible = !physicsEnabled; + } + var properties = { visible: !physicsEnabled }; @@ -425,6 +432,11 @@ if (physicsEnabled) { Camera.mode = previousCameraMode; } + + if (isInterstitialOverlaysVisible !== !physicsEnabled && !physicsEnabled === false) { + // visible changed to false. + isInterstitialOverlaysVisible = !physicsEnabled; + } } function scaleInterstitialPage(sensorToWorldScale) { diff --git a/scripts/system/libraries/globals.js b/scripts/system/libraries/globals.js index 0c382314c9..b51a905e0a 100644 --- a/scripts/system/libraries/globals.js +++ b/scripts/system/libraries/globals.js @@ -9,3 +9,5 @@ // HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + +isInterstitialOverlaysVisible = false; diff --git a/scripts/system/miniTablet.js b/scripts/system/miniTablet.js index fdc00c1ebf..a2f0d074f0 100644 --- a/scripts/system/miniTablet.js +++ b/scripts/system/miniTablet.js @@ -23,12 +23,17 @@ miniState = null, // Hands. + NO_HAND = -1, LEFT_HAND = 0, RIGHT_HAND = 1, HAND_NAMES = ["LeftHand", "RightHand"], - // Miscellaneous. + // Track controller grabbing state. HIFI_OBJECT_MANIPULATION_CHANNEL = "Hifi-Object-Manipulation", + grabbingHand = NO_HAND, + grabbedItem = null, + + // Miscellaneous. tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"), DEBUG = false; @@ -737,37 +742,11 @@ setState(MINI_VISIBLE); } - function enterMiniShowing(hand) { - miniHand = hand; - ui.show(miniHand); - miniScaleStart = Date.now(); - miniScaleTimer = Script.setTimeout(scaleMiniUp, MINI_SCALE_TIMEOUT); - } - - function updateMiniShowing() { - if (HMD.showTablet) { - setState(MINI_HIDDEN); - } - } - - function exitMiniShowing() { - if (miniScaleTimer) { - Script.clearTimeout(miniScaleTimer); - miniScaleTimer = null; - } - } - - function updateMiniVisible() { + function checkMiniVisibility() { var showLeft, showRight; - // Hide mini tablet if tablet proper has been displayed by other means. - if (HMD.showTablet) { - setState(MINI_HIDDEN); - return; - } - - // Check that the mini tablet should still be visible and if so then ensure it's on the hand that the camera is + // Check that the mini tablet should still be visible and if so then ensure it's on the hand that the camera is // gazing at. showLeft = shouldShowMini(LEFT_HAND); showRight = shouldShowMini(RIGHT_HAND); @@ -790,8 +769,47 @@ setState(MINI_HIDING); } } else { - setState(MINI_HIDING); + if (grabbedItem === null || grabbingHand !== miniHand) { + setState(MINI_HIDING); + } else { + setState(MINI_HIDDEN); + } } + } + + function enterMiniShowing(hand) { + miniHand = hand; + ui.show(miniHand); + miniScaleStart = Date.now(); + miniScaleTimer = Script.setTimeout(scaleMiniUp, MINI_SCALE_TIMEOUT); + } + + function updateMiniShowing() { + // Hide mini tablet if tablet proper has been displayed by other means. + if (HMD.showTablet) { + setState(MINI_HIDDEN); + } + + // Hide mini tablet if it should no longer be visible. + checkMiniVisibility(); + } + + function exitMiniShowing() { + if (miniScaleTimer) { + Script.clearTimeout(miniScaleTimer); + miniScaleTimer = null; + } + } + + function updateMiniVisible() { + // Hide mini tablet if tablet proper has been displayed by other means. + if (HMD.showTablet) { + setState(MINI_HIDDEN); + return; + } + + // Hide mini tablet if it should no longer be visible. + checkMiniVisibility(); // If state hasn't changed, update mini tablet rotation. if (miniState === MINI_VISIBLE) { @@ -973,6 +991,21 @@ return; } + // Track grabbed state and item. + switch (message.action) { + case "grab": + grabbingHand = HAND_NAMES.indexOf(message.joint); + grabbedItem = message.grabbedEntity; + break; + case "release": + grabbingHand = NO_HAND; + grabbedItem = null; + break; + default: + error("Unexpected grab message!"); + return; + } + if (message.grabbedEntity !== HMD.tabletID && message.grabbedEntity !== ui.getMiniTabletID()) { return; } diff --git a/scripts/system/progress.js b/scripts/system/progress.js index db09d40608..b373612790 100644 --- a/scripts/system/progress.js +++ b/scripts/system/progress.js @@ -14,11 +14,11 @@ // (function () { // BEGIN LOCAL_SCOPE - function debug() { //print.apply(null, arguments); } + Script.include("/~/system/libraries/globals.js"); var rawProgress = 100, // % raw value. displayProgress = 100, // % smoothed value to display. alpha = 0.0, @@ -83,7 +83,9 @@ // The initial delay cooldown keeps us from tracking progress before the allotted time // has passed. INITIAL_DELAY_COOLDOWN_TIME = 1000, - initialDelayCooldown = 0; + initialDelayCooldown = 0, + + isInInterstitialMode = false; function fade() { @@ -265,7 +267,7 @@ // Update state if (!visible) { // Not visible because no recent downloads - if (displayProgress < 100 || gpuTextures > 0) { // Have started downloading so fade in + if ((displayProgress < 100 || gpuTextures > 0) && !isInInterstitialMode && !isInterstitialOverlaysVisible) { // Have started downloading so fade in visible = true; alphaDelta = ALPHA_DELTA_IN; fadeTimer = Script.setInterval(fade, FADE_INTERVAL); @@ -305,10 +307,13 @@ } else { x = x * BAR_HMD_REPEAT; } + if (isInInterstitialMode || isInterstitialOverlaysVisible) { + visible = false; + } // Update progress bar Overlays.editOverlay(barDesktop.overlay, { - visible: !isHMD, + visible: !isHMD && visible, bounds: { x: barDesktop.repeat - x, y: windowHeight - barDesktop.height, @@ -318,7 +323,7 @@ }); Overlays.editOverlay(barHMD.overlay, { - visible: isHMD, + visible: isHMD && visible, bounds: { x: BAR_HMD_REPEAT - x, y: windowHeight - BAR_HMD_HEIGHT, @@ -328,11 +333,11 @@ }); Overlays.editOverlay(textDesktop.overlay, { - visible: !isHMD + visible: !isHMD && visible }); Overlays.editOverlay(textHMD.overlay, { - visible: isHMD + visible: isHMD && visible }); // Update 2D overlays to maintain positions at bottom middle of window @@ -344,6 +349,10 @@ } } + function interstitialModeChanged(inMode) { + isInInterstitialMode = inMode; + } + function setUp() { var is4k = Window.innerWidth > 3000; @@ -369,6 +378,7 @@ } setUp(); + Window.interstitialModeChanged.connect(interstitialModeChanged); GlobalServices.downloadInfoChanged.connect(onDownloadInfoChanged); GlobalServices.updateDownloadInfo(); Script.setInterval(update, 1000 / 60); diff --git a/scripts/system/redirectOverlays.js b/scripts/system/redirectOverlays.js index b1180e0cd0..bb537bee0e 100644 --- a/scripts/system/redirectOverlays.js +++ b/scripts/system/redirectOverlays.js @@ -5,14 +5,20 @@ "Oops! Protocol version mismatch.", "Oops! Not authorized to join domain.", "Oops! Connection timed out.", + "Oops! The domain is full.", "Oops! Something went wrong." ]; var PROTOCOL_VERSION_MISMATCH = 1; var NOT_AUTHORIZED = 3; + var DOMAIN_FULL = 4; var TIMEOUT = 5; - var hardRefusalErrors = [PROTOCOL_VERSION_MISMATCH, - NOT_AUTHORIZED, TIMEOUT]; + var hardRefusalErrors = [ + PROTOCOL_VERSION_MISMATCH, + NOT_AUTHORIZED, + TIMEOUT, + DOMAIN_FULL + ]; var timer = null; var isErrorState = false; @@ -26,7 +32,7 @@ return ERROR_MESSAGE_MAP[errorMessageMapIndex]; } else { // some other text. - return ERROR_MESSAGE_MAP[4]; + return ERROR_MESSAGE_MAP[ERROR_MESSAGE_MAP.length - 1]; } }; diff --git a/scripts/system/snapshot.js b/scripts/system/snapshot.js index 09f3e5fbfe..ed6ff80398 100644 --- a/scripts/system/snapshot.js +++ b/scripts/system/snapshot.js @@ -44,7 +44,10 @@ try { } function removeFromStoryIDsToMaybeDelete(story_id) { - storyIDsToMaybeDelete.splice(storyIDsToMaybeDelete.indexOf(story_id), 1); + story_id = parseInt(story_id); + if (storyIDsToMaybeDelete.indexOf(story_id) > -1) { + storyIDsToMaybeDelete.splice(storyIDsToMaybeDelete.indexOf(story_id), 1); + } print('storyIDsToMaybeDelete[] now:', JSON.stringify(storyIDsToMaybeDelete)); } @@ -258,6 +261,7 @@ function onMessage(message) { } break; case 'removeFromStoryIDsToMaybeDelete': + console.log("Facebook OR Twitter button clicked for story_id " + message.story_id); removeFromStoryIDsToMaybeDelete(message.story_id); break; default: @@ -333,11 +337,13 @@ function fillImageDataFromPrevious() { var previousAnimatedSnapStoryID = Settings.getValue("previousAnimatedSnapStoryID"); var previousAnimatedSnapBlastingDisabled = Settings.getValue("previousAnimatedSnapBlastingDisabled"); var previousAnimatedSnapHifiSharingDisabled = Settings.getValue("previousAnimatedSnapHifiSharingDisabled"); + snapshotOptions = { containsGif: previousAnimatedSnapPath !== "", processingGif: false, shouldUpload: false, - canBlast: snapshotDomainID === Settings.getValue("previousSnapshotDomainID"), + canBlast: snapshotDomainID === Settings.getValue("previousSnapshotDomainID") && + snapshotDomainID === location.domainID, isLoggedIn: isLoggedIn }; imageData = []; @@ -369,7 +375,8 @@ function snapshotUploaded(isError, reply) { isGif = fileExtensionMatches(imageURL, "gif"), ignoreGifSnapshotData = false, ignoreStillSnapshotData = false; - storyIDsToMaybeDelete.push(storyID); + storyIDsToMaybeDelete.push(parseInt(storyID)); + print('storyIDsToMaybeDelete[] now:', JSON.stringify(storyIDsToMaybeDelete)); if (isGif) { if (mostRecentGifSnapshotFilename !== replyJson.user_story.details.original_image_file_name) { ignoreGifSnapshotData = true; diff --git a/server-console/resources/console-notification.png b/server-console/resources/console-notification.png index 0fd22b8900..d506a3d2e8 100644 Binary files a/server-console/resources/console-notification.png and b/server-console/resources/console-notification.png differ diff --git a/server-console/resources/console-tray-osx-stopped.png b/server-console/resources/console-tray-osx-stopped.png index 3255d43f60..53589b60b0 100644 Binary files a/server-console/resources/console-tray-osx-stopped.png and b/server-console/resources/console-tray-osx-stopped.png differ diff --git a/server-console/resources/console-tray-osx-stopped@2x.png b/server-console/resources/console-tray-osx-stopped@2x.png index 6a75dad5bf..5356afb93e 100644 Binary files a/server-console/resources/console-tray-osx-stopped@2x.png and b/server-console/resources/console-tray-osx-stopped@2x.png differ diff --git a/server-console/src/main.js b/server-console/src/main.js index c26938745b..5c7913d775 100644 --- a/server-console/src/main.js +++ b/server-console/src/main.js @@ -338,13 +338,15 @@ const HifiNotificationType = hfNotifications.NotificationType; var pendingNotifications = {} var notificationState = NotificationState.UNNOTIFIED; -function setNotificationState (notificationType, pending = true) { - pendingNotifications[notificationType] = pending; - notificationState = NotificationState.UNNOTIFIED; - for (var key in pendingNotifications) { - if (pendingNotifications[key]) { - notificationState = NotificationState.NOTIFIED; - break; +function setNotificationState (notificationType, pending = undefined) { + if (pending !== undefined) { + pendingNotifications[notificationType] = pending; + notificationState = NotificationState.UNNOTIFIED; + for (var key in pendingNotifications) { + if (pendingNotifications[key]) { + notificationState = NotificationState.NOTIFIED; + break; + } } } updateTrayMenu(homeServer ? homeServer.state : ProcessGroupStates.STOPPED); @@ -568,7 +570,42 @@ function updateLabels(serverState) { labels.people.icon = pendingNotifications[HifiNotificationType.PEOPLE] ? menuNotificationIcon : null; labels.wallet.icon = pendingNotifications[HifiNotificationType.WALLET] ? menuNotificationIcon : null; labels.marketplace.icon = pendingNotifications[HifiNotificationType.MARKETPLACE] ? menuNotificationIcon : null; - + var onlineUsers = trayNotifications.getOnlineUsers(); + delete labels.people.submenu; + if (onlineUsers) { + for (var name in onlineUsers) { + if(labels.people.submenu == undefined) { + labels.people.submenu = []; + } + labels.people.submenu.push({ + label: name, + enabled: (onlineUsers[name].location != undefined), + click: function (item) { + setNotificationState(HifiNotificationType.PEOPLE, false); + if(onlineUsers[item.label] && onlineUsers[item.label].location) { + StartInterface("hifi://" + onlineUsers[item.label].location.root.name + onlineUsers[item.label].location.path); + } + } + }); + } + } + var currentStories = trayNotifications.getCurrentStories(); + delete labels.goto.submenu; + if (currentStories) { + for (var location in currentStories) { + if(labels.goto.submenu == undefined) { + labels.goto.submenu = []; + } + labels.goto.submenu.push({ + label: "event in " + location, + location: location, + click: function (item) { + setNotificationState(HifiNotificationType.GOTO, false); + StartInterface("hifi://" + item.location + currentStories[item.location].path); + } + }); + } + } } function updateTrayMenu(serverState) { @@ -919,6 +956,8 @@ app.on('ready', function() { trayNotifications.startPolling(); } updateTrayMenu(ProcessGroupStates.STOPPED); - - maybeInstallDefaultContentSet(onContentLoaded); + + if (isServerInstalled()) { + maybeInstallDefaultContentSet(onContentLoaded); + } }); diff --git a/server-console/src/modules/hf-notifications.js b/server-console/src/modules/hf-notifications.js index 464d268c5e..b1f337bbc3 100644 --- a/server-console/src/modules/hf-notifications.js +++ b/server-console/src/modules/hf-notifications.js @@ -73,11 +73,17 @@ HifiNotification.prototype = { text = this.data + " of your connections are online." } message = "Click to open PEOPLE."; - url="hifiapp:PEOPLE" + url="hifiapp:PEOPLE"; } else { - text = this.data.username + " is available in " + this.data.location.root.name + "."; - message = "Click to join them."; - url="hifi://" + this.data.location.root.name + this.data.location.path; + if (this.data.location) { + text = this.data.username + " is available in " + this.data.location.root.name + "."; + message = "Click to join them."; + url="hifi://" + this.data.location.root.name + this.data.location.path; + } else { + text = this.data.username + " is online."; + message = "Click to open PEOPLE."; + url="hifiapp:PEOPLE"; + } } break; @@ -136,7 +142,8 @@ HifiNotification.prototype = { function HifiNotifications(config, menuNotificationCallback) { this.config = config; this.menuNotificationCallback = menuNotificationCallback; - this.onlineUsers = new Set([]); + this.onlineUsers = {}; + this.currentStories = {}; this.storiesSince = new Date(this.config.get("storiesNotifySince", "1970-01-01T00:00:00.000Z")); this.peopleSince = new Date(this.config.get("peopleNotifySince", "1970-01-01T00:00:00.000Z")); this.walletSince = new Date(this.config.get("walletNotifySince", "1970-01-01T00:00:00.000Z")); @@ -213,6 +220,12 @@ HifiNotifications.prototype = { clearInterval(this.marketplacePollTimer); } }, + getOnlineUsers: function () { + return this.onlineUsers; + }, + getCurrentStories: function () { + return this.currentStories; + }, _showNotification: function () { var _this = this; @@ -225,7 +238,7 @@ HifiNotifications.prototype = { // previous notification immediately when a // new one is submitted _this.pendingNotifications.shift(); - if(_this.pendingNotifications.length > 0) { + if (_this.pendingNotifications.length > 0) { _this._showNotification(); } }); @@ -289,7 +302,6 @@ HifiNotifications.prototype = { finished(false); return; } - console.log(content); if (!content.total_entries) { finished(true, token); return; @@ -313,7 +325,6 @@ HifiNotifications.prototype = { notifyData = content.data.updates; break; } - notifyData.forEach(function (notifyDataEntry) { _this._addNotification(new HifiNotification(notifyType, notifyDataEntry)); }); @@ -346,7 +357,7 @@ HifiNotifications.prototype = { 'include_actions=announcement', 'restriction=open,hifi', 'require_online=true', - 'per_page=1' + 'per_page=' + MAX_NOTIFICATION_ITEMS ]; var url = METAVERSE_SERVER_URL + STORIES_URL + '?' + options.join('&'); // call a second time to determine if there are no more stories and we should @@ -357,7 +368,34 @@ HifiNotifications.prototype = { 'bearer': token } }, function (error, data) { - _this._pollToDisableHighlight(NotificationType.GOTO, error, data); + if (error || !data.body) { + console.log("Error: unable to get " + url); + finished(false); + return; + } + var content = JSON.parse(data.body); + if (!content || content.status != 'success') { + console.log("Error: unable to get " + url); + finished(false); + return; + } + + if (!content.total_entries) { + finished(true, token); + return; + } + if (!content.total_entries) { + _this.menuNotificationCallback(NotificationType.GOTO, false); + } + _this.currentStories = {}; + content.user_stories.forEach(function (story) { + // only show a single instance of each story location + // in the menu. This may cause issues with domains + // where the story locations are significantly different + // for each story. + _this.currentStories[story.place_name] = story; + }); + _this.menuNotificationCallback(NotificationType.GOTO); }); } }); @@ -400,20 +438,19 @@ HifiNotifications.prototype = { console.log("Error: unable to get " + url); return false; } - console.log(content); if (!content.total_entries) { _this.menuNotificationCallback(NotificationType.PEOPLE, false); - _this.onlineUsers = new Set([]); + _this.onlineUsers = {}; return; } - var currentUsers = new Set([]); + var currentUsers = {}; var newUsers = new Set([]); content.data.users.forEach(function (user) { - currentUsers.add(user.username); - if (!_this.onlineUsers.has(user.username)) { + currentUsers[user.username] = user; + if (!(user.username in _this.onlineUsers)) { newUsers.add(user); - _this.onlineUsers.add(user.username); + _this.onlineUsers[user.username] = user; } }); _this.onlineUsers = currentUsers; diff --git a/tests-manual/ui/qml/ControlsGalleryWindow.qml b/tests-manual/ui/qml/ControlsGalleryWindow.qml new file mode 100644 index 0000000000..32fd62da36 --- /dev/null +++ b/tests-manual/ui/qml/ControlsGalleryWindow.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 +import QtQuick.Window 2.3 +import QtQuick.Controls 1.4 +import '../../../scripts/developer/tests' as Tests + +ApplicationWindow { + width: 640 + height: 480 + visible: true + + Tests.ControlsGallery { + anchors.fill: parent + } +} diff --git a/tests-manual/ui/qml/Palettes.qml b/tests-manual/ui/qml/Palettes.qml deleted file mode 100644 index 2bdf6eba8b..0000000000 --- a/tests-manual/ui/qml/Palettes.qml +++ /dev/null @@ -1,150 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 - -Rectangle { - color: "teal" - height: 512 - width: 192 - SystemPalette { id: sp; colorGroup: SystemPalette.Active } - SystemPalette { id: spi; colorGroup: SystemPalette.Inactive } - SystemPalette { id: spd; colorGroup: SystemPalette.Disabled } - - Column { - anchors.margins: 8 - anchors.fill: parent - spacing: 8 - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "base" } - Rectangle { height: parent.height; width: 16; color: sp.base } - Rectangle { height: parent.height; width: 16; color: spi.base } - Rectangle { height: parent.height; width: 16; color: spd.base } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "alternateBase" } - Rectangle { height: parent.height; width: 16; color: sp.alternateBase } - Rectangle { height: parent.height; width: 16; color: spi.alternateBase } - Rectangle { height: parent.height; width: 16; color: spd.alternateBase } - } - Item { - height: 16 - width:parent.width - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "dark" } - Rectangle { height: parent.height; width: 16; color: sp.dark } - Rectangle { height: parent.height; width: 16; color: spi.dark } - Rectangle { height: parent.height; width: 16; color: spd.dark } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "mid" } - Rectangle { height: parent.height; width: 16; color: sp.mid } - Rectangle { height: parent.height; width: 16; color: spi.mid } - Rectangle { height: parent.height; width: 16; color: spd.mid } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "mid light" } - Rectangle { height: parent.height; width: 16; color: sp.midlight } - Rectangle { height: parent.height; width: 16; color: spi.midlight } - Rectangle { height: parent.height; width: 16; color: spd.midlight } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "light" } - Rectangle { height: parent.height; width: 16; color: sp.light} - Rectangle { height: parent.height; width: 16; color: spi.light} - Rectangle { height: parent.height; width: 16; color: spd.light} - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "shadow" } - Rectangle { height: parent.height; width: 16; color: sp.shadow} - Rectangle { height: parent.height; width: 16; color: spi.shadow} - Rectangle { height: parent.height; width: 16; color: spd.shadow} - } - Item { - height: 16 - width:parent.width - } - - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "text" } - Rectangle { height: parent.height; width: 16; color: sp.text } - Rectangle { height: parent.height; width: 16; color: spi.text } - Rectangle { height: parent.height; width: 16; color: spd.text } - } - Item { - height: 16 - width:parent.width - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "window" } - Rectangle { height: parent.height; width: 16; color: sp.window } - Rectangle { height: parent.height; width: 16; color: spi.window } - Rectangle { height: parent.height; width: 16; color: spd.window } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "window text" } - Rectangle { height: parent.height; width: 16; color: sp.windowText } - Rectangle { height: parent.height; width: 16; color: spi.windowText } - Rectangle { height: parent.height; width: 16; color: spd.windowText } - } - Item { - height: 16 - width:parent.width - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "button" } - Rectangle { height: parent.height; width: 16; color: sp.button } - Rectangle { height: parent.height; width: 16; color: spi.button } - Rectangle { height: parent.height; width: 16; color: spd.button } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "buttonText" } - Rectangle { height: parent.height; width: 16; color: sp.buttonText } - Rectangle { height: parent.height; width: 16; color: spi.buttonText } - Rectangle { height: parent.height; width: 16; color: spd.buttonText } - } - Item { - height: 16 - width:parent.width - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "highlight" } - Rectangle { height: parent.height; width: 16; color: sp.highlight } - Rectangle { height: parent.height; width: 16; color: spi.highlight } - Rectangle { height: parent.height; width: 16; color: spd.highlight } - } - Row { - width: parent.width - height: 16 - Text { height: parent.height; width: 128; text: "highlighted text" } - Rectangle { height: parent.height; width: 16; color: sp.highlightedText} - Rectangle { height: parent.height; width: 16; color: spi.highlightedText} - Rectangle { height: parent.height; width: 16; color: spd.highlightedText} - } - } -} diff --git a/tests-manual/ui/qml/ScrollingGraph.qml b/tests-manual/ui/qml/ScrollingGraph.qml deleted file mode 100644 index 55523a23f4..0000000000 --- a/tests-manual/ui/qml/ScrollingGraph.qml +++ /dev/null @@ -1,111 +0,0 @@ -import QtQuick 2.1 -import QtQuick.Controls 1.0 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 - -Rectangle { - id: root - property int size: 64 - width: size - height: size - color: 'black' - property int controlId: 0 - property real value: 0.5 - property int scrollWidth: 1 - property real min: 0.0 - property real max: 1.0 - property bool log: false - property real range: max - min - property color lineColor: 'yellow' - property bool bar: false - property real lastHeight: -1 - property string label: "" - - function update() { - value = Controller.getValue(controlId); - if (log) { - var log = Math.log(10) / Math.log(Math.abs(value)); - var sign = Math.sign(value); - value = log * sign; - } - canvas.requestPaint(); - } - - function drawHeight() { - if (value < min) { - return 0; - } - if (value > max) { - return height; - } - return ((value - min) / range) * height; - } - - Timer { - interval: 50; running: true; repeat: true - onTriggered: root.update() - } - - Canvas { - id: canvas - anchors.fill: parent - antialiasing: false - - Text { - anchors.top: parent.top - text: root.label - color: 'white' - } - - Text { - anchors.right: parent.right - anchors.top: parent.top - text: root.max - color: 'white' - } - - Text { - anchors.right: parent.right - anchors.bottom: parent.bottom - text: root.min - color: 'white' - } - - function scroll() { - var ctx = canvas.getContext('2d'); - var image = ctx.getImageData(0, 0, canvas.width, canvas.height); - ctx.beginPath(); - ctx.clearRect(0, 0, canvas.width, canvas.height); - ctx.drawImage(image, -root.scrollWidth, 0, canvas.width, canvas.height) - ctx.restore() - } - - onPaint: { - scroll(); - var ctx = canvas.getContext('2d'); - ctx.save(); - var currentHeight = root.drawHeight(); - if (root.lastHeight == -1) { - root.lastHeight = currentHeight - } - -// var x = canvas.width - root.drawWidth; -// var y = canvas.height - drawHeight; -// ctx.fillStyle = root.color -// ctx.fillRect(x, y, root.drawWidth, root.bar ? drawHeight : 1) -// ctx.fill(); -// ctx.restore() - - - ctx.beginPath(); - ctx.lineWidth = 1 - ctx.strokeStyle = root.lineColor - ctx.moveTo(canvas.width - root.scrollWidth, root.lastHeight).lineTo(canvas.width, currentHeight) - ctx.stroke() - ctx.restore() - root.lastHeight = currentHeight - } - } -} - - diff --git a/tests-manual/ui/qml/StubMenu.qml b/tests-manual/ui/qml/StubMenu.qml deleted file mode 100644 index fd0298988a..0000000000 --- a/tests-manual/ui/qml/StubMenu.qml +++ /dev/null @@ -1,730 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -import "../../../interface/resources/qml/hifi" - -Menu { - property var menuOption: MenuOption {} - Item { - Action { - id: login; - text: menuOption.login - } - Action { - id: update; - text: "Update"; - enabled: false - } - Action { - id: crashReporter; - text: "Crash Reporter..."; - enabled: false - } - Action { - id: help; - text: menuOption.help - onTriggered: Application.showHelp() - } - Action { - id: aboutApp; - text: menuOption.aboutApp - } - Action { - id: quit; - text: menuOption.quit - } - - ExclusiveGroup { id: renderResolutionGroup } - Action { - id: renderResolutionOne; - exclusiveGroup: renderResolutionGroup; - text: menuOption.renderResolutionOne; - checkable: true; - checked: true - } - Action { - id: renderResolutionTwoThird; - exclusiveGroup: renderResolutionGroup; - text: menuOption.renderResolutionTwoThird; - checkable: true - } - Action { - id: renderResolutionHalf; - exclusiveGroup: renderResolutionGroup; - text: menuOption.renderResolutionHalf; - checkable: true - } - Action { - id: renderResolutionThird; - exclusiveGroup: renderResolutionGroup; - text: menuOption.renderResolutionThird; - checkable: true - } - Action { - id: renderResolutionQuarter; - exclusiveGroup: renderResolutionGroup; - text: menuOption.renderResolutionQuarter; - checkable: true - } - - ExclusiveGroup { id: ambientLightGroup } - Action { - id: renderAmbientLightGlobal; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLightGlobal; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight0; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight0; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight1; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight1; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight2; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight2; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight3; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight3; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight4; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight4; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight5; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight5; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight6; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight6; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight7; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight7; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight8; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight8; - checkable: true; - checked: true - } - Action { - id: renderAmbientLight9; - exclusiveGroup: ambientLightGroup; - text: menuOption.renderAmbientLight9; - checkable: true; - checked: true - } - Action { - id: preferences - shortcut: StandardKey.Preferences - text: menuOption.preferences - onTriggered: dialogsManager.editPreferences() - } - - } - - Menu { - title: "File" - MenuItem { - action: login - } - MenuItem { - action: update - } - MenuItem { - action: help - } - MenuItem { - action: crashReporter - } - MenuItem { - action: aboutApp - } - MenuItem { - action: quit - } - } - - Menu { - title: "Edit" - MenuItem { - text: "Undo" } - MenuItem { - text: "Redo" } - MenuItem { - text: menuOption.runningScripts - } - MenuItem { - text: menuOption.loadScript - } - MenuItem { - text: menuOption.loadScriptURL - } - MenuItem { - text: menuOption.stopAllScripts - } - MenuItem { - text: menuOption.reloadAllScripts - } - MenuItem { - text: menuOption.scriptEditor - } - MenuItem { - text: menuOption.console_ - } - MenuItem { - text: menuOption.reloadContent - } - MenuItem { - text: menuOption.packageModel - } - } - - Menu { - title: "Audio" - MenuItem { - text: menuOption.muteAudio; - checkable: true - } - MenuItem { - text: menuOption.audioTools; - checkable: true - } - } - Menu { - title: "Avatar" - // Avatar > Attachments... - MenuItem { - text: menuOption.attachments - } - Menu { - title: "Size" - // Avatar > Size > Increase - MenuItem { - text: menuOption.increaseAvatarSize - } - // Avatar > Size > Decrease - MenuItem { - text: menuOption.decreaseAvatarSize - } - // Avatar > Size > Reset - MenuItem { - text: menuOption.resetAvatarSize - } - } - // Avatar > Reset Sensors - MenuItem { - text: menuOption.resetSensors - } - } - Menu { - title: "Display" - } - Menu { - title: "View" - ExclusiveGroup { - id: cameraModeGroup - } - - MenuItem { - text: menuOption.firstPerson; - checkable: true; - exclusiveGroup: cameraModeGroup - } - MenuItem { - text: menuOption.thirdPerson; - checkable: true; - exclusiveGroup: cameraModeGroup - } - MenuItem { - text: menuOption.fullscreenMirror; - checkable: true; - exclusiveGroup: cameraModeGroup - } - MenuItem { - text: menuOption.independentMode; - checkable: true; - exclusiveGroup: cameraModeGroup - } - MenuItem { - text: menuOption.cameraEntityMode; - checkable: true; - exclusiveGroup: cameraModeGroup - } - MenuSeparator{} - MenuItem { - text: menuOption.miniMirror; - checkable: true - } - } - Menu { - title: "Navigate" - MenuItem { - text: "Home" } - MenuItem { - text: menuOption.addressBar - } - MenuItem { - text: "Directory" } - MenuItem { - text: menuOption.copyAddress - } - MenuItem { - text: menuOption.copyPath - } - } - Menu { - title: "Settings" - MenuItem { - text: "Advanced Menus" } - MenuItem { - text: "Developer Menus" } - MenuItem { - text: menuOption.preferences - } - MenuItem { - text: "Avatar..." } - MenuItem { - text: "Audio..." } - MenuItem { - text: "LOD..." } - MenuItem { - text: menuOption.inputMenu - } - } - Menu { - title: "Developer" - Menu { - title: "Render" - MenuItem { - text: menuOption.atmosphere; - checkable: true - } - MenuItem { - text: menuOption.worldAxes; - checkable: true - } - MenuItem { - text: menuOption.debugAmbientOcclusion; - checkable: true - } - MenuItem { - text: menuOption.antialiasing; - checkable: true - } - MenuItem { - text: menuOption.stars; - checkable: true - } - Menu { - title: menuOption.renderAmbientLight - MenuItem { - action: renderAmbientLightGlobal; } - MenuItem { - action: renderAmbientLight0; } - MenuItem { - action: renderAmbientLight1; } - MenuItem { - action: renderAmbientLight2; } - MenuItem { - action: renderAmbientLight3; } - MenuItem { - action: renderAmbientLight4; } - MenuItem { - action: renderAmbientLight5; } - MenuItem { - action: renderAmbientLight6; } - MenuItem { - action: renderAmbientLight7; } - MenuItem { - action: renderAmbientLight8; } - MenuItem { - action: renderAmbientLight9; } - } - MenuItem { - text: menuOption.throttleFPSIfNotFocus; - checkable: true - } - Menu { - title: menuOption.renderResolution - MenuItem { - action: renderResolutionOne - } - MenuItem { - action: renderResolutionTwoThird - } - MenuItem { - action: renderResolutionHalf - } - MenuItem { - action: renderResolutionThird - } - MenuItem { - action: renderResolutionQuarter - } - } - MenuItem { - text: menuOption.lodTools - } - } - Menu { - title: "Assets" - MenuItem { - text: menuOption.uploadAsset - } - MenuItem { - text: menuOption.assetMigration - } - } - Menu { - title: "Avatar" - Menu { - title: "Face Tracking" - MenuItem { - text: menuOption.noFaceTracking; - checkable: true - } - MenuItem { - text: menuOption.faceshift; - checkable: true - } - MenuItem { - text: menuOption.useCamera; - checkable: true - } - MenuSeparator{} - MenuItem { - text: menuOption.binaryEyelidControl; - checkable: true - } - MenuItem { - text: menuOption.coupleEyelids; - checkable: true - } - MenuItem { - text: menuOption.useAudioForMouth; - checkable: true - } - MenuItem { - text: menuOption.velocityFilter; - checkable: true - } - MenuItem { - text: menuOption.calibrateCamera - } - MenuSeparator{} - MenuItem { - text: menuOption.muteFaceTracking; - checkable: true - } - MenuItem { - text: menuOption.autoMuteAudio; - checkable: true - } - } - Menu { - title: "Eye Tracking" - MenuItem { - text: menuOption.sMIEyeTracking; - checkable: true - } - Menu { - title: "Calibrate" - MenuItem { - text: menuOption.onePointCalibration - } - MenuItem { - text: menuOption.threePointCalibration - } - MenuItem { - text: menuOption.fivePointCalibration - } - } - MenuItem { - text: menuOption.simulateEyeTracking; - checkable: true - } - } - MenuItem { - text: menuOption.avatarReceiveStats; - checkable: true - } - MenuItem { - text: menuOption.renderBoundingCollisionShapes; - checkable: true - } - MenuItem { - text: menuOption.renderLookAtVectors; - checkable: true - } - MenuItem { - text: menuOption.renderLookAtTargets; - checkable: true - } - MenuItem { - text: menuOption.renderFocusIndicator; - checkable: true - } - MenuItem { - text: menuOption.showWhosLookingAtMe; - checkable: true - } - MenuItem { - text: menuOption.fixGaze; - checkable: true - } - MenuItem { - text: menuOption.animDebugDrawDefaultPose; - checkable: true - } - MenuItem { - text: menuOption.animDebugDrawAnimPose; - checkable: true - } - MenuItem { - text: menuOption.animDebugDrawPosition; - checkable: true - } - MenuItem { - text: menuOption.meshVisible; - checkable: true - } - MenuItem { - text: menuOption.disableEyelidAdjustment; - checkable: true - } - MenuItem { - text: menuOption.turnWithHead; - checkable: true - } - MenuItem { - text: menuOption.keyboardMotorControl; - checkable: true - } - MenuItem { - text: menuOption.scriptedMotorControl; - checkable: true - } - MenuItem { - text: menuOption.enableCharacterController; - checkable: true - } - } - Menu { - title: "Hands" - MenuItem { - text: menuOption.displayHandTargets; - checkable: true - } - MenuItem { - text: menuOption.lowVelocityFilter; - checkable: true - } - Menu { - title: "Leap Motion" - MenuItem { - text: menuOption.leapMotionOnHMD; - checkable: true - } - } - } - Menu { - title: "Entities" - MenuItem { - text: menuOption.octreeStats - } - MenuItem { - text: menuOption.showRealtimeEntityStats; - checkable: true - } - } - Menu { - title: "Network" - MenuItem { - text: menuOption.reloadContent - } - MenuItem { - text: menuOption.disableNackPackets; - checkable: true - } - MenuItem { - text: menuOption.disableActivityLogger; - checkable: true - } - MenuItem { - text: menuOption.cachesSize - } - MenuItem { - text: menuOption.diskCacheEditor - } - MenuItem { - text: menuOption.showDSConnectTable - } - MenuItem { - text: menuOption.bandwidthDetails - } - } - Menu { - title: "Timing" - Menu { - title: "Performance Timer" - MenuItem { - text: menuOption.displayDebugTimingDetails; - checkable: true - } - MenuItem { - text: menuOption.onlyDisplayTopTen; - checkable: true - } - MenuItem { - text: menuOption.expandUpdateTiming; - checkable: true - } - MenuItem { - text: menuOption.expandMyAvatarTiming; - checkable: true - } - MenuItem { - text: menuOption.expandMyAvatarSimulateTiming; - checkable: true - } - MenuItem { - text: menuOption.expandOtherAvatarTiming; - checkable: true - } - MenuItem { - text: menuOption.expandPaintGLTiming; - checkable: true - } - } - MenuItem { - text: menuOption.frameTimer; - checkable: true - } - MenuItem { - text: menuOption.runTimingTests - } - MenuItem { - text: menuOption.pipelineWarnings; - checkable: true - } - MenuItem { - text: menuOption.logExtraTimings; - checkable: true - } - MenuItem { - text: menuOption.suppressShortTimings; - checkable: true - } - } - Menu { - title: "Audio" - MenuItem { - text: menuOption.audioNoiseReduction; - checkable: true - } - MenuItem { - text: menuOption.echoServerAudio; - checkable: true - } - MenuItem { - text: menuOption.echoLocalAudio; - checkable: true - } - MenuItem { - text: menuOption.muteEnvironment - } - Menu { - title: "Audio" - MenuItem { - text: menuOption.audioScope; - checkable: true - } - MenuItem { - text: menuOption.audioScopePause; - checkable: true - } - Menu { - title: "Display Frames" - ExclusiveGroup { - id: audioScopeFramesGroup - } - MenuItem { - exclusiveGroup: audioScopeFramesGroup; - text: menuOption.audioScopeFiveFrames; - checkable: true - } - MenuItem { - exclusiveGroup: audioScopeFramesGroup; - text: menuOption.audioScopeTwentyFrames; - checkable: true - } - MenuItem { - exclusiveGroup: audioScopeFramesGroup; - text: menuOption.audioScopeFiftyFrames; - checkable: true - } - } - MenuItem { - text: menuOption.audioNetworkStats - } - } - } - Menu { - title: "Physics" - MenuItem { - text: menuOption.physicsShowOwned; - checkable: true - } - MenuItem { - text: menuOption.physicsShowHulls; - checkable: true - } - } - MenuItem { - text: menuOption.displayCrashOptions; - checkable: true - } - MenuItem { - text: menuOption.crashInterface - } - MenuItem { - text: menuOption.log - } - MenuItem { - text: menuOption.stats; - checkable: true - } - } -} diff --git a/tests-manual/ui/qml/Stubs.qml b/tests-manual/ui/qml/Stubs.qml deleted file mode 100644 index 8c1465d54c..0000000000 --- a/tests-manual/ui/qml/Stubs.qml +++ /dev/null @@ -1,346 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 - -// Stubs for the global service objects set by Interface.cpp when creating the UI -// This is useful for testing inside Qt creator where these services don't actually exist. -Item { - - Item { - objectName: "offscreenFlags" - property bool navigationFocused: false - } - - Item { - objectName: "urlHandler" - function fixupUrl(url) { return url; } - function canHandleUrl(url) { return false; } - function handleUrl(url) { return true; } - } - - Item { - objectName: "Account" - function isLoggedIn() { return true; } - function getUsername() { return "Jherico"; } - } - - Item { - objectName: "GL" - property string vendor: "" - } - - Item { - objectName: "ApplicationCompositor" - property bool reticleOverDesktop: true - } - - Item { - objectName: "Controller" - function getRecommendedOverlayRect() { - return Qt.rect(0, 0, 1920, 1080); - } - } - - Item { - objectName: "Preferences" - // List of categories obtained by logging categories as they are added in Interface in Preferences::addPreference(). - property var categories: [ - "Avatar Basics", "Snapshots", "Scripts", "Privacy", "Level of Detail Tuning", "Avatar Tuning", "Avatar Camera", - "Audio", "Octree", "HMD", "Sixense Controllers", "Graphics" - ] - } - - Item { - objectName: "ScriptDiscoveryService" - //property var scriptsModelFilter: scriptsModel - signal scriptCountChanged() - property var _runningScripts:[ - { name: "wireFrameTest.js", url: "foo/wireframetest.js", path: "foo/wireframetest.js", local: true }, - { name: "edit.js", url: "foo/edit.js", path: "foo/edit.js", local: false }, - { name: "listAllScripts.js", url: "foo/listAllScripts.js", path: "foo/listAllScripts.js", local: false }, - { name: "users.js", url: "foo/users.js", path: "foo/users.js", local: false }, - ] - - function getRunning() { - return _runningScripts; - } - } - - Item { - objectName: "HMD" - property bool active: false - } - - Item { - id: menuHelper - objectName: "MenuHelper" - - Component { - id: modelMaker - ListModel { } - } - - function toModel(menu, parent) { - if (!parent) { parent = menuHelper } - var result = modelMaker.createObject(parent); - if (menu.type !== MenuItemType.Menu) { - console.warn("Not a menu: " + menu); - return result; - } - - var items = menu.items; - for (var i = 0; i < items.length; ++i) { - var item = items[i]; - switch (item.type) { - case 2: - result.append({"name": item.title, "item": item}) - break; - case 1: - result.append({"name": item.text, "item": item}) - break; - case 0: - result.append({"name": "", "item": item}) - break; - } - } - return result; - } - - } - - Item { - objectName: "Desktop" - - property string _OFFSCREEN_ROOT_OBJECT_NAME: "desktopRoot"; - property string _OFFSCREEN_DIALOG_OBJECT_NAME: "topLevelWindow"; - - - function findChild(item, name) { - for (var i = 0; i < item.children.length; ++i) { - if (item.children[i].objectName === name) { - return item.children[i]; - } - } - return null; - } - - function findParent(item, name) { - while (item) { - if (item.objectName === name) { - return item; - } - item = item.parent; - } - return null; - } - - function findDialog(item) { - item = findParent(item, _OFFSCREEN_DIALOG_OBJECT_NAME); - return item; - } - - function closeDialog(item) { - item = findDialog(item); - if (item) { - item.visible = false - } else { - console.warn("Could not find top level dialog") - } - } - - function getDesktop(item) { - while (item) { - if (item.desktopRoot) { - break; - } - item = item.parent; - } - return item - } - - function raise(item) { - var desktop = getDesktop(item); - if (desktop) { - desktop.raise(item); - } - } - } - - Menu { - id: root - objectName: "rootMenu" - - Menu { - title: "Audio" - } - - Menu { - title: "Avatar" - } - - Menu { - title: "Display" - ExclusiveGroup { id: displayMode } - Menu { - title: "More Stuff" - - Menu { title: "Empty" } - - MenuItem { - text: "Do Nothing" - onTriggered: console.log("Nothing") - } - } - MenuItem { - text: "Oculus" - exclusiveGroup: displayMode - checkable: true - } - MenuItem { - text: "OpenVR" - exclusiveGroup: displayMode - checkable: true - } - MenuItem { - text: "OSVR" - exclusiveGroup: displayMode - checkable: true - } - MenuItem { - text: "2D Screen" - exclusiveGroup: displayMode - checkable: true - checked: true - } - MenuItem { - text: "3D Screen (Active)" - exclusiveGroup: displayMode - checkable: true - } - MenuItem { - text: "3D Screen (Passive)" - exclusiveGroup: displayMode - checkable: true - } - } - - Menu { - title: "View" - Menu { - title: "Camera Mode" - ExclusiveGroup { id: cameraMode } - MenuItem { - exclusiveGroup: cameraMode - text: "First Person"; - onTriggered: console.log(text + " checked " + checked) - checkable: true - checked: true - } - MenuItem { - exclusiveGroup: cameraMode - text: "Third Person"; - onTriggered: console.log(text) - checkable: true - } - MenuItem { - exclusiveGroup: cameraMode - text: "Independent Mode"; - onTriggered: console.log(text) - checkable: true - } - MenuItem { - exclusiveGroup: cameraMode - text: "Entity Mode"; - onTriggered: console.log(text) - enabled: false - checkable: true - } - MenuItem { - exclusiveGroup: cameraMode - text: "Fullscreen Mirror"; - onTriggered: console.log(text) - checkable: true - } - } - } - - Menu { - title: "Edit" - - MenuItem { - text: "Undo" - shortcut: "Ctrl+Z" - enabled: false - onTriggered: console.log(text) - } - - MenuItem { - text: "Redo" - shortcut: "Ctrl+Shift+Z" - enabled: false - onTriggered: console.log(text) - } - - MenuSeparator { } - - MenuItem { - text: "Cut" - shortcut: "Ctrl+X" - onTriggered: console.log(text) - } - - MenuItem { - text: "Copy" - shortcut: "Ctrl+C" - onTriggered: console.log(text) - } - - MenuItem { - text: "Paste" - shortcut: "Ctrl+V" - visible: false - onTriggered: console.log("Paste") - } - } - - Menu { - title: "Navigate" - } - - Menu { - title: "Market" - } - - Menu { - title: "Settings" - } - - Menu { - title: "Developer" - } - - Menu { - title: "Quit" - } - - Menu { - title: "File" - - Action { - id: login - text: "Login" - } - - Action { - id: quit - text: "Quit" - shortcut: "Ctrl+Q" - onTriggered: Qt.quit(); - } - - MenuItem { action: quit } - MenuItem { action: login } - } - } - -} - diff --git a/tests-manual/ui/qml/TestControllers.qml b/tests-manual/ui/qml/TestControllers.qml deleted file mode 100644 index e9a7fb49e5..0000000000 --- a/tests-manual/ui/qml/TestControllers.qml +++ /dev/null @@ -1,160 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Layouts 1.0 -import QtQuick.Dialogs 1.0 - -import "controller" -import "controls" as HifiControls -import "styles" - -HifiControls.VrDialog { - id: root - HifiConstants { id: hifi } - title: "Controller Test" - resizable: true - contentImplicitWidth: clientArea.implicitWidth - contentImplicitHeight: clientArea.implicitHeight - backgroundColor: "beige" - - property var actions: Controller.Actions - property var standard: Controller.Standard - property var hydra: null - property var testMapping: null - property bool testMappingEnabled: false - property var xbox: null - - function buildMapping() { - testMapping = Controller.newMapping(); - testMapping.fromQml(standard.RY).invert().toQml(actions.Pitch); - testMapping.fromQml(function(){ - return Math.sin(Date.now() / 250); - }).toQml(actions.Yaw); - //testMapping.makeAxis(standard.LB, standard.RB).to(actions.Yaw); - // Step yaw takes a number of degrees - testMapping.fromQml(standard.LB).pulse(0.10).invert().scale(40.0).toQml(actions.StepYaw); - testMapping.fromQml(standard.RB).pulse(0.10).scale(15.0).toQml(actions.StepYaw); - testMapping.fromQml(standard.RX).scale(15.0).toQml(actions.StepYaw); - } - - function toggleMapping() { - testMapping.enable(!testMappingEnabled); - testMappingEnabled = !testMappingEnabled; - } - - Component.onCompleted: { - var xboxRegex = /^GamePad/; - var hydraRegex = /^Hydra/; - for (var prop in Controller.Hardware) { - if(xboxRegex.test(prop)) { - root.xbox = Controller.Hardware[prop] - print("found xbox") - continue - } - if (hydraRegex.test(prop)) { - root.hydra = Controller.Hardware[prop] - print("found hydra") - continue - } - } - } - - Column { - id: clientArea - spacing: 12 - x: root.clientX - y: root.clientY - - Row { - spacing: 8 - - Button { - text: !root.testMapping ? "Build Mapping" : (root.testMappingEnabled ? "Disable Mapping" : "Enable Mapping") - onClicked: { - - if (!root.testMapping) { - root.buildMapping() - } else { - root.toggleMapping(); - } - } - } - } - - Row { - Standard { device: root.standard; label: "Standard"; width: 180 } - } - - Row { - spacing: 8 - Xbox { device: root.xbox; label: "XBox"; width: 180 } - Hydra { device: root.hydra; width: 180 } - } - - Row { - spacing: 4 - ScrollingGraph { - controlId: Controller.Actions.Yaw - label: "Yaw" - min: -2.0 - max: 2.0 - size: 64 - } - - ScrollingGraph { - controlId: Controller.Actions.YawLeft - label: "Yaw Left" - min: -2.0 - max: 2.0 - size: 64 - } - - ScrollingGraph { - controlId: Controller.Actions.YawRight - label: "Yaw Right" - min: -2.0 - max: 2.0 - size: 64 - } - - ScrollingGraph { - controlId: Controller.Actions.StepYaw - label: "StepYaw" - min: -20.0 - max: 20.0 - size: 64 - } - } - - Row { - ScrollingGraph { - controlId: Controller.Actions.TranslateZ - label: "TranslateZ" - min: -2.0 - max: 2.0 - size: 64 - } - - ScrollingGraph { - controlId: Controller.Actions.Forward - label: "Forward" - min: -2.0 - max: 2.0 - size: 64 - } - - ScrollingGraph { - controlId: Controller.Actions.Backward - label: "Backward" - min: -2.0 - max: 2.0 - size: 64 - } - - } - } -} // dialog - - - - - diff --git a/tests-manual/ui/qml/TestDialog.qml b/tests-manual/ui/qml/TestDialog.qml deleted file mode 100644 index e6675b7282..0000000000 --- a/tests-manual/ui/qml/TestDialog.qml +++ /dev/null @@ -1,94 +0,0 @@ -import QtQuick 2.3 -import QtQuick.Controls 1.2 -import QtQuick.Controls.Styles 1.3 -import "controls" - -VrDialog { - title: "Test Dialog" - id: testDialog - objectName: "TestDialog" - width: 512 - height: 512 - animationDuration: 200 - - onEnabledChanged: { - if (enabled) { - edit.forceActiveFocus(); - } - } - - Item { - id: clientArea - // The client area - anchors.fill: parent - anchors.margins: parent.margins - anchors.topMargin: parent.topMargin - - Rectangle { - property int d: 100 - id: square - objectName: "testRect" - width: d - height: d - anchors.centerIn: parent - color: "red" - NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; } - } - - - TextEdit { - id: edit - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - clip: true - text: "test edit" - anchors.top: parent.top - anchors.topMargin: 12 - } - - Button { - x: 128 - y: 192 - text: "Test" - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - anchors.right: parent.right - anchors.rightMargin: 12 - onClicked: { - console.log("Click"); - - if (square.visible) { - square.visible = false - } else { - square.visible = true - } - } - } - - Button { - id: customButton2 - y: 192 - text: "Move" - anchors.left: parent.left - anchors.leftMargin: 12 - anchors.bottom: parent.bottom - anchors.bottomMargin: 12 - onClicked: { - onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0 - } - } - - Keys.onPressed: { - console.log("Key " + event.key); - switch (event.key) { - case Qt.Key_Q: - if (Qt.ControlModifier == event.modifiers) { - event.accepted = true; - break; - } - } - } - } -} diff --git a/tests-manual/ui/qml/TestMenu.qml b/tests-manual/ui/qml/TestMenu.qml deleted file mode 100644 index fe8a26e234..0000000000 --- a/tests-manual/ui/qml/TestMenu.qml +++ /dev/null @@ -1,10 +0,0 @@ -import QtQuick 2.4 -import QtQuick.Controls 1.3 -import Hifi 1.0 - -// Currently for testing a pure QML replacement menu -Item { - Menu { - objectName: "rootMenu"; - } -} diff --git a/tests-manual/ui/qml/TestRoot.qml b/tests-manual/ui/qml/TestRoot.qml deleted file mode 100644 index bd38c696bf..0000000000 --- a/tests-manual/ui/qml/TestRoot.qml +++ /dev/null @@ -1,43 +0,0 @@ -import Hifi 1.0 -import QtQuick 2.3 -import QtQuick.Controls 1.3 -// Import local folder last so that our own control customizations override -// the built in ones -import "controls" - -Root { - id: root - anchors.fill: parent - onParentChanged: { - forceActiveFocus(); - } - Button { - id: messageBox - anchors.right: createDialog.left - anchors.rightMargin: 24 - anchors.bottom: parent.bottom - anchors.bottomMargin: 24 - text: "Message" - onClicked: { - console.log("Foo") - root.information("a") - console.log("Bar") - } - } - Button { - id: createDialog - anchors.right: parent.right - anchors.rightMargin: 24 - anchors.bottom: parent.bottom - anchors.bottomMargin: 24 - text: "Create" - onClicked: { - root.loadChild("MenuTest.qml"); - } - } - - Keys.onPressed: { - console.log("Key press root") - } -} - diff --git a/tests-manual/ui/qml/controlDemo/ButtonPage.qml b/tests-manual/ui/qml/controlDemo/ButtonPage.qml deleted file mode 100644 index 0ed7e2d6ad..0000000000 --- a/tests-manual/ui/qml/controlDemo/ButtonPage.qml +++ /dev/null @@ -1,128 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 1.2 - -ScrollView { - id: page - - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - - Item { - id: content - - width: Math.max(page.viewport.width, grid.implicitWidth + 2 * grid.rowSpacing) - height: Math.max(page.viewport.height, grid.implicitHeight + 2 * grid.columnSpacing) - - GridLayout { - id: grid - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.leftMargin: grid.rowSpacing - anchors.rightMargin: grid.rowSpacing - anchors.topMargin: grid.columnSpacing - - columns: page.width < page.height ? 1 : 2 - - GroupBox { - title: "Button" - Layout.fillWidth: true - Layout.columnSpan: grid.columns - RowLayout { - anchors.fill: parent - Button { text: "OK"; isDefault: true } - Button { text: "Cancel" } - Item { Layout.fillWidth: true } - Button { - text: "Attach" - menu: Menu { - MenuItem { text: "Image" } - MenuItem { text: "Document" } - } - } - } - } - - GroupBox { - title: "CheckBox" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - CheckBox { text: "E-mail"; checked: true } - CheckBox { text: "Calendar"; checked: true } - CheckBox { text: "Contacts" } - } - } - - GroupBox { - title: "RadioButton" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - ExclusiveGroup { id: radioGroup } - RadioButton { text: "Portrait"; exclusiveGroup: radioGroup } - RadioButton { text: "Landscape"; exclusiveGroup: radioGroup } - RadioButton { text: "Automatic"; exclusiveGroup: radioGroup; checked: true } - } - } - - GroupBox { - title: "Switch" - Layout.fillWidth: true - Layout.columnSpan: grid.columns - ColumnLayout { - anchors.fill: parent - RowLayout { - Label { text: "Wi-Fi"; Layout.fillWidth: true } - Switch { checked: true } - } - RowLayout { - Label { text: "Bluetooth"; Layout.fillWidth: true } - Switch { checked: false } - } - } - } - } - } -} diff --git a/tests-manual/ui/qml/controlDemo/InputPage.qml b/tests-manual/ui/qml/controlDemo/InputPage.qml deleted file mode 100644 index cb1878d023..0000000000 --- a/tests-manual/ui/qml/controlDemo/InputPage.qml +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 1.2 - -ScrollView { - id: page - - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - - Item { - id: content - - width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) - height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) - - ColumnLayout { - id: column - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: column.spacing - - GroupBox { - title: "TextField" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - TextField { placeholderText: "..."; Layout.fillWidth: true; z: 1 } - TextField { placeholderText: "Password"; echoMode: TextInput.Password; Layout.fillWidth: true } - } - } - - GroupBox { - title: "ComboBox" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - ComboBox { - model: Qt.fontFamilies() - Layout.fillWidth: true - } - ComboBox { - editable: true - model: ListModel { - id: listModel - ListElement { text: "Apple" } - ListElement { text: "Banana" } - ListElement { text: "Coconut" } - ListElement { text: "Orange" } - } - onAccepted: { - if (find(currentText) === -1) { - listModel.append({text: editText}) - currentIndex = find(editText) - } - } - Layout.fillWidth: true - } - } - } - - GroupBox { - title: "SpinBox" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - SpinBox { value: 99; Layout.fillWidth: true; z: 1 } - SpinBox { decimals: 2; Layout.fillWidth: true } - } - } - } - } -} diff --git a/tests-manual/ui/qml/controlDemo/ProgressPage.qml b/tests-manual/ui/qml/controlDemo/ProgressPage.qml deleted file mode 100644 index a1fa596f79..0000000000 --- a/tests-manual/ui/qml/controlDemo/ProgressPage.qml +++ /dev/null @@ -1,90 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Layouts 1.1 -import QtQuick.Controls 1.2 - -ScrollView { - id: page - - horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff - - Item { - id: content - - width: Math.max(page.viewport.width, column.implicitWidth + 2 * column.spacing) - height: Math.max(page.viewport.height, column.implicitHeight + 2 * column.spacing) - - ColumnLayout { - id: column - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: column.spacing - - GroupBox { - title: "ProgressBar" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - ProgressBar { indeterminate: true; Layout.fillWidth: true } - ProgressBar { value: slider.value; Layout.fillWidth: true } - } - } - - GroupBox { - title: "Slider" - Layout.fillWidth: true - ColumnLayout { - anchors.fill: parent - Slider { id: slider; value: 0.5; Layout.fillWidth: true } - } - } - - GroupBox { - title: "BusyIndicator" - Layout.fillWidth: true - BusyIndicator { running: true } - } - } - } -} diff --git a/tests-manual/ui/qml/controlDemo/main.qml b/tests-manual/ui/qml/controlDemo/main.qml deleted file mode 100644 index 168b9fb291..0000000000 --- a/tests-manual/ui/qml/controlDemo/main.qml +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal -** -** This file is part of the Qt Quick Controls module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:BSD$ -** You may use this file under the terms of the BSD license as follows: -** -** "Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are -** met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in -** the documentation and/or other materials provided with the -** distribution. -** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names -** of its contributors may be used to endorse or promote products derived -** from this software without specific prior written permission. -** -** -** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -import QtQuick 2.2 -import QtQuick.Layouts 1.1 -import QtQuick.Dialogs 1.1 -import QtQuick.Controls 1.2 -import "qml/UI.js" as UI -import "qml" -//import "/Users/bdavis/Git/hifi/interface/resources/qml" - -Item { - anchors.fill: parent - visible: true - //title: "Qt Quick Controls Gallery" - - MessageDialog { - id: aboutDialog - icon: StandardIcon.Information - title: "About" - text: "Qt Quick Controls Gallery" - informativeText: "This example demonstrates most of the available Qt Quick Controls." - } - - Action { - id: copyAction - text: "&Copy" - shortcut: StandardKey.Copy - iconName: "edit-copy" - enabled: (!!activeFocusItem && !!activeFocusItem["copy"]) - onTriggered: activeFocusItem.copy() - } - - Action { - id: cutAction - text: "Cu&t" - shortcut: StandardKey.Cut - iconName: "edit-cut" - enabled: (!!activeFocusItem && !!activeFocusItem["cut"]) - onTriggered: activeFocusItem.cut() - } - - Action { - id: pasteAction - text: "&Paste" - shortcut: StandardKey.Paste - iconName: "edit-paste" - enabled: (!!activeFocusItem && !!activeFocusItem["paste"]) - onTriggered: activeFocusItem.paste() - } - -// toolBar: ToolBar { -// RowLayout { -// anchors.fill: parent -// anchors.margins: spacing -// Label { -// text: UI.label -// } -// Item { Layout.fillWidth: true } -// CheckBox { -// id: enabler -// text: "Enabled" -// checked: true -// } -// } -// } - -// menuBar: MenuBar { -// Menu { -// title: "&File" -// MenuItem { -// text: "E&xit" -// shortcut: StandardKey.Quit -// onTriggered: Qt.quit() -// } -// } -// Menu { -// title: "&Edit" -// visible: tabView.currentIndex == 2 -// MenuItem { action: cutAction } -// MenuItem { action: copyAction } -// MenuItem { action: pasteAction } -// } -// Menu { -// title: "&Help" -// MenuItem { -// text: "About..." -// onTriggered: aboutDialog.open() -// } -// } -// } - - TabView { - id: tabView - - anchors.fill: parent - anchors.margins: UI.margin - tabPosition: UI.tabPosition - - Layout.minimumWidth: 360 - Layout.minimumHeight: 360 - Layout.preferredWidth: 480 - Layout.preferredHeight: 640 - - Tab { - title: "Buttons" - ButtonPage { - enabled: enabler.checked - } - } - Tab { - title: "Progress" - ProgressPage { - enabled: enabler.checked - } - } - Tab { - title: "Input" - InputPage { - enabled: enabler.checked - } - } - } -} diff --git a/tests-manual/ui/qml/main.qml b/tests-manual/ui/qml/main.qml deleted file mode 100644 index 607bd624a1..0000000000 --- a/tests-manual/ui/qml/main.qml +++ /dev/null @@ -1,461 +0,0 @@ -import QtQuick 2.5 -import QtQuick.Controls 1.4 -import QtQuick.Dialogs 1.2 as OriginalDialogs -import Qt.labs.settings 1.0 - -import "../../../interface/resources/qml" -//import "../../../interface/resources/qml/windows" -import "../../../interface/resources/qml/windows" -import "../../../interface/resources/qml/dialogs" -import "../../../interface/resources/qml/hifi" -import "../../../interface/resources/qml/hifi/dialogs" -import "../../../interface/resources/qml/styles-uit" - -ApplicationWindow { - id: appWindow - objectName: "MainWindow" - visible: true - width: 1280 - height: 800 - title: qsTr("Scratch App") - toolBar: Row { - id: testButtons - anchors { margins: 8; left: parent.left; top: parent.top } - spacing: 8 - property int count: 0 - - property var tabs: []; - property var urls: []; - property var toolbar; - property var lastButton; - - Button { - text: HMD.active ? "Disable HMD" : "Enable HMD" - onClicked: HMD.active = !HMD.active - } - - Button { - text: desktop.hmdHandMouseActive ? "Disable HMD HandMouse" : "Enable HMD HandMouse" - onClicked: desktop.hmdHandMouseActive = !desktop.hmdHandMouseActive - } - - // Window visibility - Button { - text: "toggle desktop" - onClicked: desktop.togglePinned() - } - - Button { - text: "Create Toolbar" - onClicked: testButtons.toolbar = desktop.getToolbar("com.highfidelity.interface.toolbar.system"); - } - - Button { - text: "Toggle Toolbar Direction" - onClicked: testButtons.toolbar.horizontal = !testButtons.toolbar.horizontal - } - - Button { - readonly property var icons: [ - "edit-01.svg", - "model-01.svg", - "cube-01.svg", - "sphere-01.svg", - "light-01.svg", - "text-01.svg", - "web-01.svg", - "zone-01.svg", - "particle-01.svg", - ] - property int iconIndex: 0 - readonly property string toolIconUrl: "../../../../../scripts/system/assets/images/tools/" - text: "Create Button" - onClicked: { - var name = icons[iconIndex]; - var url = toolIconUrl + name; - iconIndex = (iconIndex + 1) % icons.length; - var button = testButtons.lastButton = testButtons.toolbar.addButton({ - imageURL: url, - objectName: name, - subImage: { - y: 50, - }, - alpha: 0.9 - }); - - button.clicked.connect(function(){ - console.log("Clicked on button " + button.imageURL + " alpha " + button.alpha) - }); - } - } - - Button { - text: "Toggle Button Visible" - onClicked: testButtons.lastButton.visible = !testButtons.lastButton.visible - } - - // Error alerts - /* - Button { - // Message without title. - text: "Show Error" - onClicked: { - var messageBox = desktop.messageBox({ - text: "Diagnostic cycle will be complete in 30 seconds", - icon: hifi.icons.critical, - }); - messageBox.selected.connect(function(button) { - console.log("You clicked " + button) - }) - } - } - Button { - // detailedText is not currently used anywhere in Interface but it is easier to leave in and style good enough. - text: "Show Long Error" - onClicked: { - desktop.messageBox({ - informativeText: "Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds Diagnostic cycle will be complete in 30 seconds ", - text: "Baloney", - icon: hifi.icons.warning, - detailedText: "sakjd;laskj dksa;dl jka;lsd j;lkjas ;dlkaj s;dlakjd ;alkjda; slkjda; lkjda;lksjd ;alksjd; alksjd ;alksjd; alksjd; alksdjas;ldkjas;lkdja ;kj ;lkasjd; lkj as;dlka jsd;lka jsd;laksjd a" - }); - } - } - */ - - // query - /* - // There is no such desktop.queryBox() function; may need to update test to cover QueryDialog.qml? - Button { - text: "Show Query" - onClicked: { - var queryBox = desktop.queryBox({ - text: "Have you stopped beating your wife?", - placeholderText: "Are you sure?", - // icon: hifi.icons.critical, - }); - queryBox.selected.connect(function(result) { - console.log("User responded with " + result); - }); - - queryBox.canceled.connect(function() { - console.log("User cancelled query box "); - }) - } - } - */ - - // Browser - /* - Button { - text: "Open Browser" - onClicked: builder.createObject(desktop); - property var builder: Component { - Browser {} - } - } - */ - - - // file dialog - /* - - Button { - text: "Open Directory" - property var builder: Component { - FileDialog { selectDirectory: true } - } - - onClicked: { - var fileDialog = builder.createObject(desktop); - fileDialog.canceled.connect(function(){ - console.log("Cancelled") - }) - fileDialog.selectedFile.connect(function(file){ - console.log("Selected " + file) - }) - } - } - Button { - text: "Open File" - property var builder: Component { - FileDialog { - title: "Open File" - filter: "All Files (*.*)" - //filter: "HTML files (*.html);;Other(*.png)" - } - } - - onClicked: { - var fileDialog = builder.createObject(desktop); - fileDialog.canceled.connect(function(){ - console.log("Cancelled") - }) - fileDialog.selectedFile.connect(function(file){ - console.log("Selected " + file) - }) - } - } - */ - - // tabs - /* - Button { - text: "Add Tab" - onClicked: { - console.log(desktop.toolWindow); - desktop.toolWindow.addWebTab({ source: "Foo" }); - desktop.toolWindow.showTabForUrl("Foo", true); - } - } - - Button { - text: "Add Tab 2" - onClicked: { - console.log(desktop.toolWindow); - desktop.toolWindow.addWebTab({ source: "Foo 2" }); - desktop.toolWindow.showTabForUrl("Foo 2", true); - } - } - - Button { - text: "Add Tab 3" - onClicked: { - console.log(desktop.toolWindow); - desktop.toolWindow.addWebTab({ source: "Foo 3" }); - desktop.toolWindow.showTabForUrl("Foo 3", true); - } - } - - Button { - text: "Destroy Tab" - onClicked: { - console.log(desktop.toolWindow); - desktop.toolWindow.removeTabForUrl("Foo"); - } - } - */ - - // Hifi specific stuff - /* - Button { - // Shows the dialog with preferences sections but not each section's preference items - // because Preferences.preferencesByCategory() method is not stubbed out. - text: "Settings > General..." - property var builder: Component { - GeneralPreferencesDialog { } - } - onClicked: { - var runningScripts = builder.createObject(desktop); - } - } - - Button { - text: "Running Scripts" - property var builder: Component { - RunningScripts { } - } - onClicked: { - var runningScripts = builder.createObject(desktop); - } - } - - Button { - text: "Attachments" - property var builder: Component { - AttachmentsDialog { } - } - onClicked: { - var attachmentsDialog = builder.createObject(desktop); - } - } - Button { - // Replicates message box that pops up after selecting new avatar. Includes title. - text: "Confirm Avatar" - onClicked: { - var messageBox = desktop.messageBox({ - title: "Set Avatar", - text: "Would you like to use 'Albert' for your avatar?", - icon: hifi.icons.question, // Test question icon - //icon: hifi.icons.information, // Test informaton icon - //icon: hifi.icons.warning, // Test warning icon - //icon: hifi.icons.critical, // Test critical icon - //icon: hifi.icons.none, // Test no icon - buttons: OriginalDialogs.StandardButton.Ok + OriginalDialogs.StandardButton.Cancel, - defaultButton: OriginalDialogs.StandardButton.Ok - }); - messageBox.selected.connect(function(button) { - console.log("You clicked " + button) - }) - } - } - */ - // bookmarks - /* - Button { - text: "Bookmark Location" - onClicked: { - desktop.inputDialog({ - title: "Bookmark Location", - icon: hifi.icons.placemark, - label: "Name" - }); - } - } - Button { - text: "Delete Bookmark" - onClicked: { - desktop.inputDialog({ - title: "Delete Bookmark", - icon: hifi.icons.placemark, - label: "Select the bookmark to delete", - items: ["Bookmark A", "Bookmark B", "Bookmark C"] - }); - } - } - Button { - text: "Duplicate Bookmark" - onClicked: { - desktop.messageBox({ - title: "Duplicate Bookmark", - icon: hifi.icons.warning, - text: "The bookmark name you entered alread exists in yoru list.", - informativeText: "Would you like to overwrite it?", - buttons: OriginalDialogs.StandardButton.Yes + OriginalDialogs.StandardButton.No, - defaultButton: OriginalDialogs.StandardButton.Yes - }); - } - } - */ - - } - - - HifiConstants { id: hifi } - - Desktop { - id: desktop - anchors.fill: parent - - //rootMenu: StubMenu { id: rootMenu } - //Component.onCompleted: offscreenWindow = appWindow - - /* - MouseArea { - anchors.fill: parent - acceptedButtons: Qt.RightButton - onClicked: desktop.popupMenu(Qt.vector2d(mouseX, mouseY)); - } - */ - - Browser { - url: "http://s3.amazonaws.com/DreamingContent/testUiDelegates.html" - } - - - Window { - id: blue - closable: true - visible: true - resizable: true - destroyOnHidden: false - title: "Blue" - - width: 100; height: 100 - x: 1280 / 2; y: 720 / 2 - Settings { - category: "TestWindow.Blue" - property alias x: blue.x - property alias y: blue.y - property alias width: blue.width - property alias height: blue.height - } - - Rectangle { - anchors.fill: parent - visible: true - color: "blue" - Component.onDestruction: console.log("Blue destroyed") - } - } - - Window { - id: green - closable: true - visible: true - resizable: true - title: "Green" - destroyOnHidden: false - - width: 100; height: 100 - x: 1280 / 2; y: 720 / 2 - Settings { - category: "TestWindow.Green" - property alias x: green.x - property alias y: green.y - property alias width: green.width - property alias height: green.height - } - - Rectangle { - anchors.fill: parent - visible: true - color: "green" - Component.onDestruction: console.log("Green destroyed") - } - } - -/* - Rectangle { width: 100; height: 100; x: 100; y: 100; color: "#00f" } - - Window { - id: green - alwaysOnTop: true - frame: HiddenFrame{} - hideBackground: true - closable: true - visible: true - resizable: false - x: 1280 / 2; y: 720 / 2 - width: 100; height: 100 - Rectangle { - color: "#0f0" - width: green.width; - height: green.height; - } - } - */ - -/* - Window { - id: yellow - closable: true - visible: true - resizable: true - x: 100; y: 100 - width: 100; height: 100 - Rectangle { - anchors.fill: parent - visible: true - color: "yellow" - } - } -*/ - } - - Action { - id: openBrowserAction - text: "Open Browser" - shortcut: "Ctrl+Shift+X" - onTriggered: { - builder.createObject(desktop); - } - property var builder: Component { - ModelBrowserDialog{} - } - } -} - - - - diff --git a/tests-manual/ui/qmlscratch.pro b/tests-manual/ui/qmlscratch.pro index 5c9b91ee52..3287180d26 100644 --- a/tests-manual/ui/qmlscratch.pro +++ b/tests-manual/ui/qmlscratch.pro @@ -4,34 +4,10 @@ QT += gui qml quick xml webengine widgets CONFIG += c++11 -SOURCES += src/main.cpp \ - ../../libraries/ui/src/FileDialogHelper.cpp - -HEADERS += \ - ../../libraries/ui/src/FileDialogHelper.h +SOURCES += src/main.cpp # Additional import path used to resolve QML modules in Qt Creator's code model QML_IMPORT_PATH = ../../interface/resources/qml - DISTFILES += \ - qml/*.qml \ - ../../interface/resources/QtWebEngine/UIDelegates/original/*.qml \ - ../../interface/resources/QtWebEngine/UIDelegates/*.qml \ - ../../interface/resources/qml/*.qml \ - ../../interface/resources/qml/controls/*.qml \ - ../../interface/resources/qml/controls-uit/*.qml \ - ../../interface/resources/qml/dialogs/*.qml \ - ../../interface/resources/qml/dialogs/fileDialog/*.qml \ - ../../interface/resources/qml/dialogs/preferences/*.qml \ - ../../interface/resources/qml/dialogs/messageDialog/*.qml \ - ../../interface/resources/qml/desktop/*.qml \ - ../../interface/resources/qml/menus/*.qml \ - ../../interface/resources/qml/styles/*.qml \ - ../../interface/resources/qml/styles-uit/*.qml \ - ../../interface/resources/qml/windows/*.qml \ - ../../interface/resources/qml/hifi/*.qml \ - ../../interface/resources/qml/hifi/toolbars/*.qml \ - ../../interface/resources/qml/hifi/dialogs/*.qml \ - ../../interface/resources/qml/hifi/dialogs/preferences/*.qml \ - ../../interface/resources/qml/hifi/overlays/*.qml + qml/*.qml diff --git a/tests-manual/ui/src/main.cpp b/tests-manual/ui/src/main.cpp index 312b5f3823..a5061f4d01 100644 --- a/tests-manual/ui/src/main.cpp +++ b/tests-manual/ui/src/main.cpp @@ -3,88 +3,31 @@ #include #include -#include "../../../libraries/ui/src/FileDialogHelper.h" - - -class Preference : public QObject { - Q_OBJECT - Q_PROPERTY(QString category READ getCategory() CONSTANT) - Q_PROPERTY(QString name READ getName() CONSTANT) - Q_PROPERTY(Type type READ getType() CONSTANT) - Q_ENUMS(Type) -public: - enum Type { - Editable, - Browsable, - Spinner, - Checkbox, - }; - - Preference(QObject* parent = nullptr) : QObject(parent) {} - - Preference(const QString& category, const QString& name, QObject* parent = nullptr) - : QObject(parent), _category(category), _name(name) { } - const QString& getCategory() const { return _category; } - const QString& getName() const { return _name; } - virtual Type getType() { return Editable; } - -protected: - const QString _category; - const QString _name; -}; - -class Reticle : public QObject { - Q_OBJECT - Q_PROPERTY(QPoint position READ getPosition CONSTANT) -public: - - Reticle(QObject* parent) : QObject(parent) { - } - - QPoint getPosition() { - if (!_window) { - return QPoint(0, 0); - } - return _window->mapFromGlobal(QCursor::pos()); - } - - void setWindow(QWindow* window) { - _window = window; - } - -private: - QWindow* _window{nullptr}; -}; - QString getRelativeDir(const QString& relativePath = ".") { - QDir path(__FILE__); path.cdUp(); + QDir path(__FILE__); + path.cdUp(); + path.cdUp(); auto result = path.absoluteFilePath(relativePath); result = path.cleanPath(result) + "/"; return result; } -QString getTestQmlDir() { - return getRelativeDir("../qml"); +QString getResourcesDir() { + return getRelativeDir("../../interface/resources"); } -QString getInterfaceQmlDir() { - return getRelativeDir("/"); +QString getQmlDir() { + return getRelativeDir("../../interface/resources/qml"); } - -void setChild(QQmlApplicationEngine& engine, const char* name) { - for (auto obj : engine.rootObjects()) { - auto child = obj->findChild(QString(name)); - if (child) { - engine.rootContext()->setContextProperty(name, child); - return; - } - } - qWarning() << "Could not find object named " << name; +QString getScriptsDir() { + return getRelativeDir("../../scripts"); } void addImportPath(QQmlApplicationEngine& engine, const QString& relativePath, bool insert = false) { QString resolvedPath = getRelativeDir(relativePath); + + qDebug() << "adding import path: " << QDir::toNativeSeparators(resolvedPath); engine.addImportPath(resolvedPath); } @@ -93,44 +36,24 @@ int main(int argc, char *argv[]) { app.setOrganizationName("Some Company"); app.setOrganizationDomain("somecompany.com"); app.setApplicationName("Amazing Application"); - QDir::setCurrent(getRelativeDir("..")); - QtWebEngine::initialize(); - qmlRegisterType("Hifi", 1, 0, "Preference"); + auto scriptsDir = getScriptsDir(); + auto resourcesDir = getResourcesDir(); QQmlApplicationEngine engine; + addImportPath(engine, "."); addImportPath(engine, "qml"); - addImportPath(engine, "../../interface/resources/qml"); - addImportPath(engine, "../../interface/resources"); - engine.load(QUrl(QStringLiteral("qml/Stubs.qml"))); + addImportPath(engine, resourcesDir); + addImportPath(engine, resourcesDir + "/qml"); + addImportPath(engine, scriptsDir); + addImportPath(engine, scriptsDir + "/developer/tests"); - setChild(engine, "offscreenFlags"); - setChild(engine, "Account"); - setChild(engine, "ApplicationCompositor"); - setChild(engine, "Controller"); - setChild(engine, "Desktop"); - setChild(engine, "ScriptDiscoveryService"); - setChild(engine, "HMD"); - setChild(engine, "GL"); - setChild(engine, "MenuHelper"); - setChild(engine, "Preferences"); - setChild(engine, "urlHandler"); - engine.rootContext()->setContextProperty("DebugQML", true); - engine.rootContext()->setContextProperty("fileDialogHelper", new FileDialogHelper()); + QFontDatabase::addApplicationFont(resourcesDir + "/fonts/FiraSans-Regular.ttf"); + QFontDatabase::addApplicationFont(resourcesDir + "/fonts/FiraSans-SemiBold.ttf"); + QFontDatabase::addApplicationFont(resourcesDir + "/fonts/hifi-glyphs.ttf"); - //engine.load(QUrl(QStringLiteral("qrc:/qml/gallery/main.qml"))); - engine.load(QUrl(QStringLiteral("qml/main.qml"))); - for (QObject* rootObject : engine.rootObjects()) { - if (rootObject->objectName() == "MainWindow") { - Reticle* reticle = new Reticle(rootObject); - reticle->setWindow((QWindow*)rootObject); - engine.rootContext()->setContextProperty("Reticle", reticle); - engine.rootContext()->setContextProperty("Window", rootObject); - break; - } - } + auto url = getRelativeDir(".") + "qml/ControlsGalleryWindow.qml"; + + engine.load(url); return app.exec(); } - -#include "main.moc" - diff --git a/tests/recording/src/main.cpp b/tests/recording/src/main.cpp index 1b4e5adf6d..6181906ff0 100644 --- a/tests/recording/src/main.cpp +++ b/tests/recording/src/main.cpp @@ -1,8 +1,28 @@ +// +// main.cpp +// tests/recording/src +// +// Created by Bradley Austin Davis on 11/06/15. +// Copyright 2018 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 +// + +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wunused-private-field" +#endif + #include #include #include #include +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + #ifdef Q_OS_WIN32 #include #endif diff --git a/tools/auto-tester/AppDataHighFidelity/Interface.json b/tools/auto-tester/AppDataHighFidelity/Interface.json new file mode 100644 index 0000000000..ca91a092c8 --- /dev/null +++ b/tools/auto-tester/AppDataHighFidelity/Interface.json @@ -0,0 +1,285 @@ +{ + "AddressManager/address": "hifi://localhost/1.07449e-05,0,-0.0174923/0,0,0,1", + "Audio/Desktop/INPUT": "Microphone (Realtek Audio)", + "Audio/Desktop/OUTPUT": "Speakers / Headphones (Realtek Audio)", + "Audio/VR/INPUT": "Microphone (Realtek Audio)", + "Audio/VR/OUTPUT": "Speakers / Headphones (Realtek Audio)", + "Avatar/Avatar/fullAvatarURL": "", + "Avatar/Debug Draw Animation": false, + "Avatar/Debug Draw Base of Support": false, + "Avatar/Debug Draw Default Pose": false, + "Avatar/Debug Draw Position": false, + "Avatar/Disable Eyelid Adjustment": false, + "Avatar/Draw Mesh": true, + "Avatar/Enable Default Motor Control": true, + "Avatar/Enable Inverse Kinematics": true, + "Avatar/Enable LookAt Snapping": true, + "Avatar/Enable Scripted Motor Control": true, + "Avatar/Face Tracking/Auto Mute Microphone": false, + "Avatar/Face Tracking/Binary Eyelid Control": true, + "Avatar/Face Tracking/Couple Eyelids": true, + "Avatar/Face Tracking/Mute Face Tracking": true, + "Avatar/Face Tracking/None": false, + "Avatar/Face Tracking/Use Audio for Mouth": true, + "Avatar/Face Tracking/Use Camera": true, + "Avatar/Face Tracking/Velocity Filter": true, + "Avatar/Fix Gaze (no saccade)": false, + "Avatar/Show Bounding Collision Shapes": false, + "Avatar/Show Detailed Collision": false, + "Avatar/Show IK Chains": false, + "Avatar/Show IK Constraints": false, + "Avatar/Show IK Targets": false, + "Avatar/Show My Eye Vectors": false, + "Avatar/Show Other Eye Vectors": false, + "Avatar/Show Receive Stats": false, + "Avatar/Show SensorToWorld Matrix": false, + "Avatar/Toggle Hips Following": false, + "Avatar/Turn using Head": false, + "Avatar/animGraphURL": "", + "Avatar/attachmentData/size": 0, + "Avatar/avatarEntityData/size": 0, + "Avatar/collisionSoundURL": "https://hifi-public.s3.amazonaws.com/sounds/Collisions-otherorganic/Body_Hits_Impact.wav", + "Avatar/displayName": "", + "Avatar/dominantHand": "right", + "Avatar/flyingHMD": false, + "Avatar/fullAvatarModelName": "Default", + "Avatar/fullAvatarURL": "", + "Avatar/headPitch": 0, + "Avatar/pitchSpeed": 75, + "Avatar/scale": 1, + "Avatar/useSnapTurn": true, + "Avatar/userHeight": 1.7549999952316284, + "Avatar/yawSpeed": 100, + "Developer/Avatar/Debug Draw Animation": false, + "Developer/Avatar/Debug Draw Base of Support": false, + "Developer/Avatar/Debug Draw Default Pose": false, + "Developer/Avatar/Debug Draw Position": false, + "Developer/Avatar/Disable Eyelid Adjustment": false, + "Developer/Avatar/Draw Mesh": true, + "Developer/Avatar/Enable Default Motor Control": true, + "Developer/Avatar/Enable Inverse Kinematics": true, + "Developer/Avatar/Enable LookAt Snapping": true, + "Developer/Avatar/Enable Scripted Motor Control": true, + "Developer/Avatar/Face Tracking/Auto Mute Microphone": false, + "Developer/Avatar/Face Tracking/Binary Eyelid Control": true, + "Developer/Avatar/Face Tracking/Couple Eyelids": true, + "Developer/Avatar/Face Tracking/Mute Face Tracking": true, + "Developer/Avatar/Face Tracking/None": false, + "Developer/Avatar/Face Tracking/Use Audio for Mouth": true, + "Developer/Avatar/Face Tracking/Use Camera": true, + "Developer/Avatar/Face Tracking/Velocity Filter": true, + "Developer/Avatar/Fix Gaze (no saccade)": false, + "Developer/Avatar/Show Bounding Collision Shapes": false, + "Developer/Avatar/Show Detailed Collision": false, + "Developer/Avatar/Show IK Chains": false, + "Developer/Avatar/Show IK Constraints": false, + "Developer/Avatar/Show IK Targets": false, + "Developer/Avatar/Show My Eye Vectors": false, + "Developer/Avatar/Show Other Eye Vectors": false, + "Developer/Avatar/Show Receive Stats": false, + "Developer/Avatar/Show SensorToWorld Matrix": false, + "Developer/Avatar/Toggle Hips Following": false, + "Developer/Avatar/Turn using Head": false, + "Developer/Debug defaultScripts.js": false, + "Developer/Display Crash Options": true, + "Developer/Enable Speech Control API": false, + "Developer/Entities/Show Realtime Entity Stats": false, + "Developer/Hands/Show Hand Targets": false, + "Developer/Network/Disable Activity Logger": false, + "Developer/Network/Send wrong DS connect version": false, + "Developer/Network/Send wrong protocol version": false, + "Developer/Physics/Highlight Simulation Ownership": false, + "Developer/Physics/Show Bullet Bounding Boxes": false, + "Developer/Physics/Show Bullet Collision": false, + "Developer/Physics/Show Bullet Constraint Limits": false, + "Developer/Physics/Show Bullet Constraints": false, + "Developer/Physics/Show Bullet Contact Points": false, + "Developer/Picking/Force Coarse Picking": false, + "Developer/Render/Ambient Occlusion": false, + "Developer/Render/Compute Blendshapes": true, + "Developer/Render/Decimate Textures": false, + "Developer/Render/Default Skybox": true, + "Developer/Render/Enable Sparse Texture Management": true, + "Developer/Render/Maximum Texture Memory/1024 MB": false, + "Developer/Render/Maximum Texture Memory/2048 MB": false, + "Developer/Render/Maximum Texture Memory/256 MB": false, + "Developer/Render/Maximum Texture Memory/4 MB": false, + "Developer/Render/Maximum Texture Memory/4096 MB": false, + "Developer/Render/Maximum Texture Memory/512 MB": false, + "Developer/Render/Maximum Texture Memory/6144 MB": false, + "Developer/Render/Maximum Texture Memory/64 MB": false, + "Developer/Render/Maximum Texture Memory/8192 MB": false, + "Developer/Render/Maximum Texture Memory/Automatic Texture Memory": true, + "Developer/Render/OpenVR Threaded Submit": true, + "Developer/Render/Scale Resolution/1": true, + "Developer/Render/Scale Resolution/1/2": false, + "Developer/Render/Scale Resolution/1/3": false, + "Developer/Render/Scale Resolution/1/4": false, + "Developer/Render/Scale Resolution/2/3": false, + "Developer/Render/Shadows": true, + "Developer/Render/Temporal Antialiasing (FXAA if disabled)": true, + "Developer/Render/Throttle FPS If Not Focus": true, + "Developer/Render/World Axes": false, + "Developer/Show Animation Stats": false, + "Developer/Show Overlays": true, + "Developer/Show Statistics": false, + "Developer/Timing/Log Extra Timing Details": false, + "Developer/Timing/Log Render Pipeline Warnings": false, + "Developer/Timing/Performance Timer/Display Timing Details": false, + "Developer/Timing/Performance Timer/Expand /myAvatar": false, + "Developer/Timing/Performance Timer/Expand /myAvatar/simulation": false, + "Developer/Timing/Performance Timer/Expand /otherAvatar": false, + "Developer/Timing/Performance Timer/Expand /paintGL": false, + "Developer/Timing/Performance Timer/Expand /physics": false, + "Developer/Timing/Performance Timer/Expand /simulation": false, + "Developer/Timing/Performance Timer/Expand /update": false, + "Developer/Timing/Performance Timer/Only Display Top Ten": true, + "Developer/Timing/Show Timer": false, + "Developer/Timing/Suppress Timings Less than 10ms": false, + "Developer/UI/Desktop Tablet Becomes Toolbar": true, + "Developer/UI/HMD Tablet Becomes Toolbar": false, + "Developer/Verbose Logging": false, + "Display/3D TV - Interleaved": false, + "Display/3D TV - Side by Side Stereo": false, + "Display/Desktop": true, + "Display/Fullscreen": false, + "Display/Oculus Rift": false, + "Display/Oculus Rift (Simulator)": false, + "Edit/Allow Selecting of Large Models": true, + "Edit/Allow Selecting of Lights": true, + "Edit/Allow Selecting of Small Models": true, + "Edit/Auto Focus on Select": false, + "Edit/Create Entities As Grabbable (except Zones, Particles, and Lights)": true, + "Edit/Ease Orientation on Focus": false, + "Edit/Show Lights and Particle Systems in Create Mode": true, + "Edit/Show Zones in Create Mode": true, + "Entities/Show Realtime Entity Stats": false, + "Face Tracking/Auto Mute Microphone": false, + "Face Tracking/Binary Eyelid Control": true, + "Face Tracking/Couple Eyelids": true, + "Face Tracking/Mute Face Tracking": true, + "Face Tracking/None": false, + "Face Tracking/Use Audio for Mouth": true, + "Face Tracking/Use Camera": true, + "Face Tracking/Velocity Filter": true, + "Hands/Show Hand Targets": false, + "Leap Motion/desktopHeightOffset": 0.20000000298023224, + "Leap Motion/enabled": false, + "Leap Motion/sensorLocation": "Desktop", + "Maximum Texture Memory/1024 MB": false, + "Maximum Texture Memory/2048 MB": false, + "Maximum Texture Memory/256 MB": false, + "Maximum Texture Memory/4 MB": false, + "Maximum Texture Memory/4096 MB": false, + "Maximum Texture Memory/512 MB": false, + "Maximum Texture Memory/6144 MB": false, + "Maximum Texture Memory/64 MB": false, + "Maximum Texture Memory/8192 MB": false, + "Maximum Texture Memory/Automatic Texture Memory": true, + "Network/Disable Activity Logger": false, + "Network/Send wrong DS connect version": false, + "Network/Send wrong protocol version": false, + "Perception Neuron/enabled": false, + "Perception Neuron/serverAddress": "localhost", + "Perception Neuron/serverPort": 7001, + "Performance Timer/Display Timing Details": false, + "Performance Timer/Expand /myAvatar": false, + "Performance Timer/Expand /myAvatar/simulation": false, + "Performance Timer/Expand /otherAvatar": false, + "Performance Timer/Expand /paintGL": false, + "Performance Timer/Expand /physics": false, + "Performance Timer/Expand /simulation": false, + "Performance Timer/Expand /update": false, + "Performance Timer/Only Display Top Ten": true, + "Physics/Highlight Simulation Ownership": false, + "Physics/Show Bullet Bounding Boxes": false, + "Physics/Show Bullet Collision": false, + "Physics/Show Bullet Constraint Limits": false, + "Physics/Show Bullet Constraints": false, + "Physics/Show Bullet Contact Points": false, + "Picking/Force Coarse Picking": false, + "Render/Ambient Occlusion": false, + "Render/Compute Blendshapes": true, + "Render/Decimate Textures": false, + "Render/Default Skybox": true, + "Render/Enable Sparse Texture Management": true, + "Render/Maximum Texture Memory/1024 MB": false, + "Render/Maximum Texture Memory/2048 MB": false, + "Render/Maximum Texture Memory/256 MB": false, + "Render/Maximum Texture Memory/4 MB": false, + "Render/Maximum Texture Memory/4096 MB": false, + "Render/Maximum Texture Memory/512 MB": false, + "Render/Maximum Texture Memory/6144 MB": false, + "Render/Maximum Texture Memory/64 MB": false, + "Render/Maximum Texture Memory/8192 MB": false, + "Render/Maximum Texture Memory/Automatic Texture Memory": true, + "Render/OpenVR Threaded Submit": true, + "Render/Scale Resolution/1": true, + "Render/Scale Resolution/1/2": false, + "Render/Scale Resolution/1/3": false, + "Render/Scale Resolution/1/4": false, + "Render/Scale Resolution/2/3": false, + "Render/Shadows": true, + "Render/Temporal Antialiasing (FXAA if disabled)": true, + "Render/Throttle FPS If Not Focus": true, + "Render/World Axes": false, + "RunningScripts": [ + "file:///~//defaultScripts.js" + ], + "SDL2/enabled": true, + "Scale Resolution/1": true, + "Scale Resolution/1/2": false, + "Scale Resolution/1/3": false, + "Scale Resolution/1/4": false, + "Scale Resolution/2/3": false, + "Settings/Ask To Reset Settings on Start": false, + "Settings/Developer Menu": false, + "TabletSounds": "@Variant(\u0000\u0000\u0000\u000b\u0000\u0000\u0000\u0005\u0000\u0000\u0000(\u0000/\u0000s\u0000o\u0000u\u0000n\u0000d\u0000s\u0000/\u0000B\u0000u\u0000t\u0000t\u0000o\u0000n\u00000\u00006\u0000.\u0000w\u0000a\u0000v\u0000\u0000\u0000(\u0000/\u0000s\u0000o\u0000u\u0000n\u0000d\u0000s\u0000/\u0000B\u0000u\u0000t\u0000t\u0000o\u0000n\u00000\u00004\u0000.\u0000w\u0000a\u0000v\u0000\u0000\u0000(\u0000/\u0000s\u0000o\u0000u\u0000n\u0000d\u0000s\u0000/\u0000B\u0000u\u0000t\u0000t\u0000o\u0000n\u00000\u00007\u0000.\u0000w\u0000a\u0000v\u0000\u0000\u0000\"\u0000/\u0000s\u0000o\u0000u\u0000n\u0000d\u0000s\u0000/\u0000T\u0000a\u0000b\u00000\u00001\u0000.\u0000w\u0000a\u0000v\u0000\u0000\u0000\"\u0000/\u0000s\u0000o\u0000u\u0000n\u0000d\u0000s\u0000/\u0000T\u0000a\u0000b\u00000\u00002\u0000.\u0000w\u0000a\u0000v)", + "Timing/Log Extra Timing Details": false, + "Timing/Log Render Pipeline Warnings": false, + "Timing/Performance Timer/Display Timing Details": false, + "Timing/Performance Timer/Expand /myAvatar": false, + "Timing/Performance Timer/Expand /myAvatar/simulation": false, + "Timing/Performance Timer/Expand /otherAvatar": false, + "Timing/Performance Timer/Expand /paintGL": false, + "Timing/Performance Timer/Expand /physics": false, + "Timing/Performance Timer/Expand /simulation": false, + "Timing/Performance Timer/Expand /update": false, + "Timing/Performance Timer/Only Display Top Ten": true, + "Timing/Show Timer": false, + "Timing/Suppress Timings Less than 10ms": false, + "UI/Desktop Tablet Becomes Toolbar": true, + "UI/HMD Tablet Becomes Toolbar": false, + "UserActivityLoggerDisabled": false, + "View/Center Player In View": true, + "View/Enter First Person Mode in HMD": true, + "View/Entity Mode": false, + "View/First Person": true, + "View/Independent Mode": false, + "View/Mirror": false, + "View/Third Person": false, + "WindowGeometry": "@Rect(0 0 1920 1080)", + "WindowRoot.Windows/height": 706, + "WindowRoot.Windows/width": 480, + "WindowState": 0, + "activeDisplayPlugin": "Desktop", + "autoFocusOnSelect": true, + "cameraEaseOnFocus": true, + "desktopLODDecreaseFPS": 30.000001907348633, + "dynamicJitterBuffersEnabled": true, + "firstRun": false, + "hifi.ktx.cache_version": 1, + "hmdLODDecreaseFPS": 34, + "io.highfidelity.attachPoints": "{}", + "io.highfidelity.isEditing": false, + "loginDialogPoppedUp": false, + "sessionRunTime": 42, + "showLightsAndParticlesInEditMode": true, + "showZonesInEditMode": true, + "staticJitterBufferFrames": 1, + "toolbar/com.highfidelity.interface.toolbar.system/desktopHeight": 1059, + "toolbar/com.highfidelity.interface.toolbar.system/x": 655, + "toolbar/com.highfidelity.interface.toolbar.system/y": 953, + "toolbar/constrainToolbarToCenterX": true, + "wallet/autoLogout": true +} diff --git a/tools/auto-tester/AppDataHighFidelity/Interface/AccountInfo.bin b/tools/auto-tester/AppDataHighFidelity/Interface/AccountInfo.bin new file mode 100644 index 0000000000..65c971ea79 Binary files /dev/null and b/tools/auto-tester/AppDataHighFidelity/Interface/AccountInfo.bin differ diff --git a/tools/auto-tester/AppDataHighFidelity/Interface/avatarbookmarks.json b/tools/auto-tester/AppDataHighFidelity/Interface/avatarbookmarks.json new file mode 100644 index 0000000000..9976036f8e --- /dev/null +++ b/tools/auto-tester/AppDataHighFidelity/Interface/avatarbookmarks.json @@ -0,0 +1,861 @@ +{ + "Anime boy": { + "attachments": [ + ], + "avatarEntites": [ + { + "properties": { + "acceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "actionData": "", + "age": 6.915350914001465, + "ageAsText": "0 hours 0 minutes 6 seconds", + "angularDamping": 0.39346998929977417, + "angularVelocity": { + "x": 0, + "y": 0, + "z": 0 + }, + "animation": { + "allowTranslation": true, + "currentFrame": 0, + "firstFrame": 0, + "fps": 30, + "hold": false, + "lastFrame": 100000, + "loop": true, + "running": false, + "url": "" + }, + "boundingBox": { + "brn": { + "x": -0.10961885005235672, + "y": -0.19444090127944946, + "z": -0.15760529041290283 + }, + "center": { + "x": 2.6226043701171875e-06, + "y": -0.13999652862548828, + "z": -0.04999971389770508 + }, + "dimensions": { + "x": 0.21924294531345367, + "y": 0.10888873785734177, + "z": 0.2152111530303955 + }, + "tfl": { + "x": 0.10962409526109695, + "y": -0.0855521634221077, + "z": 0.057605862617492676 + } + }, + "canCastShadow": true, + "certificateID": "", + "clientOnly": true, + "cloneAvatarEntity": false, + "cloneDynamic": false, + "cloneLifetime": 300, + "cloneLimit": 0, + "cloneOriginID": "{00000000-0000-0000-0000-000000000000}", + "cloneable": false, + "collidesWith": "", + "collisionMask": 0, + "collisionSoundURL": "", + "collisionless": false, + "collisionsWillMove": false, + "compoundShapeURL": "", + "created": "2018-06-06T17:27:53Z", + "damping": 0.39346998929977417, + "density": 1000, + "description": "", + "dimensions": { + "x": 0.21924294531345367, + "y": 0.07768379896879196, + "z": 0.2055898904800415 + }, + "dynamic": false, + "editionNumber": 15, + "entityInstanceNumber": 0, + "friction": 0.5, + "gravity": { + "x": 0, + "y": 0, + "z": 0 + }, + "href": "", + "id": "{5d20c775-a0d7-4163-b158-4e0a784a4625}", + "ignoreForCollisions": false, + "itemArtist": "jyoum", + "itemCategories": "Wearables", + "itemDescription": "Wear these, and others will respect your authoritah.", + "itemLicense": "", + "itemName": "Aviators", + "jointRotations": [ + ], + "jointRotationsSet": [ + ], + "jointTranslations": [ + ], + "jointTranslationsSet": [ + ], + "lastEdited": 1528306178314655, + "lastEditedBy": "{439a2669-4626-487f-9dcf-2d15e77c69a2}", + "lifetime": -1, + "limitedRun": 4294967295, + "localPosition": { + "x": 2.6226043701171875e-06, + "y": -0.13999652862548828, + "z": -0.04999971389770508 + }, + "localRotation": { + "w": 0.9969173073768616, + "x": -0.07845909893512726, + "y": 0, + "z": 0 + }, + "locked": false, + "marketplaceID": "40d879ec-93f0-4b4a-8c58-dd6349bdb058", + "modelURL": "http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx", + "name": "", + "naturalDimensions": { + "x": 0.1660931408405304, + "y": 0.05885136127471924, + "z": 0.15574991703033447 + }, + "naturalPosition": { + "x": 0, + "y": 1.6633577346801758, + "z": 0.048884183168411255 + }, + "originalTextures": "{\n \"aviator:Eyewear2F\": \"http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx/Aviator.fbm/aviator_Eyewear_Diffuse.png\",\n \"aviator:Eyewear2F1\": \"http://mpassets.highfidelity.com/40d879ec-93f0-4b4a-8c58-dd6349bdb058-v1/Aviator.fbx/Aviator.fbm/aviator_Eyewear_Specular.png\"\n}\n", + "owningAvatarID": "{439a2669-4626-487f-9dcf-2d15e77c69a2}", + "parentID": "{439a2669-4626-487f-9dcf-2d15e77c69a2}", + "parentJointIndex": 66, + "position": { + "x": 2.6226043701171875e-06, + "y": -0.13999652862548828, + "z": -0.04999971389770508 + }, + "queryAACube": { + "scale": 0.9313028454780579, + "x": -1.4091639518737793, + "y": -10.133878707885742, + "z": 1.9983724355697632 + }, + "registrationPoint": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "relayParentJoints": false, + "renderInfo": { + "drawCalls": 1, + "hasTransparent": false, + "texturesCount": 2, + "texturesSize": 1310720, + "verticesCount": 982 + }, + "restitution": 0.5, + "rotation": { + "w": 0.9969173073768616, + "x": -0.07845909893512726, + "y": 0, + "z": 0 + }, + "script": "", + "scriptTimestamp": 0, + "serverScripts": "", + "shapeType": "box", + "staticCertificateVersion": 0, + "textures": "", + "type": "Model", + "userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}", + "velocity": { + "x": 0, + "y": 0, + "z": 0 + }, + "visible": true + } + } + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/46e0fd52-3cff-462f-ba97-927338d88295-v1/AnimeBoy2.fst", + "version": 3 + }, + "Anime girl": { + "attachments": [ + ], + "avatarEntites": [ + { + "properties": { + "acceleration": { + "x": 0, + "y": 0, + "z": 0 + }, + "actionData": "", + "age": 19.66267967224121, + "ageAsText": "0 hours 0 minutes 19 seconds", + "angularDamping": 0.39346998929977417, + "angularVelocity": { + "x": 0, + "y": 0, + "z": 0 + }, + "animation": { + "allowTranslation": true, + "currentFrame": 0, + "firstFrame": 0, + "fps": 30, + "hold": false, + "lastFrame": 100000, + "loop": true, + "running": false, + "url": "" + }, + "boundingBox": { + "brn": { + "x": -0.10536206513643265, + "y": -0.16647332906723022, + "z": -0.12632352113723755 + }, + "center": { + "x": 0, + "y": -0.12999999523162842, + "z": -0.030000001192092896 + }, + "dimensions": { + "x": 0.2107241302728653, + "y": 0.07294666767120361, + "z": 0.1926470398902893 + }, + "tfl": { + "x": 0.10536206513643265, + "y": -0.09352666139602661, + "z": 0.06632351875305176 + } + }, + "canCastShadow": true, + "certificateID": "", + "clientOnly": true, + "cloneAvatarEntity": false, + "cloneDynamic": false, + "cloneLifetime": 300, + "cloneLimit": 0, + "cloneOriginID": "{00000000-0000-0000-0000-000000000000}", + "cloneable": false, + "collidesWith": "", + "collisionMask": 0, + "collisionSoundURL": "", + "collisionless": false, + "collisionsWillMove": false, + "compoundShapeURL": "", + "created": "2018-06-05T00:10:37Z", + "damping": 0.39346998929977417, + "density": 1000, + "description": "", + "dimensions": { + "x": 0.2107241302728653, + "y": 0.07294666767120361, + "z": 0.1926470398902893 + }, + "dynamic": false, + "editionNumber": 5, + "entityInstanceNumber": 0, + "friction": 0.5, + "gravity": { + "x": 0, + "y": 0, + "z": 0 + }, + "href": "", + "id": "{1586b83a-2af7-4532-9bfb-82fe3f5d5ce9}", + "ignoreForCollisions": false, + "itemArtist": "moam_00", + "itemCategories": "Wearables", + "itemDescription": "Perfect for side-glancin'.", + "itemLicense": "", + "itemName": "Blacker Fem Glasses", + "jointRotations": [ + ], + "jointRotationsSet": [ + ], + "jointTranslations": [ + ], + "jointTranslationsSet": [ + ], + "lastEdited": 1528157470041658, + "lastEditedBy": "{425df1a8-289b-42fc-819c-c3b2a12d7165}", + "lifetime": -1, + "limitedRun": 4294967295, + "localPosition": { + "x": 0, + "y": -0.12999999523162842, + "z": -0.029999999329447746 + }, + "localRotation": { + "w": 1, + "x": -2.2351741790771484e-08, + "y": 3.4924596548080444e-10, + "z": 3.725290298461914e-09 + }, + "locked": false, + "marketplaceID": "06781d12-9139-48f4-ac2a-417dde090981", + "modelURL": "http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx", + "name": "Female Glasses 3 by Mario Andrade", + "naturalDimensions": { + "x": 0.16209548711776733, + "y": 0.05611282214522362, + "z": 0.14819003641605377 + }, + "naturalPosition": { + "x": 0, + "y": -7.636845111846924e-08, + "z": 0 + }, + "originalTextures": "{\n \"file49\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Mixed_AO.jpg\",\n \"file81\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Metallic.jpg\",\n \"file84\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Roughness.jpg\",\n \"file86\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Base_Color.jpg\",\n \"file87\": \"http://mpassets.highfidelity.com/06781d12-9139-48f4-ac2a-417dde090981-v1/FemGlasses03.fbx/FemGlasses03.fbm/FemGlasses03Mat_Normal_DirectX.jpg\"\n}\n", + "owningAvatarID": "{1277f725-fbb4-478b-ae79-1241fd90e508}", + "parentID": "{1277f725-fbb4-478b-ae79-1241fd90e508}", + "parentJointIndex": 66, + "position": { + "x": 0, + "y": -0.12999999523162842, + "z": -0.029999999329447746 + }, + "queryAACube": { + "scale": 0.8840523958206177, + "x": -2.6587564945220947, + "y": -10.162277221679688, + "z": -0.9548344016075134 + }, + "registrationPoint": { + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "relayParentJoints": false, + "renderInfo": { + "drawCalls": 1, + "hasTransparent": false, + "texturesCount": 5, + "texturesSize": 0, + "verticesCount": 1156 + }, + "restitution": 0.5, + "rotation": { + "w": 1, + "x": -2.2351741790771484e-08, + "y": 3.4924596548080444e-10, + "z": 3.725290298461914e-09 + }, + "script": "", + "scriptTimestamp": 0, + "serverScripts": "", + "shapeType": "box", + "staticCertificateVersion": 0, + "textures": "", + "type": "Model", + "userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}", + "velocity": { + "x": 0, + "y": 0, + "z": 0 + }, + "visible": true + } + } + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/0dce3426-55c8-4641-8dd5-d76eb575b64a-v1/Anime_F_Outfit.fst", + "version": 3 + }, + "Last Legends: Male": { + "attachments": [ + ], + "avatarEntites": [ + { + "properties": { + "acceleration": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "actionData": "", + "age": 321.8835144042969, + "ageAsText": "0 hours 5 minutes 21 seconds", + "angularDamping": 0.39346998929977417, + "angularVelocity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "animation": { + "allowTranslation": true, + "currentFrame": 0, + "firstFrame": 0, + "fps": 30, + "hold": false, + "lastFrame": 100000, + "loop": true, + "running": false, + "url": "" + }, + "boundingBox": { + "brn": { + "blue": -0.03950843587517738, + "green": 0.20785385370254517, + "red": -0.04381325840950012, + "x": -0.04381325840950012, + "y": 0.20785385370254517, + "z": -0.03950843587517738 + }, + "center": { + "blue": 0, + "green": 0.23000000417232513, + "red": 0, + "x": 0, + "y": 0.23000000417232513, + "z": 0 + }, + "dimensions": { + "blue": 0.07901687175035477, + "green": 0.044292300939559937, + "red": 0.08762651681900024, + "x": 0.08762651681900024, + "y": 0.044292300939559937, + "z": 0.07901687175035477 + }, + "tfl": { + "blue": 0.03950843587517738, + "green": 0.2521461546421051, + "red": 0.04381325840950012, + "x": 0.04381325840950012, + "y": 0.2521461546421051, + "z": 0.03950843587517738 + } + }, + "canCastShadow": true, + "certificateID": "", + "clientOnly": true, + "cloneAvatarEntity": false, + "cloneDynamic": false, + "cloneLifetime": 300, + "cloneLimit": 0, + "cloneOriginID": "{00000000-0000-0000-0000-000000000000}", + "cloneable": false, + "collidesWith": "", + "collisionMask": 0, + "collisionSoundURL": "", + "collisionless": false, + "collisionsWillMove": false, + "compoundShapeURL": "", + "created": "2018-07-26T23:56:46Z", + "damping": 0.39346998929977417, + "density": 1000, + "description": "", + "dimensions": { + "blue": 0.07229919731616974, + "green": 0.06644226610660553, + "red": 0.03022606298327446, + "x": 0.03022606298327446, + "y": 0.06644226610660553, + "z": 0.07229919731616974 + }, + "dynamic": false, + "editionNumber": 58, + "entityInstanceNumber": 0, + "friction": 0.5, + "gravity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "href": "", + "id": "{03053239-bb37-4c51-a013-a1772baaeed5}", + "ignoreForCollisions": false, + "itemArtist": "jyoum", + "itemCategories": "Wearables", + "itemDescription": "A cool scifi watch for your avatar!", + "itemLicense": "", + "itemName": "Scifi Watch", + "jointRotations": [ + ], + "jointRotationsSet": [ + ], + "jointTranslations": [ + ], + "jointTranslationsSet": [ + ], + "lastEdited": 1532649569894305, + "lastEditedBy": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "lifetime": -1, + "limitedRun": 4294967295, + "localPosition": { + "blue": 0, + "green": 0.23000000417232513, + "red": 0, + "x": 0, + "y": 0.23000000417232513, + "z": 0 + }, + "localRotation": { + "w": 0.5910986065864563, + "x": -0.48726415634155273, + "y": -0.4088630974292755, + "z": 0.49599072337150574 + }, + "locked": false, + "marketplaceID": "0685794d-fddb-4bad-a608-6d7789ceda90", + "modelURL": "http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx", + "name": "Scifi Watch by Jimi", + "naturalDimensions": { + "blue": 0.055614765733480453, + "green": 0.0511094331741333, + "red": 0.023250818252563477, + "x": 0.023250818252563477, + "y": 0.0511094331741333, + "z": 0.055614765733480453 + }, + "naturalPosition": { + "blue": -0.06031447649002075, + "green": 1.4500460624694824, + "red": 0.6493338942527771, + "x": 0.6493338942527771, + "y": 1.4500460624694824, + "z": -0.06031447649002075 + }, + "originalTextures": "{\n \"file4\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Base_Color.png\",\n \"file5\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Normal_OpenGL.png\",\n \"file6\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Metallic.png\",\n \"file7\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Roughness.png\",\n \"file8\": \"http://mpassets.highfidelity.com/0685794d-fddb-4bad-a608-6d7789ceda90-v1/ScifiWatch.fbx/ScifiWatch/texture/lambert1_Emissive.png\"\n}\n", + "owningAvatarID": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "parentID": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "parentJointIndex": 16, + "position": { + "blue": 0, + "green": 0.23000000417232513, + "red": 0, + "x": 0, + "y": 0.23000000417232513, + "z": 0 + }, + "queryAACube": { + "scale": 0.3082179129123688, + "x": 495.7716979980469, + "y": 498.345703125, + "z": 498.52044677734375 + }, + "registrationPoint": { + "blue": 0.5, + "green": 0.5, + "red": 0.5, + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "relayParentJoints": false, + "renderInfo": { + "drawCalls": 1, + "hasTransparent": false, + "texturesCount": 5, + "texturesSize": 786432, + "verticesCount": 273 + }, + "restitution": 0.5, + "rotation": { + "w": 0.5910986065864563, + "x": -0.48726415634155273, + "y": -0.4088630974292755, + "z": 0.49599072337150574 + }, + "script": "", + "scriptTimestamp": 0, + "serverScripts": "", + "shapeType": "box", + "staticCertificateVersion": 0, + "textures": "", + "type": "Model", + "userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"[LR]ForeArm\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}", + "velocity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "visible": true + } + }, + { + "properties": { + "acceleration": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "actionData": "", + "age": 308.8044128417969, + "ageAsText": "0 hours 5 minutes 8 seconds", + "angularDamping": 0.39346998929977417, + "angularVelocity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "animation": { + "allowTranslation": true, + "currentFrame": 0, + "firstFrame": 0, + "fps": 30, + "hold": false, + "lastFrame": 100000, + "loop": true, + "running": false, + "url": "" + }, + "boundingBox": { + "brn": { + "blue": -0.2340194433927536, + "green": -0.07067721337080002, + "red": -0.17002610862255096, + "x": -0.17002610862255096, + "y": -0.07067721337080002, + "z": -0.2340194433927536 + }, + "center": { + "blue": -0.039825439453125, + "green": 0.02001953125, + "red": 0.0001678466796875, + "x": 0.0001678466796875, + "y": 0.02001953125, + "z": -0.039825439453125 + }, + "dimensions": { + "blue": 0.3883880078792572, + "green": 0.18139348924160004, + "red": 0.34038791060447693, + "x": 0.34038791060447693, + "y": 0.18139348924160004, + "z": 0.3883880078792572 + }, + "tfl": { + "blue": 0.1543685644865036, + "green": 0.11071627587080002, + "red": 0.17036180198192596, + "x": 0.17036180198192596, + "y": 0.11071627587080002, + "z": 0.1543685644865036 + } + }, + "canCastShadow": true, + "certificateID": "", + "clientOnly": true, + "cloneAvatarEntity": false, + "cloneDynamic": false, + "cloneLifetime": 300, + "cloneLimit": 0, + "cloneOriginID": "{00000000-0000-0000-0000-000000000000}", + "cloneable": false, + "collidesWith": "", + "collisionMask": 0, + "collisionSoundURL": "", + "collisionless": false, + "collisionsWillMove": false, + "compoundShapeURL": "", + "created": "2018-07-26T23:56:46Z", + "damping": 0.39346998929977417, + "density": 1000, + "description": "", + "dimensions": { + "blue": 0.38838762044906616, + "green": 0.16981728374958038, + "red": 0.33466479182243347, + "x": 0.33466479182243347, + "y": 0.16981728374958038, + "z": 0.38838762044906616 + }, + "dynamic": false, + "editionNumber": 18, + "entityInstanceNumber": 0, + "friction": 0.5, + "gravity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "href": "", + "id": "{1bf231ce-3913-4c53-be3c-b1f4094dac51}", + "ignoreForCollisions": false, + "itemArtist": "jyoum", + "itemCategories": "Wearables", + "itemDescription": "A stylish and classic piece of headwear for your avatar.", + "itemLicense": "", + "itemName": "Fedora", + "jointRotations": [ + ], + "jointRotationsSet": [ + ], + "jointTranslations": [ + ], + "jointTranslationsSet": [ + ], + "lastEdited": 1532649698129709, + "lastEditedBy": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "lifetime": -1, + "limitedRun": 4294967295, + "localPosition": { + "blue": -0.039825439453125, + "green": 0.02001953125, + "red": 0.0001678466796875, + "x": 0.0001678466796875, + "y": 0.02001953125, + "z": -0.039825439453125 + }, + "localRotation": { + "w": 0.9998477101325989, + "x": -9.898545982878204e-09, + "y": 5.670873406415922e-07, + "z": 0.017452405765652657 + }, + "locked": false, + "marketplaceID": "11c4208d-15d7-4449-9758-a08da6dbd3dc", + "modelURL": "http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx", + "name": "", + "naturalDimensions": { + "blue": 0.320981502532959, + "green": 0.14034485816955566, + "red": 0.2765824794769287, + "x": 0.2765824794769287, + "y": 0.14034485816955566, + "z": 0.320981502532959 + }, + "naturalPosition": { + "blue": 0.022502630949020386, + "green": 1.7460365295410156, + "red": 0.000143393874168396, + "x": 0.000143393874168396, + "y": 1.7460365295410156, + "z": 0.022502630949020386 + }, + "originalTextures": "{\n \"file5\": \"http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx/Texture/Fedora_Hat1_Base_Color.png\",\n \"file7\": \"http://mpassets.highfidelity.com/11c4208d-15d7-4449-9758-a08da6dbd3dc-v1/Fedora.fbx/Texture/Fedora_Hat1_Roughness.png\"\n}\n", + "owningAvatarID": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "parentID": "{042ac463-7879-40f0-8126-e2e56c4345ca}", + "parentJointIndex": 66, + "position": { + "blue": -0.039825439453125, + "green": 0.02001953125, + "red": 0.0001678466796875, + "x": 0.0001678466796875, + "y": 0.02001953125, + "z": -0.039825439453125 + }, + "queryAACube": { + "scale": 1.6202316284179688, + "x": 495.21051025390625, + "y": 498.5577697753906, + "z": 497.6370849609375 + }, + "registrationPoint": { + "blue": 0.5, + "green": 0.5, + "red": 0.5, + "x": 0.5, + "y": 0.5, + "z": 0.5 + }, + "relayParentJoints": false, + "renderInfo": { + "drawCalls": 1, + "hasTransparent": false, + "texturesCount": 2, + "texturesSize": 327680, + "verticesCount": 719 + }, + "restitution": 0.5, + "rotation": { + "w": 0.9998477101325989, + "x": -9.898545982878204e-09, + "y": 5.670873406415922e-07, + "z": 0.017452405765652657 + }, + "script": "", + "scriptTimestamp": 0, + "serverScripts": "", + "shapeType": "box", + "staticCertificateVersion": 0, + "textures": "", + "type": "Model", + "userData": "{\"Attachment\":{\"action\":\"attach\",\"joint\":\"HeadTop_End\",\"attached\":false,\"options\":{\"translation\":{\"x\":0,\"y\":0,\"z\":0},\"scale\":1}},\"grabbableKey\":{\"cloneable\":false,\"grabbable\":true}}", + "velocity": { + "blue": 0, + "green": 0, + "red": 0, + "x": 0, + "y": 0, + "z": 0 + }, + "visible": true + } + } + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/28569047-6f1a-4100-af67-8054ec397cc3-v1/LLMale2.fst", + "version": 3 + }, + "Last legends Female": { + "attachments": [ + ], + "avatarEntites": [ + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/8d823be5-6197-4418-b984-eb94160ed956-v1/LLFemale_Clothes.fst", + "version": 3 + }, + "Matthew": { + "attachments": [ + ], + "avatarEntites": [ + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/b652081b-a199-425e-ae5c-7815721bdc09-v1/matthew.fst", + "version": 3 + }, + "Priscilla": { + "attachments": [ + ], + "avatarEntites": [ + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/e7565f93-8bc5-47c2-b6eb-b3b31d4a1339-v1/priscilla.fst", + "version": 3 + }, + "Woody": { + "attachments": [ + ], + "avatarEntites": [ + ], + "avatarScale": 1, + "avatarUrl": "http://mpassets.highfidelity.com/ad348528-de38-420c-82bb-054cb22163f5-v1/mannequin.fst", + "version": 3 + } +} diff --git a/tools/auto-tester/AppDataHighFidelity/assignment-client/entities/models.json.gz b/tools/auto-tester/AppDataHighFidelity/assignment-client/entities/models.json.gz new file mode 100644 index 0000000000..1eeeac50ac Binary files /dev/null and b/tools/auto-tester/AppDataHighFidelity/assignment-client/entities/models.json.gz differ diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/AccountInfo.bin b/tools/auto-tester/AppDataHighFidelity/domain-server/AccountInfo.bin new file mode 100644 index 0000000000..645e34895e Binary files /dev/null and b/tools/auto-tester/AppDataHighFidelity/domain-server/AccountInfo.bin differ diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/config.json b/tools/auto-tester/AppDataHighFidelity/domain-server/config.json new file mode 100644 index 0000000000..d662d89f28 --- /dev/null +++ b/tools/auto-tester/AppDataHighFidelity/domain-server/config.json @@ -0,0 +1,7 @@ +{ + "metaverse": { + "automatic_networking": "full", + "id": "17b1cb9c-08c4-45aa-9257-163ad3913529" + }, + "version": 2.2 +} diff --git a/tools/auto-tester/AppDataHighFidelity/domain-server/entities/models.json.gz b/tools/auto-tester/AppDataHighFidelity/domain-server/entities/models.json.gz new file mode 100644 index 0000000000..1eeeac50ac Binary files /dev/null and b/tools/auto-tester/AppDataHighFidelity/domain-server/entities/models.json.gz differ diff --git a/tools/auto-tester/CMakeLists.txt b/tools/auto-tester/CMakeLists.txt index 1546a35f4c..06930ab0fe 100644 --- a/tools/auto-tester/CMakeLists.txt +++ b/tools/auto-tester/CMakeLists.txt @@ -48,4 +48,19 @@ if (WIN32) POST_BUILD COMMAND CMD /C "SET PATH=%PATH%;${QT_DIR}/bin && ${WINDEPLOYQT_COMMAND} ${EXTRA_DEPLOY_OPTIONS} $<$,$,$>:--release> \"$\"" ) + + # add a custom command to copy the empty Apps/Data High Fidelity folder (i.e. - a valid folder with no entities) + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory "${CMAKE_CURRENT_SOURCE_DIR}/AppDataHighFidelity" "$/AppDataHighFidelity" + ) + + # add a custom command to copy the SSL DLLs + add_custom_command( + TARGET ${TARGET_NAME} + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy_directory D:/GitHub/vcpkg/installed/x64-windows/bin "$" + ) + endif () \ No newline at end of file diff --git a/tools/auto-tester/Create.PNG b/tools/auto-tester/Create.PNG index d82d4873a2..85d70e59ed 100644 Binary files a/tools/auto-tester/Create.PNG and b/tools/auto-tester/Create.PNG differ diff --git a/tools/auto-tester/Evaluate.PNG b/tools/auto-tester/Evaluate.PNG index d530dec994..2f711f61a3 100644 Binary files a/tools/auto-tester/Evaluate.PNG and b/tools/auto-tester/Evaluate.PNG differ diff --git a/tools/auto-tester/README.md b/tools/auto-tester/README.md index 0924e77f8b..e029955edc 100644 --- a/tools/auto-tester/README.md +++ b/tools/auto-tester/README.md @@ -5,14 +5,16 @@ The auto-tester is a stand alone application that provides a mechanism for regre * The snapshots are compared to a 'canonical' set of images that have been produced beforehand. * The result, if any test failed, is a zipped folder describing the failure. -Auto-tester has 4 functions, separated into 4 tabs: +Auto-tester has 5 functions, separated into 4 tabs: 1. Creating tests, MD files and recursive scripts -2. Evaluating the results of running tests -3. TestRail interface -4. Windows task bar utility (Windows only) +1. Windows task bar utility (Windows only) +1. Running tests +1. Evaluating the results of running tests +1. Web interface + ## Installation ### Executable -1. Download the installer by browsing to [here](). +1. Download the installer by browsing to [here](). 2. Double click on the installer and install to a convenient location ![](./setup_7z.PNG) 3. To run the auto-tester, double click **auto-tester.exe**. @@ -25,6 +27,17 @@ Python 3 can be downloaded from: 3. Mac (**macOS 64-bit/32-bit installer** or **macOS 64-bit/32-bit installer**) After installation - create an environment variable called PYTHON_PATH and set it to the folder containing the Python executable. +### AWS interface +#### Windows +1. Download the AWS CLI from `https://aws.amazon.com/cli/` +1. Install (installer is named `AWSCLI64PY3.msi`) +1. Open a new command prompt and run `aws configure` +1. Enter the AWS account number +1. Enter the secret key +1. Leave region name and ouput format as default [None] + +1. Install the latest release of Boto3 via pip: +>pip install boto3 # Create ![](./Create.PNG) @@ -36,6 +49,9 @@ This function is used to create/update Expected Images after a successful run of The user will be asked for the snapshot folder and then the tests root folder. All snapshots located in the snapshot folder will be used to create or update the expected images in the relevant tests. ### Details As an example - if the snapshots folder contains an image named `tests.content.entity.zone.zoneOrientation.00003.png`, then this file will be copied to `tests/contente/enity/zone/zoneOrientation/ExpectedImage0003.png`. +## Create Tests Outline +### Usage +This function creates an MD file in the (user-selected) tests root folder. The file provides links to both the tests and the MD files. ## Create MD file ### Usage This function creates a file named `test.md` from a `test.js` script. The user will be asked for the folder containing the test script: @@ -54,13 +70,20 @@ The process to produce the MD file is a simplistic parse of the test script. ### Usage This function creates all MD files recursively from the user-selected root folder. This can be any folder in the tests hierarchy (e.g. all engine\material tests). -The file provides a hierarchial list of all the tests -## Create Tests Outline +The file provides a hierarchal list of all the tests +## Create testAuto script ### Usage -This function creates an MD file in the (user-selected) tests root folder. The file provides links to both the tests and the MD files. +This function creates a script named `testAuto.js` in a user-selected test folder. +### Details +The script created runs the `test.js` script in the folder in automatic mode. The script is the same for all tests. +## Create all testAuto scripts +### Usage +This function creates all testAuto scripts recursively from the user-selected root folder. This can be any folder in the tests hierarchy (e.g. all engine\material tests). + +The file provides a hierarchical list of all the tests ## Create Recursive Script ### Usage -After the user selects a folder within the tests hierarchy, a script is created, named `testRecursive.js`. This script calls all `test.js` scripts in the subfolders. +After the user selects a folder within the tests hierarchy, a script is created, named `testRecursive.js`. This script calls all `test.js` scripts in the sub-folders. ### Details The various scripts are called in alphabetical order. @@ -92,6 +115,34 @@ autoTester.runRecursive(); In this case all recursive scripts, from the selected folder down, are created. Running this function in the tests root folder will create (or update) all the recursive scripts. +# Windows +![](./Windows.PNG) + +This tab is Windows-specific. It provides buttons to hide and show the task bar. + +The task bar should be hidden for all tests that use the primary camera. This is required to ensure that the snapshots are the right size. +# Run +![](./Run.PNG) +The run tab is used to run tests in automatic mode. The tests require the location of a folder to store files in; this folder can safely be re-used for any number of runs (the "Working Folder"). +The test script that is run is `https://github.com/highfidelity/hifi_tests/blob/master/tests/testRecursive.js`. The user can use a different branch' or even repository, if required. +Tests can be run server-less, or with the local host. In the second case, the domain-server and assignment-clients are run before starting Interface. +The default is to run the latest build. The user can select a specific build or PR if desired. +Testing can be started immediately, or run on a schedule. + +A test run is performed in a number of steps: +1. If the latest run has been selected then the `dev-builds.xml` file is downloaded to identify the latest build. +1. The installer is then downloaded. +1. After downloading the High Fidelity application is installed. This requires that UAC be disabled! +1. Any instances of the server-console, assignment-client, domain-server or Interface are killed before running the tests. +1. Interface is run with the appropriate command line parameters. +1. The expected images are then downloaded from GitHub and compared to the actual images from the tests. + +The working folder will ultimately contain the following: +1. A folder named `High Fidelity`. This is where High Fidelity is installed. +1. A folder named `snapshots`. This folder contains the zipped results folders (one for each run). It also contains both the actual images and the expected images from the last run; note that these are deleted before running tests (All PNG files in the folder are deleted. In addition - a text file named `tests_completed.txt` is created at the end of the test script - this signals that Interface did not crash during the test run. +1. The `dev-builds.xml` file, if it was downloaded. +1. The HighFidelity installer. Note that this is always named `HighFidelity-Beta-latest-dev` so as not to store too many installers over time. +1. A log file describing the runs. This file is appended to after each run. # Evaluate ![](./Evaluate.PNG) @@ -103,13 +154,13 @@ If any tests have failed, then a zipped folder will be created in the snapshots ### Usage Before starting the evaluation, make sure the GitHub user and branch are set correctly. The user should not normally be changed, but the branch may need to be set to the appropriate RC. -After setting the checkbox as required and pressing Evaluate - the user will be asked for the snapshots folder. +After setting the check-box as required and pressing Evaluate - the user will be asked for the snapshots folder. ### Details Evaluation proceeds in a number of steps: 1. A folder is created to store any failures -1. The expecetd images are download from GitHub. They are named slightly differently from the snapshots (e.g. `tests.engine.render.effect.highlight.coverage.00000.png` and `tests.engine.render.effect.highlight.coverage.00000_EI.png`). +1. The expected images are download from GitHub. They are named slightly differently from the snapshots (e.g. `tests.engine.render.effect.highlight.coverage.00000.png` and `tests.engine.render.effect.highlight.coverage.00000_EI.png`). 1. The images are then pair-wise compared, using the SSIM algorithm. A fixed threshold is used to define a mismatch. @@ -119,8 +170,10 @@ Evaluation proceeds in a number of steps: 1. If not in interactive mode, or the user has defined the results as an error, an error is written into the error folder. The error itself is a folder with the 3 images and a small text file containing details. 1. At the end of the test, the folder is zipped and the original folder is deleted. If there are no errors then the zipped folder will be empty. -# TestRail -![](./TestRail.PNG) + +# Web Interface +![](./WebInterface.PNG) +This tab has two functions: updating the TestRail cases, runs and results, and creating web page reports that are stored on AWS. Before updating TestRail, make sure the GitHub user and branch are set correctly. The user should not normally be changed, but the branch may need to be set to the appropriate RC. @@ -129,9 +182,9 @@ Any access to TestRail will require the TestRail account (default is High Fideli ![](./TestRailSelector.PNG) - The default test rail user is shown, and can be changed as needed. -- The username is usually the user's email. +- The user-name is usually the user's email. - The Project ID defaults to 14 - Interface. -- The Suite ID defaults to 1147 - Renderong. +- The Suite ID defaults to 1147 - Rendering. - The TestRail page provides 3 functions for writing to TestRail. ## Create Test Cases ### Usage @@ -188,10 +241,7 @@ A number of Python scripts are created: - `getRuns.py` reads the release names from TestRail - `addRun` is the script that writes to TestRail. -In addition - a file containing all the releases will be created - `runs.txt` -# Windows -![](./Windows.PNG) - -This tab is Windows-specific. It provides buttons to hide and show the task bar. - -The task bar should be hidden for all tests that use the primary camera. This is required to ensure that the snapshots are the right size. \ No newline at end of file +In addition - a file containing all the releases will be created - `runs.txt`. +## Create Web Page +This function requests a zipped results folder and converts it to a web page. The page is created in a user-selecetd working folder. +If the `Update AWS` checkbox is checked then the page will also be copied to AWS, and the appropriate URL will be displayed in the window below the button. diff --git a/tools/auto-tester/Run.PNG b/tools/auto-tester/Run.PNG new file mode 100644 index 0000000000..29f81299c8 Binary files /dev/null and b/tools/auto-tester/Run.PNG differ diff --git a/tools/auto-tester/TestRail.PNG b/tools/auto-tester/TestRail.PNG deleted file mode 100644 index 042d0cf1cb..0000000000 Binary files a/tools/auto-tester/TestRail.PNG and /dev/null differ diff --git a/tools/auto-tester/Web Interface.PNG b/tools/auto-tester/Web Interface.PNG new file mode 100644 index 0000000000..d7216e3c18 Binary files /dev/null and b/tools/auto-tester/Web Interface.PNG differ diff --git a/tools/auto-tester/WebInterface.PNG b/tools/auto-tester/WebInterface.PNG new file mode 100644 index 0000000000..d9d3df3fc6 Binary files /dev/null and b/tools/auto-tester/WebInterface.PNG differ diff --git a/tools/auto-tester/Windows.PNG b/tools/auto-tester/Windows.PNG index bf7b76ba02..32e3bfd53e 100644 Binary files a/tools/auto-tester/Windows.PNG and b/tools/auto-tester/Windows.PNG differ diff --git a/tools/auto-tester/src/AWSInterface.cpp b/tools/auto-tester/src/AWSInterface.cpp new file mode 100644 index 0000000000..628db5329c --- /dev/null +++ b/tools/auto-tester/src/AWSInterface.cpp @@ -0,0 +1,413 @@ +// +// AWSInterface.cpp +// +// Created by Nissim Hadar on 3 Oct 2018. +// 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 "AWSInterface.h" + +#include +#include +#include + +#include +#include + +AWSInterface::AWSInterface(QObject* parent) : QObject(parent) { + _pythonInterface = new PythonInterface(); + _pythonCommand = _pythonInterface->getPythonCommand(); +} + +void AWSInterface::createWebPageFromResults(const QString& testResults, + const QString& workingDirectory, + QCheckBox* updateAWSCheckBox, + QLineEdit* urlLineEdit) { + _testResults = testResults; + _workingDirectory = workingDirectory; + + _urlLineEdit = urlLineEdit; + _urlLineEdit->setEnabled(false); + + extractTestFailuresFromZippedFolder(); + createHTMLFile(); + + if (updateAWSCheckBox->isChecked()) { + updateAWS(); + } +} + +void AWSInterface::extractTestFailuresFromZippedFolder() { + // For a test results zip file called `D:/tt/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ].zip` + // the folder will be called `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]` + // and, this folder will be in the workign directory + QStringList parts =_testResults.split('/'); + QString zipFolderName = _workingDirectory + "/" + parts[parts.length() - 1].split('.')[0]; + if (QDir(zipFolderName).exists()) { + QDir dir = zipFolderName; + dir.removeRecursively(); + } + + QDir().mkdir(_workingDirectory); + JlCompress::extractDir(_testResults, _workingDirectory); +} + +void AWSInterface::createHTMLFile() { + // For file named `D:/tt/snapshots/TestResults--2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ].zip` + // - the HTML will be in a folder named `TestResults--2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ]` + QStringList pathComponents = _testResults.split('/'); + QString filename = pathComponents[pathComponents.length() - 1]; + _resultsFolder = filename.left(filename.length() - 4); + + QString resultsPath = _workingDirectory + "/" + _resultsFolder + "/"; + QDir().mkdir(resultsPath); + _htmlFilename = resultsPath + HTML_FILENAME; + + QFile file(_htmlFilename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not create '" + _htmlFilename + "'"); + exit(-1); + } + + QTextStream stream(&file); + + startHTMLpage(stream); + writeHead(stream); + writeBody(stream); + finishHTMLpage(stream); + + file.close(); +} + +void AWSInterface::startHTMLpage(QTextStream& stream) { + stream << "\n"; + stream << "\n"; +} + +void AWSInterface::writeHead(QTextStream& stream) { + stream << "\t" << "\n"; + stream << "\t" << "\t" << "\n"; + stream << "\t" << "\n"; +} + +void AWSInterface::writeBody(QTextStream& stream) { + stream << "\t" << "\n"; + writeTitle(stream); + writeTable(stream); + stream << "\t" << "\n"; +} + +void AWSInterface::finishHTMLpage(QTextStream& stream) { + stream << "\n"; +} + +void AWSInterface::writeTitle(QTextStream& stream) { + // Separate relevant components from the results name + // The expected format is as follows: `D:/tt/snapshots/TestResults--2018-10-04_11-09-41(PR14128)[DESKTOP-PMKNLSQ].zip` + QStringList tokens = _testResults.split('/'); + + // date_buildorPR_hostName will be 2018-10-03_15-35-28(9433)[DESKTOP-PMKNLSQ] + QString date_buildorPR_hostName = tokens[tokens.length() - 1].split("--")[1].split(".")[0]; + + QString buildorPR = date_buildorPR_hostName.split('(')[1].split(')')[0]; + QString hostName = date_buildorPR_hostName.split('[')[1].split(']')[0]; + + QStringList dateList = date_buildorPR_hostName.split('(')[0].split('_')[0].split('-'); + QString year = dateList[0]; + QString month = dateList[1]; + QString day = dateList[2]; + + QStringList timeList = date_buildorPR_hostName.split('(')[0].split('_')[1].split('-'); + QString hour = timeList[0]; + QString minute = timeList[1]; + QString second = timeList[2]; + + const QString months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + stream << "\t" << "\t" << "\n"; + stream << "\t" << "\t" << "

Failures for "; + stream << months[month.toInt() - 1] << " " << day << ", " << year << ", "; + stream << hour << ":" << minute << ":" << second << ", "; + + if (buildorPR.left(2) == "PR") { + stream << "PR " << buildorPR.right(buildorPR.length() - 2) << ", "; + } else { + stream << "build " << buildorPR << ", "; + } + + stream << "run on " << hostName << "

\n"; +} + +void AWSInterface::writeTable(QTextStream& stream) { + QString previousTestName{ "" }; + + // Loop over all entries in directory. This is done in stages, as the names are not in the order of the tests + // The first stage reads the directory names into a list + // The second stage renames the tests by removing everything up to "--tests." + // The third stage renames the directories + // The fourth and lasts stage creates the HTML entries + // + // Note that failures are processed first, then successes + QStringList originalNamesFailures; + QStringList originalNamesSuccesses; + QDirIterator it1(_workingDirectory.toStdString().c_str()); + while (it1.hasNext()) { + QString nextDirectory = it1.next(); + + // Skip `.` and `..` directories + if (nextDirectory.right(1) == ".") { + continue; + } + + // Only process failure folders + if (!nextDirectory.contains("--tests.")) { + continue; + } + + // Look at the filename at the end of the path + QStringList parts = nextDirectory.split('/'); + QString name = parts[parts.length() - 1]; + if (name.left(7) == "Failure") { + originalNamesFailures.append(nextDirectory); + } else { + originalNamesSuccesses.append(nextDirectory); + } + } + + QStringList newNamesFailures; + for (int i = 0; i < originalNamesFailures.length(); ++i) { + newNamesFailures.append(originalNamesFailures[i].split("--tests.")[1]); + } + + QStringList newNamesSuccesses; + for (int i = 0; i < originalNamesSuccesses.length(); ++i) { + newNamesSuccesses.append(originalNamesSuccesses[i].split("--tests.")[1]); + } + + _htmlFailuresFolder = _workingDirectory + "/" + _resultsFolder + "/" + FAILURES_FOLDER; + QDir().mkdir(_htmlFailuresFolder); + + _htmlSuccessesFolder = _workingDirectory + "/" + _resultsFolder + "/" + SUCCESSES_FOLDER; + QDir().mkdir(_htmlSuccessesFolder); + + for (int i = 0; i < newNamesFailures.length(); ++i) { + QDir().rename(originalNamesFailures[i], _htmlFailuresFolder + "/" + newNamesFailures[i]); + } + + for (int i = 0; i < newNamesSuccesses.length(); ++i) { + QDir().rename(originalNamesSuccesses[i], _htmlSuccessesFolder + "/" + newNamesSuccesses[i]); + } + + QDirIterator it2((_htmlFailuresFolder).toStdString().c_str()); + while (it2.hasNext()) { + QString nextDirectory = it2.next(); + + // Skip `.` and `..` directories, as well as the HTML directory + if (nextDirectory.right(1) == "." || nextDirectory.contains(QString("/") + _resultsFolder + "/TestResults--")) { + continue; + } + + QStringList pathComponents = nextDirectory.split('/'); + QString filename = pathComponents[pathComponents.length() - 1]; + int splitIndex = filename.lastIndexOf("."); + QString testName = filename.left(splitIndex).replace(".", " / "); + QString testNumber = filename.right(filename.length() - (splitIndex + 1)); + + // The failures are ordered lexicographically, so we know that we can rely on the testName changing to create a new table + if (testName != previousTestName) { + if (!previousTestName.isEmpty()) { + closeTable(stream); + } + + previousTestName = testName; + + stream << "\t\t

" << testName << "

\n"; + + openTable(stream); + } + + createEntry(testNumber.toInt(), filename, stream, true); + } + + closeTable(stream); + stream << "\t" << "\t" << "\n"; + stream << "\t" << "\t" << "

The following tests passed:

"; + + QDirIterator it3((_htmlSuccessesFolder).toStdString().c_str()); + while (it3.hasNext()) { + QString nextDirectory = it3.next(); + + // Skip `.` and `..` directories, as well as the HTML directory + if (nextDirectory.right(1) == "." || nextDirectory.contains(QString("/") + _resultsFolder + "/TestResults--")) { + continue; + } + + QStringList pathComponents = nextDirectory.split('/'); + QString filename = pathComponents[pathComponents.length() - 1]; + int splitIndex = filename.lastIndexOf("."); + QString testName = filename.left(splitIndex).replace(".", " / "); + QString testNumber = filename.right(filename.length() - (splitIndex + 1)); + + // The failures are ordered lexicographically, so we know that we can rely on the testName changing to create a new table + if (testName != previousTestName) { + if (!previousTestName.isEmpty()) { + closeTable(stream); + } + + previousTestName = testName; + + stream << "\t\t

" << testName << "

\n"; + + openTable(stream); + } + + createEntry(testNumber.toInt(), filename, stream, false); + } + + closeTable(stream); +} + +void AWSInterface::openTable(QTextStream& stream) { + stream << "\t\t\n"; + stream << "\t\t\t\n"; + stream << "\t\t\t\t\n"; + stream << "\t\t\t\t\n"; + stream << "\t\t\t\t\n"; + stream << "\t\t\t\t\n"; + stream << "\t\t\t\n"; +} + +void AWSInterface::closeTable(QTextStream& stream) { + stream << "\t\t

Test

Actual Image

Expected Image

Difference Image

\n"; +} + +void AWSInterface::createEntry(int index, const QString& testResult, QTextStream& stream, const bool isFailure) { + stream << "\t\t\t\n"; + stream << "\t\t\t\t

" << QString::number(index) << "

\n"; + + // For a test named `D:/t/fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf/Failure_1--tests.engine.interaction.pick.collision.many.00000` + // we need `Failure_1--tests.engine.interaction.pick.collision.many.00000` + QStringList resultNameComponents = testResult.split('/'); + QString resultName = resultNameComponents[resultNameComponents.length() - 1]; + + QString folder; + bool differenceFileFound; + if (isFailure) { + folder = FAILURES_FOLDER; + differenceFileFound = QFile::exists(_htmlFailuresFolder + "/" + resultName + "/Difference Image.png"); + } else { + folder = SUCCESSES_FOLDER; + differenceFileFound = QFile::exists(_htmlSuccessesFolder + "/" + resultName + "/Difference Image.png"); + } + + + stream << "\t\t\t\t\n"; + stream << "\t\t\t\t\n"; + + if (differenceFileFound) { + stream << "\t\t\t\t\n"; + } else { + stream << "\t\t\t\t

No Image Found

\n"; + } + + stream << "\t\t\t\n"; +} + +void AWSInterface::updateAWS() { + QString filename = _workingDirectory + "/updateAWS.py"; + if (QFile::exists(filename)) { + QFile::remove(filename); + } + QFile file(filename); + + if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not create 'addTestCases.py'"); + exit(-1); + } + + QTextStream stream(&file); + + stream << "import boto3\n"; + stream << "s3 = boto3.resource('s3')\n\n"; + + QDirIterator it1(_htmlFailuresFolder.toStdString().c_str()); + while (it1.hasNext()) { + QString nextDirectory = it1.next(); + + // Skip `.` and `..` directories + if (nextDirectory.right(1) == ".") { + continue; + } + + // nextDirectory looks like `D:/t/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/failures/engine.render.effect.bloom.00000` + // We need to concatenate the last 3 components, to get `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/failures/engine.render.effect.bloom.00000` + QStringList parts = nextDirectory.split('/'); + QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; + + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; + + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; + + if (QFile::exists(_htmlFailuresFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Difference Image.png" << "', Body=data)\n\n"; + } + } + + QDirIterator it2(_htmlSuccessesFolder.toStdString().c_str()); + while (it2.hasNext()) { + QString nextDirectory = it2.next(); + + // Skip `.` and `..` directories + if (nextDirectory.right(1) == ".") { + continue; + } + + // nextDirectory looks like `D:/t/TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/successes/engine.render.effect.bloom.00000` + // We need to concatenate the last 3 components, to get `TestResults--2018-10-02_16-54-11(9426)[DESKTOP-PMKNLSQ]/successes/engine.render.effect.bloom.00000` + QStringList parts = nextDirectory.split('/'); + QString filename = parts[parts.length() - 3] + "/" + parts[parts.length() - 2] + "/" + parts[parts.length() - 1]; + + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Actual Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Actual Image.png" << "', Body=data)\n\n"; + + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Expected Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Expected Image.png" << "', Body=data)\n\n"; + + if (QFile::exists(_htmlSuccessesFolder + "/" + parts[parts.length() - 1] + "/Difference Image.png")) { + stream << "data = open('" << _workingDirectory << "/" << filename << "/" << "Difference Image.png" << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << filename << "/" << "Difference Image.png" << "', Body=data)\n\n"; + } + } + + stream << "data = open('" << _workingDirectory << "/" << _resultsFolder << "/" << HTML_FILENAME << "', 'rb')\n"; + stream << "s3.Bucket('hifi-content').put_object(Bucket='" << AWS_BUCKET << "', Key='" << _resultsFolder << "/" + << HTML_FILENAME << "', Body=data, ContentType='text/html')\n"; + + file.close(); + + // Show user the URL + _urlLineEdit->setEnabled(true); + _urlLineEdit->setText(QString("https://") + AWS_BUCKET + ".s3.amazonaws.com/" + _resultsFolder + "/" + HTML_FILENAME); + _urlLineEdit->setCursorPosition(0); + + QProcess* process = new QProcess(); + + connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); }); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); + connect(process, static_cast(&QProcess::finished), this, + [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); + + QStringList parameters = QStringList() << filename ; + process->start(_pythonCommand, parameters); +} diff --git a/tools/auto-tester/src/AWSInterface.h b/tools/auto-tester/src/AWSInterface.h new file mode 100644 index 0000000000..c5be5f35bb --- /dev/null +++ b/tools/auto-tester/src/AWSInterface.h @@ -0,0 +1,72 @@ +// +// AWSInterface.h +// +// Created by Nissim Hadar on 3 Oct 2018. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AWSInterface_h +#define hifi_AWSInterface_h + +#include +#include +#include +#include + +#include "ui/BusyWindow.h" + +#include "PythonInterface.h" + +class AWSInterface : public QObject { + Q_OBJECT +public: + explicit AWSInterface(QObject* parent = 0); + + void createWebPageFromResults(const QString& testResults, + const QString& workingDirectory, + QCheckBox* updateAWSCheckBox, + QLineEdit* urlLineEdit); + + void extractTestFailuresFromZippedFolder(); + void createHTMLFile(); + + void startHTMLpage(QTextStream& stream); + void writeHead(QTextStream& stream); + void writeBody(QTextStream& stream); + void finishHTMLpage(QTextStream& stream); + + void writeTitle(QTextStream& stream); + void writeTable(QTextStream& stream); + void openTable(QTextStream& stream); + void closeTable(QTextStream& stream); + + void createEntry(int index, const QString& testResult, QTextStream& stream, const bool isFailure); + + void updateAWS(); + +private: + QString _testResults; + QString _workingDirectory; + QString _resultsFolder; + QString _htmlFailuresFolder; + QString _htmlSuccessesFolder; + QString _htmlFilename; + + const QString FAILURES_FOLDER{ "failures" }; + const QString SUCCESSES_FOLDER{ "successes" }; + const QString HTML_FILENAME{ "TestResults.html" }; + + BusyWindow _busyWindow; + + PythonInterface* _pythonInterface; + QString _pythonCommand; + + QString AWS_BUCKET{ "hifi-qa" }; + + QLineEdit* _urlLineEdit; +}; + +#endif // hifi_AWSInterface_h \ No newline at end of file diff --git a/tools/auto-tester/src/Downloader.cpp b/tools/auto-tester/src/Downloader.cpp index 530a3b61bd..cb9863f34d 100644 --- a/tools/auto-tester/src/Downloader.cpp +++ b/tools/auto-tester/src/Downloader.cpp @@ -11,20 +11,20 @@ #include -Downloader::Downloader(QUrl imageUrl, QObject *parent) : QObject(parent) { +Downloader::Downloader(QUrl fileURL, QObject *parent) : QObject(parent) { connect( &_networkAccessManager, SIGNAL (finished(QNetworkReply*)), this, SLOT (fileDownloaded(QNetworkReply*)) ); - QNetworkRequest request(imageUrl); + QNetworkRequest request(fileURL); _networkAccessManager.get(request); } void Downloader::fileDownloaded(QNetworkReply* reply) { QNetworkReply::NetworkError error = reply->error(); if (error != QNetworkReply::NetworkError::NoError) { - QMessageBox::information(0, "Test Aborted", "Failed to download image: " + reply->errorString()); + QMessageBox::information(0, "Test Aborted", "Failed to download file: " + reply->errorString()); return; } diff --git a/tools/auto-tester/src/Downloader.h b/tools/auto-tester/src/Downloader.h index b0ad58fac5..6d1029698f 100644 --- a/tools/auto-tester/src/Downloader.h +++ b/tools/auto-tester/src/Downloader.h @@ -30,7 +30,7 @@ class Downloader : public QObject { Q_OBJECT public: - explicit Downloader(QUrl imageUrl, QObject *parent = 0); + explicit Downloader(QUrl fileURL, QObject *parent = 0); QByteArray downloadedData() const; diff --git a/tools/auto-tester/src/PythonInterface.cpp b/tools/auto-tester/src/PythonInterface.cpp new file mode 100644 index 0000000000..4922b8a8df --- /dev/null +++ b/tools/auto-tester/src/PythonInterface.cpp @@ -0,0 +1,32 @@ +// +// PythonInterface.cpp +// +// Created by Nissim Hadar on Oct 6, 2018. +// 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 "PythonInterface.h" + +#include +#include +#include + +PythonInterface::PythonInterface() { + if (QProcessEnvironment::systemEnvironment().contains("PYTHON_PATH")) { + QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); + if (!QFile::exists(_pythonPath + "/" + _pythonExe)) { + QMessageBox::critical(0, _pythonExe, QString("Python executable not found in ") + _pythonPath); + } + _pythonCommand = _pythonPath + "/" + _pythonExe; + } else { + QMessageBox::critical(0, "PYTHON_PATH not defined", + "Please set PYTHON_PATH to directory containing the Python executable"); + exit(-1); + } +} + +QString PythonInterface::getPythonCommand() { + return _pythonCommand; +} diff --git a/tools/auto-tester/src/PythonInterface.h b/tools/auto-tester/src/PythonInterface.h new file mode 100644 index 0000000000..f32a39a644 --- /dev/null +++ b/tools/auto-tester/src/PythonInterface.h @@ -0,0 +1,26 @@ +// +// PythonInterface.h +// +// Created by Nissim Hadar on Oct 6, 2018. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_PythonInterface_h +#define hifi_PythonInterface_h + +#include + +class PythonInterface { +public: + PythonInterface(); + + QString getPythonCommand(); + +private: + const QString _pythonExe{ "python.exe" }; + QString _pythonCommand; +}; + +#endif // hifi_PythonInterface_h diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 3da789f405..582f6209af 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,10 @@ extern AutoTester* autoTester; #include -Test::Test() { +Test::Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode) { + _progressBar = progressBar; + _checkBoxInteractiveMode = checkBoxInteractiveMode; + _mismatchWindow.setModal(true); if (autoTester) { @@ -34,17 +38,17 @@ Test::Test() { bool Test::createTestResultsFolderPath(const QString& directory) { QDateTime now = QDateTime::currentDateTime(); - _testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT); + _testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER + "--" + now.toString(DATETIME_FORMAT) + "(local)[" + QHostInfo::localHostName() + "]"; QDir testResultsFolder(_testResultsFolderPath); // Create a new test results folder return QDir().mkdir(_testResultsFolderPath); } -void Test::zipAndDeleteTestResultsFolder() { +QString Test::zipAndDeleteTestResultsFolder() { QString zippedResultsFileName { _testResultsFolderPath + ".zip" }; QFileInfo fileInfo(zippedResultsFileName); - if (!fileInfo.exists()) { + if (fileInfo.exists()) { QFile::remove(zippedResultsFileName); } @@ -55,25 +59,30 @@ void Test::zipAndDeleteTestResultsFolder() { //In all cases, for the next evaluation _testResultsFolderPath = ""; - _index = 1; + _failureIndex = 1; + _successIndex = 1; + + return zippedResultsFileName; } -bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) { - progressBar->setMinimum(0); - progressBar->setMaximum(_expectedImagesFullFilenames.length() - 1); - progressBar->setValue(0); - progressBar->setVisible(true); +int Test::compareImageLists() { + _progressBar->setMinimum(0); + _progressBar->setMaximum(_expectedImagesFullFilenames.length() - 1); + _progressBar->setValue(0); + _progressBar->setVisible(true); // Loop over both lists and compare each pair of images // Quit loop if user has aborted due to a failed test. - bool success{ true }; bool keepOn{ true }; + int numberOfFailures{ 0 }; for (int i = 0; keepOn && i < _expectedImagesFullFilenames.length(); ++i) { // First check that images are the same size QImage resultImage(_resultImagesFullFilenames[i]); QImage expectedImage(_expectedImagesFullFilenames[i]); double similarityIndex; // in [-1.0 .. 1.0], where 1.0 means images are identical + + bool isInteractiveMode = (!_isRunningFromCommandLine && _checkBoxInteractiveMode->isChecked() && !_isRunningInAutomaticTestRun); // similarityIndex is set to -100.0 to indicate images are not the same size if (isInteractiveMode && (resultImage.width() != expectedImage.width() || resultImage.height() != expectedImage.height())) { @@ -83,19 +92,20 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) similarityIndex = _imageComparer.compareImages(resultImage, expectedImage); } - if (similarityIndex < THRESHOLD) { - TestFailure testFailure = TestFailure{ - (float)similarityIndex, - _expectedImagesFullFilenames[i].left(_expectedImagesFullFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) - QFileInfo(_expectedImagesFullFilenames[i].toStdString().c_str()).fileName(), // filename of expected image - QFileInfo(_resultImagesFullFilenames[i].toStdString().c_str()).fileName() // filename of result image - }; + TestResult testResult = TestResult{ + (float)similarityIndex, + _expectedImagesFullFilenames[i].left(_expectedImagesFullFilenames[i].lastIndexOf("/") + 1), // path to the test (including trailing /) + QFileInfo(_expectedImagesFullFilenames[i].toStdString().c_str()).fileName(), // filename of expected image + QFileInfo(_resultImagesFullFilenames[i].toStdString().c_str()).fileName() // filename of result image + }; - _mismatchWindow.setTestFailure(testFailure); + _mismatchWindow.setTestResult(testResult); + + if (similarityIndex < THRESHOLD) { + ++numberOfFailures; if (!isInteractiveMode) { - appendTestResultsToFile(_testResultsFolderPath, testFailure, _mismatchWindow.getComparisonImage()); - success = false; + appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), true); } else { _mismatchWindow.exec(); @@ -103,41 +113,53 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) case USER_RESPONSE_PASS: break; case USE_RESPONSE_FAIL: - appendTestResultsToFile(_testResultsFolderPath, testFailure, _mismatchWindow.getComparisonImage()); - success = false; + appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), true); break; case USER_RESPONSE_ABORT: keepOn = false; - success = false; break; default: assert(false); break; } } + } else { + appendTestResultsToFile(_testResultsFolderPath, testResult, _mismatchWindow.getComparisonImage(), false); } - progressBar->setValue(i); + _progressBar->setValue(i); } - progressBar->setVisible(false); - return success; + _progressBar->setVisible(false); + return numberOfFailures; } -void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { +void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestResult testResult, QPixmap comparisonImage, bool hasFailed) { if (!QDir().exists(_testResultsFolderPath)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Folder " + _testResultsFolderPath + " not found"); exit(-1); } - QString failureFolderPath { _testResultsFolderPath + "/Failure_" + QString::number(_index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) }; - if (!QDir().mkdir(failureFolderPath)) { - QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); + QString resultFolderPath; + if (hasFailed) { + resultFolderPath = _testResultsFolderPath + "/Failure_" + QString::number(_failureIndex) + "--" + + testResult._actualImageFilename.left(testResult._actualImageFilename.length() - 4); + + ++_failureIndex; + } else { + resultFolderPath = _testResultsFolderPath + "/Success_" + QString::number(_successIndex) + "--" + + testResult._actualImageFilename.left(testResult._actualImageFilename.length() - 4); + + ++_successIndex; + } + + if (!QDir().mkdir(resultFolderPath)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Failed to create folder " + resultFolderPath); exit(-1); } - ++_index; - QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); + QFile descriptionFile(resultFolderPath + "/" + TEST_RESULTS_FILENAME); if (!descriptionFile.open(QIODevice::ReadWrite)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + TEST_RESULTS_FILENAME); exit(-1); @@ -145,10 +167,10 @@ void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestFa // Create text file describing the failure QTextStream stream(&descriptionFile); - stream << "Test failed in folder " << testFailure._pathname.left(testFailure._pathname.length() - 1) << endl; // remove trailing '/' - stream << "Expected image was " << testFailure._expectedImageFilename << endl; - stream << "Actual image was " << testFailure._actualImageFilename << endl; - stream << "Similarity _index was " << testFailure._error << endl; + stream << "Test failed in folder " << testResult._pathname.left(testResult._pathname.length() - 1) << endl; // remove trailing '/' + stream << "Expected image was " << testResult._expectedImageFilename << endl; + stream << "Actual image was " << testResult._actualImageFilename << endl; + stream << "Similarity index was " << testResult._error << endl; descriptionFile.close(); @@ -156,26 +178,34 @@ void Test::appendTestResultsToFile(const QString& _testResultsFolderPath, TestFa QString sourceFile; QString destinationFile; - sourceFile = testFailure._pathname + testFailure._expectedImageFilename; - destinationFile = failureFolderPath + "/" + "Expected Image.png"; + sourceFile = testResult._pathname + testResult._expectedImageFilename; + destinationFile = resultFolderPath + "/" + "Expected Image.png"; if (!QFile::copy(sourceFile, destinationFile)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } - sourceFile = testFailure._pathname + testFailure._actualImageFilename; - destinationFile = failureFolderPath + "/" + "Actual Image.png"; + sourceFile = testResult._pathname + testResult._actualImageFilename; + destinationFile = resultFolderPath + "/" + "Actual Image.png"; if (!QFile::copy(sourceFile, destinationFile)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to copy " + sourceFile + " to " + destinationFile); exit(-1); } - comparisonImage.save(failureFolderPath + "/" + "Difference Image.png"); + comparisonImage.save(resultFolderPath + "/" + "Difference Image.png"); } -void Test::startTestsEvaluation(const QString& testFolder, const QString& branchFromCommandLine, const QString& userFromCommandLine) { - if (testFolder.isNull()) { - // Get list of JPEG images in folder, sorted by name +void Test::startTestsEvaluation(const bool isRunningFromCommandLine, + const bool isRunningInAutomaticTestRun, + const QString& snapshotDirectory, + const QString& branchFromCommandLine, + const QString& userFromCommandLine +) { + _isRunningFromCommandLine = isRunningFromCommandLine; + _isRunningInAutomaticTestRun = isRunningInAutomaticTestRun; + + if (snapshotDirectory.isNull()) { + // Get list of PNG images in folder, sorted by name QString previousSelection = _snapshotDirectory; QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); if (!parent.isNull() && parent.right(1) != "/") { @@ -184,14 +214,14 @@ void Test::startTestsEvaluation(const QString& testFolder, const QString& branch _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", parent, QFileDialog::ShowDirsOnly); - // If user cancelled then restore previous selection and return + // If user canceled then restore previous selection and return if (_snapshotDirectory == "") { _snapshotDirectory = previousSelection; return; } } else { - _snapshotDirectory = testFolder; - _exitWhenComplete = true; + _snapshotDirectory = snapshotDirectory; + _exitWhenComplete = (isRunningFromCommandLine && !isRunningInAutomaticTestRun); } // Quit if test results folder could not be created @@ -238,25 +268,28 @@ void Test::startTestsEvaluation(const QString& testFolder, const QString& branch } } - autoTester->downloadImages(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames); + autoTester->downloadFiles(expectedImagesURLs, _snapshotDirectory, _expectedImagesFilenames, (void *)this); } - -void Test::finishTestsEvaluation(bool isRunningFromCommandline, bool interactiveMode, QProgressBar* progressBar) { - bool success = compareImageLists((!isRunningFromCommandline && interactiveMode), progressBar); +void Test::finishTestsEvaluation() { + int numberOfFailures = compareImageLists(); - if (interactiveMode && !isRunningFromCommandline) { - if (success) { + if (!_isRunningFromCommandLine && !_isRunningInAutomaticTestRun) { + if (numberOfFailures == 0) { QMessageBox::information(0, "Success", "All images are as expected"); } else { QMessageBox::information(0, "Failure", "One or more images are not as expected"); } } - zipAndDeleteTestResultsFolder(); + QString zippedFolderName = zipAndDeleteTestResultsFolder(); if (_exitWhenComplete) { exit(0); } + + if (_isRunningInAutomaticTestRun) { + autoTester->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures); + } } bool Test::isAValidDirectory(const QString& pathname) { @@ -302,176 +335,8 @@ void Test::includeTest(QTextStream& textStream, const QString& testPathname) { textStream << "Script.include(testsRootPath + \"" << partialPathWithoutTests + "\");" << endl; } -// Creates a single script in a user-selected folder. -// This script will run all text.js scripts in every applicable sub-folder -void Test::createRecursiveScript() { - // Select folder to start recursing from - QString previousSelection = _testDirectory; - QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); - if (!parent.isNull() && parent.right(1) != "/") { - parent += "/"; - } - - _testDirectory = - QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", parent, - QFileDialog::ShowDirsOnly); - - // If user cancelled then restore previous selection and return - if (_testDirectory == "") { - _testDirectory = previousSelection; - return; - } - - createRecursiveScript(_testDirectory, true); -} - -// This method creates a `testRecursive.js` script in every sub-folder. -void Test::createAllRecursiveScripts() { - // Select folder to start recursing from - QString previousSelection = _testsRootDirectory; - QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); - if (!parent.isNull() && parent.right(1) != "/") { - parent += "/"; - } - - _testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the recursive scripts", - parent, QFileDialog::ShowDirsOnly); - - // If user cancelled then restore previous selection and return - if (_testsRootDirectory == "") { - _testsRootDirectory = previousSelection; - return; - } - - createRecursiveScript(_testsRootDirectory, false); - - QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); - - // Only process directories - QDir dir; - if (!isAValidDirectory(directory)) { - continue; - } - - // Only process directories that have sub-directories - bool hasNoSubDirectories{ true }; - QDirIterator it2(directory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it2.hasNext()) { - QString directory2 = it2.next(); - - // Only process directories - QDir dir; - if (isAValidDirectory(directory2)) { - hasNoSubDirectories = false; - break; - } - } - - if (!hasNoSubDirectories) { - createRecursiveScript(directory, false); - } - } - - QMessageBox::information(0, "Success", "Scripts have been created"); -} - -void Test::createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode) { - const QString recursiveTestsFilename("testRecursive.js"); - QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); - if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { - QMessageBox::critical(0, - "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), - "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\"" - ); - - exit(-1); - } - - QTextStream textStream(&allTestsFilename); - - const QString DATE_TIME_FORMAT("MMM d yyyy, h:mm"); - textStream << "// This is an automatically generated file, created by auto-tester on " << QDateTime::currentDateTime().toString(DATE_TIME_FORMAT) << endl << endl; - - // Include 'autoTest.js' - QString branch = autoTester->getSelectedBranch(); - QString user = autoTester->getSelectedUser(); - - textStream << "PATH_TO_THE_REPO_PATH_UTILS_FILE = \"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + "/tests/utils/branchUtils.js\";" << endl; - textStream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);" << endl; - textStream << "var autoTester = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; - - textStream << "var testsRootPath = autoTester.getTestsRootPath();" << endl << endl; - - // Wait 10 seconds before starting - textStream << "if (typeof Test !== 'undefined') {" << endl; - textStream << " Test.wait(10000);" << endl; - textStream << "};" << endl << endl; - - textStream << "autoTester.enableRecursive();" << endl; - textStream << "autoTester.enableAuto();" << endl << endl; - - // This is used to verify that the recursive test contains at least one test - bool testFound{ false }; - - // Directories are included in reverse order. The autoTester scripts use a stack mechanism, - // so this ensures that the tests run in alphabetical order (a convenience when debugging) - QStringList directories; - - // First test if top-level folder has a test.js file - const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME }; - QFileInfo fileInfo(testPathname); - if (fileInfo.exists()) { - // Current folder contains a test - directories.push_front(testPathname); - - testFound = true; - } - - QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); - while (it.hasNext()) { - QString directory = it.next(); - - // Only process directories - QDir dir(directory); - if (!isAValidDirectory(directory)) { - continue; - } - - const QString testPathname { directory + "/" + TEST_FILENAME }; - QFileInfo fileInfo(testPathname); - if (fileInfo.exists()) { - // Current folder contains a test - directories.push_front(testPathname); - - testFound = true; - } - } - - if (interactiveMode && !testFound) { - QMessageBox::information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); - allTestsFilename.close(); - return; - } - - // Now include the test scripts - for (int i = 0; i < directories.length(); ++i) { - includeTest(textStream, directories.at(i)); - } - - textStream << endl; - textStream << "autoTester.runRecursive();" << endl; - - allTestsFilename.close(); - - if (interactiveMode) { - QMessageBox::information(0, "Success", "Script has been created"); - } -} - void Test::createTests() { - // Rename files sequentially, as ExpectedResult_00000.jpeg, ExpectedResult_00001.jpg and so on + // Rename files sequentially, as ExpectedResult_00000.png, ExpectedResult_00001.png and so on // Any existing expected result images will be deleted QString previousSelection = _snapshotDirectory; QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); @@ -482,7 +347,7 @@ void Test::createTests() { _snapshotDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", parent, QFileDialog::ShowDirsOnly); - // If user cancelled then restore previous selection and return + // If user canceled then restore previous selection and return if (_snapshotDirectory == "") { _snapshotDirectory = previousSelection; return; @@ -497,7 +362,7 @@ void Test::createTests() { _testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select test root folder", parent, QFileDialog::ShowDirsOnly); - // If user cancelled then restore previous selection and return + // If user canceled then restore previous selection and return if (_testsRootDirectory == "") { _testsRootDirectory = previousSelection; return; @@ -613,9 +478,7 @@ ExtractedText Test::getTestScriptLines(QString testFileName) { return relevantTextFromTest; } -// Create an MD file for a user-selected test. -// The folder selected must contain a script named "test.js", the file produced is named "test.md" -void Test::createMDFile() { +bool Test::createFileSetup() { // Folder selection QString previousSelection = _testDirectory; QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); @@ -624,20 +487,18 @@ void Test::createMDFile() { } _testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test", parent, - QFileDialog::ShowDirsOnly); + QFileDialog::ShowDirsOnly); - // If user cancelled then restore previous selection and return + // If user canceled then restore previous selection and return if (_testDirectory == "") { _testDirectory = previousSelection; - return; + return false; } - createMDFile(_testDirectory); - - QMessageBox::information(0, "Success", "MD file has been created"); + return true; } -void Test::createAllMDFiles() { +bool Test::createAllFilesSetup() { // Select folder to start recursing from QString previousSelection = _testsRootDirectory; QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); @@ -645,12 +506,32 @@ void Test::createAllMDFiles() { parent += "/"; } - _testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the root folder for the MD files", parent, - QFileDialog::ShowDirsOnly); + _testsRootDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", parent, + QFileDialog::ShowDirsOnly); // If user cancelled then restore previous selection and return if (_testsRootDirectory == "") { _testsRootDirectory = previousSelection; + return false; + } + + return true; +} + +// Create an MD file for a user-selected test. +// The folder selected must contain a script named "test.js", the file produced is named "test.md" +void Test::createMDFile() { + if (!createFileSetup()) { + return; + } + + if (createMDFile(_testDirectory)) { + QMessageBox::information(0, "Success", "MD file has been created"); + } +} + +void Test::createAllMDFiles() { + if (!createAllFilesSetup()) { return; } @@ -681,18 +562,18 @@ void Test::createAllMDFiles() { QMessageBox::information(0, "Success", "MD files have been created"); } -void Test::createMDFile(const QString& _testDirectory) { +bool Test::createMDFile(const QString& directory) { // Verify folder contains test.js file - QString testFileName(_testDirectory + "/" + TEST_FILENAME); + QString testFileName(directory + "/" + TEST_FILENAME); QFileInfo testFileInfo(testFileName); if (!testFileInfo.exists()) { QMessageBox::critical(0, "Error", "Could not find file: " + TEST_FILENAME); - return; + return false; } ExtractedText testScriptLines = getTestScriptLines(testFileName); - QString mdFilename(_testDirectory + "/" + "test.md"); + QString mdFilename(directory + "/" + "test.md"); QFile mdFile(mdFilename); if (!mdFile.open(QIODevice::WriteOnly)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create file " + mdFilename); @@ -705,9 +586,6 @@ void Test::createMDFile(const QString& _testDirectory) { QString testName = testScriptLines.title; stream << "# " << testName << "\n"; - // Find the relevant part of the path to the test (i.e. from "tests" down - QString partialPath = extractPathFromTestsDown(_testDirectory); - stream << "## Run this script URL: [Manual](./test.js?raw=true) [Auto](./testAuto.js?raw=true)(from menu/Edit/Open and Run scripts from URL...)." << "\n\n"; stream << "## Preconditions" << "\n"; @@ -727,6 +605,223 @@ void Test::createMDFile(const QString& _testDirectory) { } mdFile.close(); + + foreach (auto test, testScriptLines.stepList) { + delete test; + } + testScriptLines.stepList.clear(); + + return true; +} + +void Test::createTestAutoScript() { + if (!createFileSetup()) { + return; + } + + if (createTestAutoScript(_testDirectory)) { + QMessageBox::information(0, "Success", "'autoTester.js` script has been created"); + } +} + +void Test::createAllTestAutoScripts() { + if (!createAllFilesSetup()) { + return; + } + + // First test if top-level folder has a test.js file + const QString testPathname{ _testsRootDirectory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + createTestAutoScript(_testsRootDirectory); + } + + QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir; + if (!isAValidDirectory(directory)) { + continue; + } + + const QString testPathname{ directory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + createTestAutoScript(directory); + } + } + + QMessageBox::information(0, "Success", "'autoTester.js' scripts have been created"); +} + +bool Test::createTestAutoScript(const QString& directory) { + // Verify folder contains test.js file + QString testFileName(directory + "/" + TEST_FILENAME); + QFileInfo testFileInfo(testFileName); + if (!testFileInfo.exists()) { + QMessageBox::critical(0, "Error", "Could not find file: " + TEST_FILENAME); + return false; + } + + QString testAutoScriptFilename(directory + "/" + "testAuto.js"); + QFile testAutoScriptFile(testAutoScriptFilename); + if (!testAutoScriptFile.open(QIODevice::WriteOnly)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Failed to create file " + testAutoScriptFilename); + exit(-1); + } + + QTextStream stream(&testAutoScriptFile); + + stream << "if (typeof PATH_TO_THE_REPO_PATH_UTILS_FILE === 'undefined') PATH_TO_THE_REPO_PATH_UTILS_FILE = 'https://raw.githubusercontent.com/highfidelity/hifi_tests/master/tests/utils/branchUtils.js';\n"; + stream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);\n"; + stream << "var autoTester = createAutoTester(Script.resolvePath('.'));\n\n"; + stream << "autoTester.enableAuto();\n\n"; + stream << "Script.include('./test.js?raw=true');\n"; + + testAutoScriptFile.close(); + return true; +} + +// Creates a single script in a user-selected folder. +// This script will run all text.js scripts in every applicable sub-folder +void Test::createRecursiveScript() { + if (!createFileSetup()) { + return; + } + + createRecursiveScript(_testDirectory, true); + QMessageBox::information(0, "Success", "'testRecursive.js` script has been created"); +} + +// This method creates a `testRecursive.js` script in every sub-folder. +void Test::createAllRecursiveScripts() { + if (!createAllFilesSetup()) { + return; + } + + createRecursiveScript(_testsRootDirectory, false); + + QDirIterator it(_testsRootDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir; + if (!isAValidDirectory(directory)) { + continue; + } + + // Only process directories that have sub-directories + bool hasNoSubDirectories{ true }; + QDirIterator it2(directory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it2.hasNext()) { + QString directory2 = it2.next(); + + // Only process directories + QDir dir; + if (isAValidDirectory(directory2)) { + hasNoSubDirectories = false; + break; + } + } + + if (!hasNoSubDirectories) { + createRecursiveScript(directory, false); + } + } + + QMessageBox::information(0, "Success", "Scripts have been created"); +} + +void Test::createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode) { + const QString recursiveTestsFilename("testRecursive.js"); + QFile allTestsFilename(topLevelDirectory + "/" + recursiveTestsFilename); + if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Failed to create \"" + recursiveTestsFilename + "\" in directory \"" + topLevelDirectory + "\""); + + exit(-1); + } + + QTextStream textStream(&allTestsFilename); + + textStream << "// This is an automatically generated file, created by auto-tester" << endl; + + // Include 'autoTest.js' + QString branch = autoTester->getSelectedBranch(); + QString user = autoTester->getSelectedUser(); + + textStream << "PATH_TO_THE_REPO_PATH_UTILS_FILE = \"https://raw.githubusercontent.com/" + user + "/hifi_tests/" + branch + + "/tests/utils/branchUtils.js\";" + << endl; + textStream << "Script.include(PATH_TO_THE_REPO_PATH_UTILS_FILE);" << endl; + textStream << "var autoTester = createAutoTester(Script.resolvePath(\".\"));" << endl << endl; + + textStream << "var testsRootPath = autoTester.getTestsRootPath();" << endl << endl; + + // Wait 10 seconds before starting + textStream << "if (typeof Test !== 'undefined') {" << endl; + textStream << " Test.wait(10000);" << endl; + textStream << "};" << endl << endl; + + textStream << "autoTester.enableRecursive();" << endl; + textStream << "autoTester.enableAuto();" << endl << endl; + + // This is used to verify that the recursive test contains at least one test + bool testFound{ false }; + + // Directories are included in reverse order. The autoTester scripts use a stack mechanism, + // so this ensures that the tests run in alphabetical order (a convenience when debugging) + QStringList directories; + + // First test if top-level folder has a test.js file + const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + // Current folder contains a test + directories.push_front(testPathname); + + testFound = true; + } + + QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); + while (it.hasNext()) { + QString directory = it.next(); + + // Only process directories + QDir dir(directory); + if (!isAValidDirectory(directory)) { + continue; + } + + const QString testPathname{ directory + "/" + TEST_FILENAME }; + QFileInfo fileInfo(testPathname); + if (fileInfo.exists()) { + // Current folder contains a test + directories.push_front(testPathname); + + testFound = true; + } + } + + if (interactiveMode && !testFound) { + QMessageBox::information(0, "Failure", "No \"" + TEST_FILENAME + "\" files found"); + allTestsFilename.close(); + return; + } + + // Now include the test scripts + for (int i = 0; i < directories.length(); ++i) { + includeTest(textStream, directories.at(i)); + } + + textStream << endl; + textStream << "autoTester.runRecursive();" << endl; + + allTestsFilename.close(); } void Test::createTestsOutline() { @@ -739,7 +834,7 @@ void Test::createTestsOutline() { _testDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select the tests root folder", parent, QFileDialog::ShowDirsOnly); - // If user cancelled then restore previous selection and return + // If user canceled then restore previous selection and return if (_testDirectory == "") { _testDirectory = previousSelection; return; @@ -949,3 +1044,19 @@ QString Test::getExpectedImagePartialSourceDirectory(const QString& filename) { void Test::setTestRailCreateMode(TestRailCreateMode testRailCreateMode) { _testRailCreateMode = testRailCreateMode; } + +void Test::createWebPage(QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit) { + QString testResults = QFileDialog::getOpenFileName(nullptr, "Please select the zipped test results to update from", nullptr, + "Zipped Test Results (*.zip)"); + if (testResults.isNull()) { + return; + } + + QString tempDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select a folder to store temporary files in", + nullptr, QFileDialog::ShowDirsOnly); + if (tempDirectory.isNull()) { + return; + } + + _awsInterface.createWebPageFromResults(testResults, tempDirectory, updateAWSCheckBox, urlLineEdit); +} \ No newline at end of file diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 853e9c98e2..f653a91782 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -16,6 +16,7 @@ #include #include +#include "AWSInterface.h" #include "ImageComparer.h" #include "ui/MismatchWindow.h" #include "TestRailInterface.h" @@ -41,28 +42,41 @@ enum TestRailCreateMode { class Test { public: - Test(); + Test(QProgressBar* progressBar, QCheckBox* checkBoxInteractiveMode); - void startTestsEvaluation(const QString& testFolder = QString(), const QString& branchFromCommandLine = QString(), const QString& userFromCommandLine = QString()); - void finishTestsEvaluation(bool isRunningFromCommandline, bool interactiveMode, QProgressBar* progressBar); + void startTestsEvaluation(const bool isRunningFromCommandLine, + const bool isRunningInAutomaticTestRun, + const QString& snapshotDirectory = QString(), + const QString& branchFromCommandLine = QString(), + const QString& userFromCommandLine = QString()); - void createRecursiveScript(); - void createAllRecursiveScripts(); - void createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode); + void finishTestsEvaluation(); void createTests(); void createTestsOutline(); + bool createFileSetup(); + bool createAllFilesSetup(); + void createMDFile(); void createAllMDFiles(); - void createMDFile(const QString& topLevelDirectory); + bool createMDFile(const QString& directory); + + void createTestAutoScript(); + void createAllTestAutoScripts(); + bool createTestAutoScript(const QString& directory); void createTestRailTestCases(); void createTestRailRun(); + void updateTestRailRunResult(); - bool compareImageLists(bool isInteractiveMode, QProgressBar* progressBar); + void createRecursiveScript(); + void createAllRecursiveScripts(); + void createRecursiveScript(const QString& topLevelDirectory, bool interactiveMode); + + int compareImageLists(); QStringList createListOfAll_imagesInDirectory(const QString& imageFormat, const QString& pathToImageDirectory); @@ -70,10 +84,10 @@ public: void includeTest(QTextStream& textStream, const QString& testPathname); - void appendTestResultsToFile(const QString& testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); + void appendTestResultsToFile(const QString& testResultsFolderPath, TestResult testResult, QPixmap comparisonImage, bool hasFailed); bool createTestResultsFolderPath(const QString& directory); - void zipAndDeleteTestResultsFolder(); + QString zipAndDeleteTestResultsFolder(); static bool isAValidDirectory(const QString& pathname); QString extractPathFromTestsDown(const QString& fullPath); @@ -84,12 +98,20 @@ public: void setTestRailCreateMode(TestRailCreateMode testRailCreateMode); + void createWebPage(QCheckBox* updateAWSCheckBox, QLineEdit* urlLineEdit); + private: + QProgressBar* _progressBar; + QCheckBox* _checkBoxInteractiveMode; + + bool _isRunningFromCommandLine{ false }; + bool _isRunningInAutomaticTestRun{ false }; + const QString TEST_FILENAME { "test.js" }; const QString TEST_RESULTS_FOLDER { "TestResults" }; const QString TEST_RESULTS_FILENAME { "TestResults.txt" }; - const double THRESHOLD{ 0.96 }; + const double THRESHOLD{ 0.935 }; QDir _imageDirectory; @@ -98,7 +120,8 @@ private: ImageComparer _imageComparer; QString _testResultsFolderPath; - int _index { 1 }; + int _failureIndex{ 1 }; + int _successIndex{ 1 }; // Expected images are in the format ExpectedImage_dddd.jpg (d == decimal digit) const int NUM_DIGITS { 5 }; @@ -132,8 +155,9 @@ private: bool _exitWhenComplete{ false }; TestRailInterface _testRailInterface; - TestRailCreateMode _testRailCreateMode { PYTHON }; + + AWSInterface _awsInterface; }; #endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/TestRailInterface.cpp b/tools/auto-tester/src/TestRailInterface.cpp index 93559490e5..f943935539 100644 --- a/tools/auto-tester/src/TestRailInterface.cpp +++ b/tools/auto-tester/src/TestRailInterface.cpp @@ -16,66 +16,40 @@ #include #include +#include #include #include TestRailInterface::TestRailInterface() { _testRailTestCasesSelectorWindow.setURL("https://highfidelity.testrail.net"); - ////_testRailTestCasesSelectorWindow.setURL("https://nissimhadar.testrail.io"); _testRailTestCasesSelectorWindow.setUser("@highfidelity.io"); - ////_testRailTestCasesSelectorWindow.setUser("nissim.hadar@gmail.com"); - _testRailTestCasesSelectorWindow.setProjectID(INTERFACE_PROJECT_ID); - ////_testRailTestCasesSelectorWindow.setProjectID(2); + _testRailTestCasesSelectorWindow.setProjectID(INTERFACE_AUTOMATION_PROJECT_ID); _testRailTestCasesSelectorWindow.setSuiteID(INTERFACE_SUITE_ID); - ////_testRailTestCasesSelectorWindow.setSuiteID(2); _testRailRunSelectorWindow.setURL("https://highfidelity.testrail.net"); - ////_testRailRunSelectorWindow.setURL("https://nissimhadar.testrail.io"); _testRailRunSelectorWindow.setUser("@highfidelity.io"); - ////_testRailRunSelectorWindow.setUser("nissim.hadar@gmail.com"); - _testRailRunSelectorWindow.setProjectID(INTERFACE_PROJECT_ID); - ////_testRailRunSelectorWindow.setProjectID(2); + _testRailRunSelectorWindow.setProjectID(INTERFACE_AUTOMATION_PROJECT_ID); _testRailRunSelectorWindow.setSuiteID(INTERFACE_SUITE_ID); - ////_testRailRunSelectorWindow.setSuiteID(2); _testRailResultsSelectorWindow.setURL("https://highfidelity.testrail.net"); - ////_testRailResultsSelectorWindow.setURL("https://nissimhadar.testrail.io"); _testRailResultsSelectorWindow.setUser("@highfidelity.io"); - ////_testRailResultsSelectorWindow.setUser("nissim.hadar@gmail.com"); - _testRailResultsSelectorWindow.setProjectID(INTERFACE_PROJECT_ID); - ////_testRailResultsSelectorWindow.setProjectID(2); + _testRailResultsSelectorWindow.setProjectID(INTERFACE_AUTOMATION_PROJECT_ID); _testRailResultsSelectorWindow.setSuiteID(INTERFACE_SUITE_ID); - ////_testRailResultsSelectorWindow.setSuiteID(2); + + _pythonInterface = new PythonInterface(); + _pythonCommand = _pythonInterface->getPythonCommand(); } QString TestRailInterface::getObject(const QString& path) { return path.right(path.length() - path.lastIndexOf("/") - 1); } - -bool TestRailInterface::setPythonCommand() { - if (QProcessEnvironment::systemEnvironment().contains("PYTHON_PATH")) { - QString _pythonPath = QProcessEnvironment::systemEnvironment().value("PYTHON_PATH"); - if (!QFile::exists(_pythonPath + "/" + pythonExe)) { - QMessageBox::critical(0, pythonExe, QString("Python executable not found in ") + _pythonPath); - } - _pythonCommand = _pythonPath + "/" + pythonExe; - return true; - } else { - QMessageBox::critical(0, "PYTHON_PATH not defined", - "Please set PYTHON_PATH to directory containing the Python executable"); - return false; - } - - return false; -} - // Creates the testrail.py script // This is the file linked to from http://docs.gurock.com/testrail-api2/bindings-python void TestRailInterface::createTestRailDotPyScript() { @@ -240,7 +214,7 @@ bool TestRailInterface::requestTestRailTestCasesDataFromUser() { _url = _testRailTestCasesSelectorWindow.getURL() + "/"; _user = _testRailTestCasesSelectorWindow.getUser(); _password = _testRailTestCasesSelectorWindow.getPassword(); - ////_password = "tutKA76";//// + _projectID = QString::number(_testRailTestCasesSelectorWindow.getProjectID()); _suiteID = QString::number(_testRailTestCasesSelectorWindow.getSuiteID()); @@ -258,7 +232,7 @@ bool TestRailInterface::requestTestRailRunDataFromUser() { _url = _testRailRunSelectorWindow.getURL() + "/"; _user = _testRailRunSelectorWindow.getUser(); _password = _testRailRunSelectorWindow.getPassword(); - ////_password = "tutKA76";//// + _projectID = QString::number(_testRailRunSelectorWindow.getProjectID()); _suiteID = QString::number(_testRailRunSelectorWindow.getSuiteID()); @@ -276,7 +250,7 @@ bool TestRailInterface::requestTestRailResultsDataFromUser() { _url = _testRailResultsSelectorWindow.getURL() + "/"; _user = _testRailResultsSelectorWindow.getUser(); _password = _testRailResultsSelectorWindow.getPassword(); - ////_password = "tutKA76";//// + _projectID = QString::number(_testRailResultsSelectorWindow.getProjectID()); _suiteID = QString::number(_testRailResultsSelectorWindow.getSuiteID()); @@ -377,8 +351,9 @@ void TestRailInterface::createAddTestCasesPythonScript(const QString& testDirect QMessageBox::Yes | QMessageBox::No).exec() ) { QProcess* process = new QProcess(); - connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); }); + connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); }); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); @@ -489,8 +464,8 @@ void TestRailInterface::addRun() { stream << "\tcase_ids.append(case['id'])\n\n"; // Now, we can create the run - stream << "data = { 'name': '" + _sectionNames[_testRailRunSelectorWindow.getSectionID()].replace("Section", "Run") + - "', 'suite_id': " + _suiteID + + stream << "data = { 'name': '" + _sectionNames[_testRailRunSelectorWindow.getSectionID()].replace("Section", "Run") + "[" + + QHostInfo::localHostName() + "]" + "', 'suite_id': " + _suiteID + ", 'include_all': False, 'case_ids': case_ids}\n"; stream << "run = client.send_post('add_run/" + _projectID + "', data)\n"; @@ -503,7 +478,7 @@ void TestRailInterface::addRun() { ) { QProcess* process = new QProcess(); connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); }); - + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); @@ -511,6 +486,7 @@ void TestRailInterface::addRun() { process->start(_pythonCommand, parameters); } } + void TestRailInterface::updateRunWithResults() { QString filename = _outputDirectory + "/updateRunWithResults.py"; if (QFile::exists(filename)) { @@ -536,17 +512,27 @@ void TestRailInterface::updateRunWithResults() { // The failed tests are read, formatted and inserted into a set // A failure named 'Failure_1--tests.content.entity.material.apply.avatars.00000' is formatted to 'content/entity/material/apply/avatars' // This is the name of the test in TestRail + // + // A success is named `Success_-tests. ... stream << "from os import listdir\n"; stream << "failed_tests = set()\n"; - stream << "for entry in listdir('" + _outputDirectory + "/" + tempName + "'):\n"; - stream << "\tparts = entry.split('--tests.')[1].split('.')\n"; - stream << "\tfailed_test = parts[0]\n"; - stream << "\tfor i in range(1, len(parts) - 1):\n"; - stream << "\t\tfailed_test = failed_test + '/' + parts[i]\n"; + QDir dir(_outputDirectory + "/" + TEMP_NAME); + if (dir.exists()) { + stream << "for entry in listdir('" + _outputDirectory + "/" + TEMP_NAME + "'):\n"; + + // skip over successes + stream << "\tif entry.split('_')[0] == 'Success':\n"; + stream << "\t\tcontinue\n"; + + stream << "\tparts = entry.split('--tests.')[1].split('.')\n"; + stream << "\tfailed_test = parts[0]\n"; + stream << "\tfor i in range(1, len(parts) - 1):\n"; + stream << "\t\tfailed_test = failed_test + '/' + parts[i]\n"; - stream << "\tfailed_tests.add(failed_test)\n\n"; + stream << "\tfailed_tests.add(failed_test)\n\n"; + } // Initialize the array of results that will be eventually used to update TestRail stream << "status_ids = []\n"; @@ -580,7 +566,13 @@ void TestRailInterface::updateRunWithResults() { stream << "\tresults.append({'case_id': case_ids[i], 'status_id': status_ids[i] })\n\n"; stream << "data = { 'results': results }\n"; - stream << "section = client.send_post('add_results_for_cases/' + str(" << runID << "), data)\n"; + stream << "client.send_post('add_results_for_cases/' + str(" << runID << "), data)\n"; + + // Also update the run + QStringList parts = _testResults.split('/'); + QString resultName = parts[parts.length() - 1].split('.')[0]; + stream << "client.send_post('update_run/' + str(" << runID << ")," + << " { 'description' : 'https://hifi-qa.s3.amazonaws.com/" << resultName << "/TestResults.html' })\n"; file.close(); @@ -590,7 +582,7 @@ void TestRailInterface::updateRunWithResults() { ) { QProcess* process = new QProcess(); connect(process, &QProcess::started, this, [=]() { _busyWindow.exec(); }); - + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { _busyWindow.hide(); }); @@ -765,6 +757,7 @@ void TestRailInterface::getReleasesFromTestRail() { QProcess* process = new QProcess(); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { updateReleasesComboData(exitCode, exitStatus); }); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); QStringList parameters = QStringList() << filename; process->start(_pythonCommand, parameters); @@ -779,10 +772,6 @@ void TestRailInterface::createTestSuitePython(const QString& testDirectory, _userGitHub = userGitHub; _branchGitHub = branchGitHub; - if (!setPythonCommand()) { - return; - } - if (!requestTestRailTestCasesDataFromUser()) { return; } @@ -812,6 +801,7 @@ void TestRailInterface::createTestSuiteXML(const QString& testDirectory, QDomElement suiteName = _document.createElement("name"); suiteName.appendChild( _document.createTextNode("Test Suite - " + QDateTime::currentDateTime().toString("yyyy-MM-ddTHH:mm"))); + topLevelSection.appendChild(suiteName); // This is the first call to 'process'. This is then called recursively to build the full XML tree @@ -908,7 +898,7 @@ QDomElement TestRailInterface::processTestXML(const QString& fullDirectory, ++i; QString title{ words[i] }; for (++i; i < words.length() - 1; ++i) { - title += " / " + words[i]; + title += "/" + words[i]; } QDomElement titleElement = _document.createElement("title"); @@ -1036,7 +1026,6 @@ void TestRailInterface::processTestPython(const QString& fullDirectory, QString testContent = QString("Execute instructions in [THIS TEST](") + testMDName + ")"; QString testExpected = QString("Refer to the expected result in the linked description."); - stream << "data = {\n" << "\t'title': '" << title << "',\n" << "\t'template_id': 2,\n" @@ -1087,6 +1076,7 @@ void TestRailInterface::getTestSectionsFromTestRail() { QProcess* process = new QProcess(); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { updateSectionsComboData(exitCode, exitStatus); }); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); QStringList parameters = QStringList() << filename; process->start(_pythonCommand, parameters); @@ -1125,6 +1115,7 @@ void TestRailInterface::getRunsFromTestRail() { QProcess* process = new QProcess(); connect(process, static_cast(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus exitStatus) { updateRunsComboData(exitCode, exitStatus); }); + connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater())); QStringList parameters = QStringList() << filename; @@ -1134,10 +1125,6 @@ void TestRailInterface::getRunsFromTestRail() { void TestRailInterface::createTestRailRun(const QString& outputDirectory) { _outputDirectory = outputDirectory; - if (!setPythonCommand()) { - return; - } - if (!requestTestRailRunDataFromUser()) { return; } @@ -1151,10 +1138,7 @@ void TestRailInterface::createTestRailRun(const QString& outputDirectory) { void TestRailInterface::updateTestRailRunResults(const QString& testResults, const QString& tempDirectory) { _outputDirectory = tempDirectory; - - if (!setPythonCommand()) { - return; - } + _testResults = testResults; if (!requestTestRailResultsDataFromUser()) { return; @@ -1164,11 +1148,20 @@ void TestRailInterface::updateTestRailRunResults(const QString& testResults, con createTestRailDotPyScript(); // Extract test failures from zipped folder - QString tempSubDirectory = tempDirectory + "/" + tempName; + QString tempSubDirectory = tempDirectory + "/" + TEMP_NAME; QDir dir = tempSubDirectory; dir.mkdir(tempSubDirectory); JlCompress::extractDir(testResults, tempSubDirectory); // TestRail will be updated after the process initiated by getTestRunFromTestRail has completed getRunsFromTestRail(); + + dir.rmdir(tempSubDirectory); +} + +void TestRailInterface::extractTestFailuresFromZippedFolder(const QString& testResults, const QString& tempDirectory) { + QString tempSubDirectory = tempDirectory + "/" + TEMP_NAME; + QDir dir = tempSubDirectory; + dir.mkdir(tempSubDirectory); + JlCompress::extractDir(testResults, tempSubDirectory); } \ No newline at end of file diff --git a/tools/auto-tester/src/TestRailInterface.h b/tools/auto-tester/src/TestRailInterface.h index 6f250dfbba..6843ca0142 100644 --- a/tools/auto-tester/src/TestRailInterface.h +++ b/tools/auto-tester/src/TestRailInterface.h @@ -12,7 +12,6 @@ #define hifi_test_testrail_interface_h #include "ui/BusyWindow.h" - #include "ui/TestRailTestCasesSelectorWindow.h" #include "ui/TestRailRunSelectorWindow.h" #include "ui/TestRailResultsSelectorWindow.h" @@ -22,7 +21,9 @@ #include #include -class TestRailInterface : public QObject{ +#include "PythonInterface.h" + +class TestRailInterface : public QObject { Q_OBJECT public: @@ -65,9 +66,7 @@ public: bool requestTestRailRunDataFromUser(); bool requestTestRailResultsDataFromUser(); - void createAddTestCasesPythonScript(const QString& testDirectory, - const QString& userGitHub, - const QString& branchGitHub); + void createAddTestCasesPythonScript(const QString& testDirectory, const QString& userGitHub, const QString& branchGitHub); void processDirectoryPython(const QString& directory, QTextStream& stream, @@ -88,14 +87,14 @@ public: void addRun(); void updateRunWithResults(); - bool setPythonCommand(); + void extractTestFailuresFromZippedFolder(const QString& testResults, const QString& tempDirectory); private: // HighFidelity Interface project ID in TestRail - const int INTERFACE_PROJECT_ID{ 24 }; + const int INTERFACE_AUTOMATION_PROJECT_ID{ 26 }; // Rendering suite ID - const int INTERFACE_SUITE_ID{ 1147 }; + const int INTERFACE_SUITE_ID{ 1312 }; QDomDocument _document; @@ -111,13 +110,11 @@ private: QString _suiteID; QString _testDirectory; + QString _testResults; QString _outputDirectory; QString _userGitHub; QString _branchGitHub; - const QString pythonExe{ "python.exe" }; - QString _pythonCommand; - QStringList _releaseNames; QStringList _sectionNames; @@ -126,7 +123,10 @@ private: QStringList _runNames; std::vector _runIDs; - QString tempName{ "fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf" }; + QString TEMP_NAME{ "fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf" }; + + PythonInterface* _pythonInterface; + QString _pythonCommand; }; #endif \ No newline at end of file diff --git a/tools/auto-tester/src/TestRunner.cpp b/tools/auto-tester/src/TestRunner.cpp new file mode 100644 index 0000000000..674cf6f8e8 --- /dev/null +++ b/tools/auto-tester/src/TestRunner.cpp @@ -0,0 +1,608 @@ +// +// TestRunner.cpp +// +// Created by Nissim Hadar on 1 Sept 2018. +// 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 "TestRunner.h" + +#include +#include +#include + +#include "ui/AutoTester.h" +extern AutoTester* autoTester; + +#ifdef Q_OS_WIN +#include +#include +#endif + +TestRunner::TestRunner(std::vector dayCheckboxes, + std::vector timeEditCheckboxes, + std::vector timeEdits, + QLabel* workingFolderLabel, + QCheckBox* runServerless, + QCheckBox* runLatest, + QLineEdit* url, + QPushButton* runNow, + QObject* parent) : + QObject(parent) { + _dayCheckboxes = dayCheckboxes; + _timeEditCheckboxes = timeEditCheckboxes; + _timeEdits = timeEdits; + _workingFolderLabel = workingFolderLabel; + _runServerless = runServerless; + _runLatest = runLatest; + _url = url; + _runNow = runNow; + + installerThread = new QThread(); + installerWorker = new Worker(); + installerWorker->moveToThread(installerThread); + installerThread->start(); + connect(this, SIGNAL(startInstaller()), installerWorker, SLOT(runCommand())); + connect(installerWorker, SIGNAL(commandComplete()), this, SLOT(installationComplete())); + + interfaceThread = new QThread(); + interfaceWorker = new Worker(); + interfaceThread->start(); + interfaceWorker->moveToThread(interfaceThread); + connect(this, SIGNAL(startInterface()), interfaceWorker, SLOT(runCommand())); + connect(interfaceWorker, SIGNAL(commandComplete()), this, SLOT(interfaceExecutionComplete())); +} + +TestRunner::~TestRunner() { + delete installerThread; + delete interfaceThread; + + delete interfaceThread; + delete interfaceWorker; + + if (_timer) { + delete _timer; + } +} + +void TestRunner::setWorkingFolder() { + // Everything will be written to this folder + QString previousSelection = _workingFolder; + QString parent = previousSelection.left(previousSelection.lastIndexOf('/')); + if (!parent.isNull() && parent.right(1) != "/") { + parent += "/"; + } + + _workingFolder = QFileDialog::getExistingDirectory(nullptr, "Please select a temporary folder for installation", parent, + QFileDialog::ShowDirsOnly); + + // If user canceled then restore previous selection and return + if (_workingFolder == "") { + _workingFolder = previousSelection; + return; + } + + _installationFolder = _workingFolder + "/High Fidelity"; + _logFile.setFileName(_workingFolder + "/log.txt"); + + autoTester->enableRunTabControls(); + _workingFolderLabel->setText(QDir::toNativeSeparators(_workingFolder)); + + _timer = new QTimer(this); + connect(_timer, SIGNAL(timeout()), this, SLOT(checkTime())); + _timer->start(30 * 1000); //time specified in ms +} + +void TestRunner::run() { + _runNow->setEnabled(false); + + _testStartDateTime = QDateTime::currentDateTime(); + _automatedTestIsRunning = true; + + // Initial setup + _branch = autoTester->getSelectedBranch(); + _user = autoTester->getSelectedUser(); + + // This will be restored at the end of the tests + saveExistingHighFidelityAppDataFolder(); + + // Download the latest High Fidelity build XML. + // Note that this is not needed for PR builds (or whenever `Run Latest` is unchecked) + // It is still downloaded, to simplify the flow + QStringList urls; + QStringList filenames; + + urls << DEV_BUILD_XML_URL; + filenames << DEV_BUILD_XML_FILENAME; + + updateStatusLabel("Downloading Build XML"); + + buildXMLDownloaded = false; + autoTester->downloadFiles(urls, _workingFolder, filenames, (void*)this); + + // `downloadComplete` will run after download has completed +} + +void TestRunner::downloadComplete() { + if (!buildXMLDownloaded) { + // Download of Build XML has completed + buildXMLDownloaded = true; + + // Download the High Fidelity installer + QStringList urls; + QStringList filenames; + if (_runLatest->isChecked()) { + parseBuildInformation(); + + _installerFilename = INSTALLER_FILENAME_LATEST; + + urls << _buildInformation.url; + filenames << _installerFilename; + } else { + QString urlText = _url->text(); + urls << urlText; + _installerFilename = getInstallerNameFromURL(urlText); + filenames << _installerFilename; + } + + updateStatusLabel("Downloading installer"); + + autoTester->downloadFiles(urls, _workingFolder, filenames, (void*)this); + + // `downloadComplete` will run again after download has completed + + } else { + // Download of Installer has completed + appendLog(QString("Tests started at ") + QString::number(_testStartDateTime.time().hour()) + ":" + + QString("%1").arg(_testStartDateTime.time().minute(), 2, 10, QChar('0')) + ", on " + + _testStartDateTime.date().toString("ddd, MMM d, yyyy")); + + updateStatusLabel("Installing"); + + // Kill any existing processes that would interfere with installation + killProcesses(); + + runInstaller(); + } +} + +void TestRunner::runInstaller() { + // Qt cannot start an installation process using QProcess::start (Qt Bug 9761) + // To allow installation, the installer is run using the `system` command + + QStringList arguments{ QStringList() << QString("/S") << QString("/D=") + QDir::toNativeSeparators(_installationFolder) }; + + QString installerFullPath = _workingFolder + "/" + _installerFilename; + + QString commandLine = + "\"" + QDir::toNativeSeparators(installerFullPath) + "\"" + " /S /D=" + QDir::toNativeSeparators(_installationFolder); + + installerWorker->setCommandLine(commandLine); + emit startInstaller(); +} + +void TestRunner::installationComplete() { + verifyInstallationSucceeded(); + + createSnapshotFolder(); + + updateStatusLabel("Running tests"); + + if (!_runServerless->isChecked()) { + startLocalServerProcesses(); + } + + runInterfaceWithTestScript(); +} + +void TestRunner::verifyInstallationSucceeded() { + // Exit if the executables are missing. + // On Windows, the reason is probably that UAC has blocked the installation. This is treated as a critical error +#ifdef Q_OS_WIN + QFileInfo interfaceExe(QDir::toNativeSeparators(_installationFolder) + "\\interface.exe"); + QFileInfo assignmentClientExe(QDir::toNativeSeparators(_installationFolder) + "\\assignment-client.exe"); + QFileInfo domainServerExe(QDir::toNativeSeparators(_installationFolder) + "\\domain-server.exe"); + + if (!interfaceExe.exists() || !assignmentClientExe.exists() || !domainServerExe.exists()) { + QMessageBox::critical(0, "Installation of High Fidelity has failed", "Please verify that UAC has been disabled"); + exit(-1); + } +#endif +} + +void TestRunner::saveExistingHighFidelityAppDataFolder() { + QString dataDirectory{ "NOT FOUND" }; + +#ifdef Q_OS_WIN + dataDirectory = qgetenv("USERPROFILE") + "\\AppData\\Roaming"; +#endif + + if (_runLatest->isChecked()) { + _appDataFolder = dataDirectory + "\\High Fidelity"; + } else { + // We are running a PR build + _appDataFolder = dataDirectory + "\\High Fidelity - " + getPRNumberFromURL(_url->text()); + } + + _savedAppDataFolder = dataDirectory + "/" + UNIQUE_FOLDER_NAME; + if (_savedAppDataFolder.exists()) { + _savedAppDataFolder.removeRecursively(); + } + + if (_appDataFolder.exists()) { + // The original folder is saved in a unique name + _appDataFolder.rename(_appDataFolder.path(), _savedAppDataFolder.path()); + } + + // Copy an "empty" AppData folder (i.e. no entities) + copyFolder(QDir::currentPath() + "/AppDataHighFidelity", _appDataFolder.path()); +} + +void TestRunner::createSnapshotFolder() { + _snapshotFolder = _workingFolder + "/" + SNAPSHOT_FOLDER_NAME; + + // Just delete all PNGs from the folder if it already exists + if (QDir(_snapshotFolder).exists()) { + // Note that we cannot use just a `png` filter, as the filenames include periods + // Also, delete any `jpg` and `txt` files + // The idea is to leave only previous zipped result folders + QDirIterator it(_snapshotFolder.toStdString().c_str()); + while (it.hasNext()) { + QString filename = it.next(); + if (filename.right(4) == ".png" || filename.right(4) == ".jpg" || filename.right(4) == ".txt") { + QFile::remove(filename); + } + } + + } else { + QDir().mkdir(_snapshotFolder); + } +} + +void TestRunner::killProcesses() { +#ifdef Q_OS_WIN + try { + QStringList processesToKill = QStringList() << "interface.exe" + << "assignment-client.exe" + << "domain-server.exe" + << "server-console.exe"; + + // Loop until all pending processes to kill have actually died + QStringList pendingProcessesToKill; + do { + pendingProcessesToKill.clear(); + + // Get list of running tasks + HANDLE processSnapHandle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (processSnapHandle == INVALID_HANDLE_VALUE) { + throw("Process snapshot creation failure"); + } + + PROCESSENTRY32 processEntry32; + processEntry32.dwSize = sizeof(PROCESSENTRY32); + if (!Process32First(processSnapHandle, &processEntry32)) { + CloseHandle(processSnapHandle); + throw("Process32First failed"); + } + + // Kill any task in the list + do { + foreach (QString process, processesToKill) + if (QString(processEntry32.szExeFile) == process) { + QString commandLine = "taskkill /im " + process + " /f >nul"; + system(commandLine.toStdString().c_str()); + pendingProcessesToKill << process; + } + } while (Process32Next(processSnapHandle, &processEntry32)); + + QThread::sleep(2); + } while (!pendingProcessesToKill.isEmpty()); + + } catch (QString errorMessage) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); + exit(-1); + } catch (...) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); + exit(-1); + } +#endif +} + +void TestRunner::startLocalServerProcesses() { +#ifdef Q_OS_WIN + QString commandLine; + + commandLine = "start \"domain-server.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\domain-server.exe\""; + system(commandLine.toStdString().c_str()); + + commandLine = + "start \"assignment-client.exe\" \"" + QDir::toNativeSeparators(_installationFolder) + "\\assignment-client.exe\" -n 6"; + system(commandLine.toStdString().c_str()); +#endif + // Give server processes time to stabilize + QThread::sleep(20); +} + +void TestRunner::runInterfaceWithTestScript() { + QString exeFile = QString("\"") + QDir::toNativeSeparators(_installationFolder) + "\\interface.exe\""; + QString snapshotFolder = QString("\"") + QDir::toNativeSeparators(_snapshotFolder) + "\""; + + QString url = QString("hifi://localhost"); + if (_runServerless->isChecked()) { + // Move to an empty area + url = "file:///~serverless/tutorial.json"; + } else { + url = "hifi://localhost"; + } + + QString testScript = + QString("https://raw.githubusercontent.com/") + _user + "/hifi_tests/" + _branch + "/tests/testRecursive.js"; + + QString commandLine = exeFile + " --url " + url + " --no-updater --no-login" + " --testScript " + testScript + + " quitWhenFinished --testResultsLocation " + snapshotFolder; + + interfaceWorker->setCommandLine(commandLine); + emit startInterface(); +} + +void TestRunner::interfaceExecutionComplete() { + killProcesses(); + + QFileInfo testCompleted(QDir::toNativeSeparators(_snapshotFolder) +"/tests_completed.txt"); + if (!testCompleted.exists()) { + QMessageBox::critical(0, "Tests not completed", "Interface seems to have crashed before completion of the test scripts"); + _runNow->setEnabled(true); + return; + } + + evaluateResults(); + + // The High Fidelity AppData folder will be restored after evaluation has completed +} + +void TestRunner::evaluateResults() { + updateStatusLabel("Evaluating results"); + autoTester->startTestsEvaluation(false, true, _snapshotFolder, _branch, _user); +} + +void TestRunner::automaticTestRunEvaluationComplete(QString zippedFolder, int numberOfFailures) { + addBuildNumberToResults(zippedFolder); + restoreHighFidelityAppDataFolder(); + + updateStatusLabel("Testing complete"); + + QDateTime currentDateTime = QDateTime::currentDateTime(); + + QString completionText = QString("Tests completed at ") + QString::number(currentDateTime.time().hour()) + ":" + + QString("%1").arg(currentDateTime.time().minute(), 2, 10, QChar('0')) + ", on " + + currentDateTime.date().toString("ddd, MMM d, yyyy"); + + if (numberOfFailures == 0) { + completionText += "; no failures"; + } else if (numberOfFailures == 1) { + completionText += "; 1 failure"; + } else { + completionText += QString("; ") + QString::number(numberOfFailures) + " failures"; + } + appendLog(completionText); + + _automatedTestIsRunning = false; + + _runNow->setEnabled(true); +} + +void TestRunner::addBuildNumberToResults(QString zippedFolderName) { + QString augmentedFilename; + if (!_runLatest->isChecked()) { + augmentedFilename = zippedFolderName.replace("local", getPRNumberFromURL(_url->text())); + } else { + augmentedFilename = zippedFolderName.replace("local", _buildInformation.build); + } + QFile::rename(zippedFolderName, augmentedFilename); +} + +void TestRunner::restoreHighFidelityAppDataFolder() { + _appDataFolder.removeRecursively(); + + if (_savedAppDataFolder != QDir()) { + _appDataFolder.rename(_savedAppDataFolder.path(), _appDataFolder.path()); + } +} + +// Copies a folder recursively +void TestRunner::copyFolder(const QString& source, const QString& destination) { + try { + if (!QFileInfo(source).isDir()) { + // just a file copy + QFile::copy(source, destination); + } else { + QDir destinationDir(destination); + if (!destinationDir.cdUp()) { + throw("'source '" + source + "'seems to be a root folder"); + } + + if (!destinationDir.mkdir(QFileInfo(destination).fileName())) { + throw("Could not create destination folder '" + destination + "'"); + } + + QStringList fileNames = + QDir(source).entryList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden | QDir::System); + + foreach (const QString& fileName, fileNames) { + copyFolder(QString(source + "/" + fileName), QString(destination + "/" + fileName)); + } + } + } catch (QString errorMessage) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); + exit(-1); + } catch (...) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); + exit(-1); + } +} + +void TestRunner::checkTime() { + // No processing is done if a test is running + if (_automatedTestIsRunning) { + return; + } + + QDateTime now = QDateTime::currentDateTime(); + + // Check day of week + if (!_dayCheckboxes.at(now.date().dayOfWeek() - 1)->isChecked()) { + return; + } + + // Check the time + bool timeToRun{ false }; + + for (size_t i = 0; i < std::min(_timeEditCheckboxes.size(), _timeEdits.size()); ++i) { + if (_timeEditCheckboxes[i]->isChecked() && (_timeEdits[i]->time().hour() == now.time().hour()) && + (_timeEdits[i]->time().minute() == now.time().minute())) { + timeToRun = true; + break; + } + } + + if (timeToRun) { + run(); + } +} + +void TestRunner::updateStatusLabel(const QString& message) { + autoTester->updateStatusLabel(message); +} + +void TestRunner::appendLog(const QString& message) { + if (!_logFile.open(QIODevice::Append | QIODevice::Text)) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), + "Could not open the log file"); + exit(-1); + } + + _logFile.write(message.toStdString().c_str()); + _logFile.write("\n"); + _logFile.close(); + + autoTester->appendLogWindow(message); +} + +QString TestRunner::getInstallerNameFromURL(const QString& url) { + // An example URL: https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe + try { + QStringList urlParts = url.split("/"); + return urlParts[urlParts.size() - 1]; + } catch (QString errorMessage) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); + exit(-1); + } catch (...) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); + exit(-1); + } +} + +QString TestRunner::getPRNumberFromURL(const QString& url) { + try { + QStringList urlParts = url.split("/"); + QStringList filenameParts = urlParts[urlParts.size() - 1].split("-"); + if (filenameParts.size() <= 3) { + throw "URL not in expected format, should look like `https://deployment.highfidelity.com/jobs/pr-build/label%3Dwindows/13023/HighFidelity-Beta-Interface-PR14006-be76c43.exe`"; + } + return filenameParts[filenameParts.size() - 2]; + } catch (QString errorMessage) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); + exit(-1); + } catch (...) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); + exit(-1); + } +} + +void TestRunner::parseBuildInformation() { + try { + QDomDocument domDocument; + QString filename{ _workingFolder + "/" + DEV_BUILD_XML_FILENAME }; + QFile file(filename); + if (!file.open(QIODevice::ReadOnly) || !domDocument.setContent(&file)) { + throw QString("Could not open " + filename); + } + + QString platformOfInterest; +#ifdef Q_OS_WIN + platformOfInterest = "windows"; +#elif defined(Q_OS_MAC) + platformOfInterest = "mac"; +#endif + QDomElement element = domDocument.documentElement(); + + // Verify first element is "projects" + if (element.tagName() != "projects") { + throw("File seems to be in wrong format"); + } + + element = element.firstChild().toElement(); + if (element.tagName() != "project") { + throw("File seems to be in wrong format"); + } + + if (element.attribute("name") != "interface") { + throw("File is not from 'interface' build"); + } + + // Now loop over the platforms + while (!element.isNull()) { + element = element.firstChild().toElement(); + if (element.tagName() != "platform" || element.attribute("name") != platformOfInterest) { + continue; + } + + // Next element should be the build + element = element.firstChild().toElement(); + if (element.tagName() != "build") { + throw("File seems to be in wrong format"); + } + + // Next element should be the version + element = element.firstChild().toElement(); + if (element.tagName() != "version") { + throw("File seems to be in wrong format"); + } + + // Add the build number to the end of the filename + _buildInformation.build = element.text(); + + // First sibling should be stable_version + element = element.nextSibling().toElement(); + if (element.tagName() != "stable_version") { + throw("File seems to be in wrong format"); + } + + // Next sibling should be url + element = element.nextSibling().toElement(); + if (element.tagName() != "url") { + throw("File seems to be in wrong format"); + } + _buildInformation.url = element.text(); + } + + } catch (QString errorMessage) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), errorMessage); + exit(-1); + } catch (...) { + QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "unknown error"); + exit(-1); + } +} + +void Worker::setCommandLine(const QString& commandLine) { + _commandLine = commandLine; +} + +int Worker::runCommand() { + int result = system(_commandLine.toStdString().c_str()); + emit commandComplete(); + return result; +} \ No newline at end of file diff --git a/tools/auto-tester/src/TestRunner.h b/tools/auto-tester/src/TestRunner.h new file mode 100644 index 0000000000..e6cb7cd764 --- /dev/null +++ b/tools/auto-tester/src/TestRunner.h @@ -0,0 +1,151 @@ +// +// TestRunner.h +// +// Created by Nissim Hadar on 1 Sept 2018. +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_testRunner_h +#define hifi_testRunner_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +class BuildInformation { +public: + QString build; + QString url; +}; + +class Worker; + +class TestRunner : public QObject { + Q_OBJECT +public: + explicit TestRunner(std::vector dayCheckboxes, + std::vector timeEditCheckboxes, + std::vector timeEdits, + QLabel* workingFolderLabel, + QCheckBox* runServerless, + QCheckBox* runLatest, + QLineEdit* url, + QPushButton* runNow, + QObject* parent = 0); + + ~TestRunner(); + + void setWorkingFolder(); + + void run(); + + void downloadComplete(); + void runInstaller(); + void verifyInstallationSucceeded(); + + void saveExistingHighFidelityAppDataFolder(); + void restoreHighFidelityAppDataFolder(); + + void createSnapshotFolder(); + + void killProcesses(); + void startLocalServerProcesses(); + + void runInterfaceWithTestScript(); + + void evaluateResults(); + void automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures); + void addBuildNumberToResults(QString zippedFolderName); + + void copyFolder(const QString& source, const QString& destination); + + void updateStatusLabel(const QString& message); + void appendLog(const QString& message); + + QString getInstallerNameFromURL(const QString& url); + QString getPRNumberFromURL(const QString& url); + + void parseBuildInformation(); + +private slots: + void checkTime(); + void installationComplete(); + void interfaceExecutionComplete(); + +signals: + void startInstaller(); + void startInterface(); + +private: + bool _automatedTestIsRunning{ false }; + + const QString INSTALLER_FILENAME_LATEST{ "HighFidelity-Beta-latest-dev.exe" }; + + QString _installerURL; + QString _installerFilename; + const QString DEV_BUILD_XML_URL{ "https://highfidelity.com/dev-builds.xml" }; + const QString DEV_BUILD_XML_FILENAME{ "dev-builds.xml" }; + + bool buildXMLDownloaded; + + QDir _appDataFolder; + QDir _savedAppDataFolder; + + QString _workingFolder; + QString _installationFolder; + QString _snapshotFolder; + + const QString UNIQUE_FOLDER_NAME{ "fgadhcUDHSFaidsfh3478JJJFSDFIUSOEIrf" }; + const QString SNAPSHOT_FOLDER_NAME{ "snapshots" }; + + QString _branch; + QString _user; + + std::vector _dayCheckboxes; + std::vector _timeEditCheckboxes; + std::vector _timeEdits; + QLabel* _workingFolderLabel; + QCheckBox* _runServerless; + QCheckBox* _runLatest; + QLineEdit* _url; + QPushButton* _runNow; + QTimer* _timer; + + QFile _logFile; + + QDateTime _testStartDateTime; + + QThread* installerThread; + QThread* interfaceThread; + Worker* installerWorker; + Worker* interfaceWorker; + + BuildInformation _buildInformation; +}; + +class Worker : public QObject { + Q_OBJECT +public: + void setCommandLine(const QString& commandLine); + +public slots: + int runCommand(); + +signals: + void commandComplete(); + void startInstaller(); + void startInterface(); + +private: + QString _commandLine; +}; +#endif // hifi_testRunner_h \ No newline at end of file diff --git a/tools/auto-tester/src/common.h b/tools/auto-tester/src/common.h index 939814df62..5df4e9c921 100644 --- a/tools/auto-tester/src/common.h +++ b/tools/auto-tester/src/common.h @@ -12,9 +12,9 @@ #include -class TestFailure { +class TestResult { public: - TestFailure(float error, QString pathname, QString expectedImageFilename, QString actualImageFilename) : + TestResult(float error, QString pathname, QString expectedImageFilename, QString actualImageFilename) : _error(error), _pathname(pathname), _expectedImageFilename(expectedImageFilename), diff --git a/tools/auto-tester/src/main.cpp b/tools/auto-tester/src/main.cpp index 03b8cf51ff..ac4b4593c5 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/auto-tester/src/main.cpp @@ -66,7 +66,7 @@ int main(int argc, char *argv[]) { autoTester->setup(); if (!testFolder.isNull()) { - autoTester->runFromCommandLine(testFolder, branch, user); + autoTester->startTestsEvaluation(true ,false, testFolder, branch, user); } else { autoTester->show(); } diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 13bda4853f..32457c2224 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -28,34 +28,86 @@ AutoTester::AutoTester(QWidget* parent) : QMainWindow(parent) { connect(_ui.actionAbout, &QAction::triggered, this, &AutoTester::about); connect(_ui.actionContent, &QAction::triggered, this, &AutoTester::content); + // The second tab hides and shows the Windows task bar #ifndef Q_OS_WIN - _ui.tabWidget->setTabEnabled(3, false); + _ui.tabWidget->removeTab(1); #endif - // helpWindow.textBrowser->setText() + _ui.statusLabel->setText(""); + _ui.plainTextEdit->setReadOnly(true); + + setWindowTitle("Auto Tester - v6.7"); + + // Coming soon to an auto-tester near you... + //// _helpWindow.textBrowser->setText() +} + +AutoTester::~AutoTester() { + delete _signalMapper; + + if (_test) { + delete _test; + } + + if (_testRunner) { + delete _testRunner; + } } void AutoTester::setup() { - _test = new Test(); + if (_test) { + delete _test; + } + _test = new Test(_ui.progressBar, _ui.checkBoxInteractiveMode); + + std::vector dayCheckboxes; + dayCheckboxes.emplace_back(_ui.mondayCheckBox); + dayCheckboxes.emplace_back(_ui.tuesdayCheckBox); + dayCheckboxes.emplace_back(_ui.wednesdayCheckBox); + dayCheckboxes.emplace_back(_ui.thursdayCheckBox); + dayCheckboxes.emplace_back(_ui.fridayCheckBox); + dayCheckboxes.emplace_back(_ui.saturdayCheckBox); + dayCheckboxes.emplace_back(_ui.sundayCheckBox); + + std::vector timeEditCheckboxes; + timeEditCheckboxes.emplace_back(_ui.timeEdit1checkBox); + timeEditCheckboxes.emplace_back(_ui.timeEdit2checkBox); + timeEditCheckboxes.emplace_back(_ui.timeEdit3checkBox); + timeEditCheckboxes.emplace_back(_ui.timeEdit4checkBox); + + std::vector timeEdits; + timeEdits.emplace_back(_ui.timeEdit1); + timeEdits.emplace_back(_ui.timeEdit2); + timeEdits.emplace_back(_ui.timeEdit3); + timeEdits.emplace_back(_ui.timeEdit4); + + if (_testRunner) { + delete _testRunner; + } + _testRunner = new TestRunner(dayCheckboxes, timeEditCheckboxes, timeEdits, _ui.workingFolderLabel, _ui.checkBoxServerless, _ui.checkBoxRunLatest, _ui.urlLineEdit, _ui.runNowButton); } -void AutoTester::runFromCommandLine(const QString& testFolder, const QString& branch, const QString& user) { - _isRunningFromCommandline = true; - _test->startTestsEvaluation(testFolder, branch, user); +void AutoTester::startTestsEvaluation(const bool isRunningFromCommandLine, + const bool isRunningInAutomaticTestRun, + const QString& snapshotDirectory, + const QString& branch, + const QString& user +) { + _test->startTestsEvaluation(isRunningFromCommandLine, isRunningInAutomaticTestRun, snapshotDirectory, branch, user); } void AutoTester::on_tabWidget_currentChanged(int index) { - if (index == 1 || index == 2) { - _ui.userTextEdit->setDisabled(false); - _ui.branchTextEdit->setDisabled(false); + if (index == 0 || index == 2 || index == 3) { + _ui.userLineEdit->setDisabled(false); + _ui.branchLineEdit->setDisabled(false); } else { - _ui.userTextEdit->setDisabled(true); - _ui.branchTextEdit->setDisabled(true); + _ui.userLineEdit->setDisabled(true); + _ui.branchLineEdit->setDisabled(true); } } void AutoTester::on_evaluateTestsButton_clicked() { - _test->startTestsEvaluation(); + _test->startTestsEvaluation(false, false); } void AutoTester::on_createRecursiveScriptButton_clicked() { @@ -78,6 +130,14 @@ void AutoTester::on_createAllMDFilesButton_clicked() { _test->createAllMDFiles(); } +void AutoTester::on_createTestAutoScriptButton_clicked() { + _test->createTestAutoScript(); +} + +void AutoTester::on_createAllTestAutoScriptsButton_clicked() { + _test->createAllTestAutoScripts(); +} + void AutoTester::on_createTestsOutlineButton_clicked() { _test->createTestsOutline(); } @@ -90,6 +150,28 @@ void AutoTester::on_createTestRailRunButton_clicked() { _test->createTestRailRun(); } +void AutoTester::on_setWorkingFolderButton_clicked() { + _testRunner->setWorkingFolder(); +} + +void AutoTester::enableRunTabControls() { + _ui.runNowButton->setEnabled(true); + _ui.daysGroupBox->setEnabled(true); + _ui.timesGroupBox->setEnabled(true); +} + +void AutoTester::on_runNowButton_clicked() { + _testRunner->run(); +} + +void AutoTester::on_checkBoxRunLatest_clicked() { + _ui.urlLineEdit->setEnabled(!_ui.checkBoxRunLatest->isChecked()); +} + +void AutoTester::automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures) { + _testRunner->automaticTestRunEvaluationComplete(zippedFolderName, numberOfFailures); +} + void AutoTester::on_updateTestRailRunResultsButton_clicked() { _test->updateTestRailRunResult(); } @@ -130,7 +212,11 @@ void AutoTester::on_createXMLScriptRadioButton_clicked() { _test->setTestRailCreateMode(XML); } -void AutoTester::downloadImage(const QUrl& url) { +void AutoTester::on_createWebPagePushButton_clicked() { + _test->createWebPage(_ui.updateAWSCheckBox, _ui.awsURLLineEdit); +} + +void AutoTester::downloadFile(const QUrl& url) { _downloaders.emplace_back(new Downloader(url, this)); connect(_downloaders[_index], SIGNAL(downloaded()), _signalMapper, SLOT(map())); @@ -139,70 +225,86 @@ void AutoTester::downloadImage(const QUrl& url) { ++_index; } -void AutoTester::downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames) { +void AutoTester::downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void *caller) { + connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveFile(int))); + _directoryName = directoryName; _filenames = filenames; + _caller = caller; - _numberOfImagesToDownload = URLs.size(); - _numberOfImagesDownloaded = 0; + _numberOfFilesToDownload = URLs.size(); + _numberOfFilesDownloaded = 0; _index = 0; _ui.progressBar->setMinimum(0); - _ui.progressBar->setMaximum(_numberOfImagesToDownload - 1); + _ui.progressBar->setMaximum(_numberOfFilesToDownload - 1); _ui.progressBar->setValue(0); _ui.progressBar->setVisible(true); - _downloaders.clear(); - for (int i = 0; i < _numberOfImagesToDownload; ++i) { - QUrl imageURL(URLs[i]); - downloadImage(imageURL); + foreach (auto downloader, _downloaders) { + delete downloader; } - connect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveImage(int))); + _downloaders.clear(); + for (int i = 0; i < _numberOfFilesToDownload; ++i) { + downloadFile(URLs[i]); + } } -void AutoTester::saveImage(int index) { +void AutoTester::saveFile(int index) { try { QFile file(_directoryName + "/" + _filenames[index]); file.open(QIODevice::WriteOnly); file.write(_downloaders[index]->downloadedData()); file.close(); } catch (...) { - QMessageBox::information(0, "Test Aborted", "Failed to save image: " + _filenames[index]); + QMessageBox::information(0, "Test Aborted", "Failed to save file: " + _filenames[index]); _ui.progressBar->setVisible(false); return; } - ++_numberOfImagesDownloaded; + ++_numberOfFilesDownloaded; - if (_numberOfImagesDownloaded == _numberOfImagesToDownload) { - disconnect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveImage(int))); - _test->finishTestsEvaluation(_isRunningFromCommandline, _ui.checkBoxInteractiveMode->isChecked(), _ui.progressBar); + if (_numberOfFilesDownloaded == _numberOfFilesToDownload) { + disconnect(_signalMapper, SIGNAL(mapped(int)), this, SLOT(saveFile(int))); + if (_caller == _test) { + _test->finishTestsEvaluation(); + } else if (_caller == _testRunner) { + _testRunner->downloadComplete(); + } } else { - _ui.progressBar->setValue(_numberOfImagesDownloaded); + _ui.progressBar->setValue(_numberOfFilesDownloaded); } } void AutoTester::about() { - QMessageBox::information(0, "About", QString("Built ") + __DATE__ + " : " + __TIME__); + QMessageBox::information(0, "About", QString("Built ") + __DATE__ + ", " + __TIME__); } void AutoTester::content() { - helpWindow.show(); + _helpWindow.show(); } void AutoTester::setUserText(const QString& user) { - _ui.userTextEdit->setText(user); + _ui.userLineEdit->setText(user); } QString AutoTester::getSelectedUser() { - return _ui.userTextEdit->toPlainText(); + return _ui.userLineEdit->text(); } void AutoTester::setBranchText(const QString& branch) { - _ui.branchTextEdit->setText(branch); + _ui.branchLineEdit->setText(branch); } QString AutoTester::getSelectedBranch() { - return _ui.branchTextEdit->toPlainText(); + return _ui.branchLineEdit->text(); } + +void AutoTester::updateStatusLabel(const QString& status) { + _ui.statusLabel->setText(status); +} + +void AutoTester::appendLogWindow(const QString& message) { + _ui.plainTextEdit->appendPlainText(message); +} \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index e29da5b716..429a8b60e1 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -19,19 +19,28 @@ #include "../Test.h" #include "HelpWindow.h" +#include "../TestRunner.h" +#include "../AWSInterface.h" class AutoTester : public QMainWindow { Q_OBJECT public: - AutoTester(QWidget *parent = Q_NULLPTR); + AutoTester(QWidget* parent = Q_NULLPTR); + ~AutoTester(); void setup(); - void runFromCommandLine(const QString& testFolder, const QString& branch, const QString& user); + void startTestsEvaluation(const bool isRunningFromCommandLine, + const bool isRunningInAutomaticTestRun, + const QString& snapshotDirectory, + const QString& branch, + const QString& user); - void downloadImage(const QUrl& url); - void downloadImages(const QStringList& URLs, const QString& directoryName, const QStringList& filenames); + void automaticTestRunEvaluationComplete(QString zippedFolderName, int numberOfFailures); + + void downloadFile(const QUrl& url); + void downloadFiles(const QStringList& URLs, const QString& directoryName, const QStringList& filenames, void* caller); void setUserText(const QString& user); QString getSelectedUser(); @@ -39,21 +48,35 @@ public: void setBranchText(const QString& branch); QString getSelectedBranch(); + void enableRunTabControls(); + + void updateStatusLabel(const QString& status); + void appendLogWindow(const QString& message); + private slots: void on_tabWidget_currentChanged(int index); void on_evaluateTestsButton_clicked(); void on_createRecursiveScriptButton_clicked(); void on_createAllRecursiveScriptsButton_clicked(); - void on_createTestsButton_clicked(); + void on_createTestsButton_clicked(); void on_createMDFileButton_clicked(); void on_createAllMDFilesButton_clicked(); + void on_createTestAutoScriptButton_clicked(); + void on_createAllTestAutoScriptsButton_clicked(); + void on_createTestsOutlineButton_clicked(); void on_createTestRailTestCasesButton_clicked(); void on_createTestRailRunButton_clicked(); + + void on_setWorkingFolderButton_clicked(); + void on_runNowButton_clicked(); + + void on_checkBoxRunLatest_clicked(); + void on_updateTestRailRunResultsButton_clicked(); void on_hideTaskbarButton_clicked(); @@ -62,16 +85,21 @@ private slots: void on_createPythonScriptRadioButton_clicked(); void on_createXMLScriptRadioButton_clicked(); + void on_createWebPagePushButton_clicked(); + void on_closeButton_clicked(); - void saveImage(int index); + void saveFile(int index); void about(); void content(); private: Ui::AutoTesterClass _ui; - Test* _test; + Test* _test{ nullptr }; + TestRunner* _testRunner{ nullptr }; + + AWSInterface _awsInterface; std::vector _downloaders; @@ -82,13 +110,15 @@ private: // Used to enable passing a parameter to slots QSignalMapper* _signalMapper; - int _numberOfImagesToDownload { 0 }; - int _numberOfImagesDownloaded { 0 }; - int _index { 0 }; + int _numberOfFilesToDownload{ 0 }; + int _numberOfFilesDownloaded{ 0 }; + int _index{ 0 }; - bool _isRunningFromCommandline { false }; + bool _isRunningFromCommandline{ false }; - HelpWindow helpWindow; + HelpWindow _helpWindow; + + void* _caller; }; -#endif // hifi_AutoTester_h \ No newline at end of file +#endif // hifi_AutoTester_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index ac8fcf5e86..b277fbdb2a 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -6,8 +6,8 @@ 0 0 - 432 - 734 + 720 + 870 @@ -23,8 +23,8 @@ - 166 - 610 + 470 + 750 100 40 @@ -36,10 +36,10 @@ - 12 + 45 140 - 408 - 461 + 630 + 580 @@ -52,8 +52,8 @@ - 96 - 20 + 195 + 60 220 40 @@ -65,8 +65,8 @@ - 96 - 100 + 70 + 180 220 40 @@ -78,8 +78,8 @@ - 96 - 150 + 320 + 180 220 40 @@ -91,8 +91,8 @@ - 96 - 230 + 195 + 120 220 40 @@ -104,8 +104,8 @@ - 96 - 310 + 70 + 300 220 40 @@ -117,8 +117,8 @@ - 96 - 360 + 320 + 300 220 40 @@ -127,30 +127,436 @@ Create all Recursive Scripts + + + + 70 + 240 + 220 + 40 + + + + Create testAuto script + + + + + + 320 + 240 + 220 + 40 + + + + Create all testAuto scripts + + + + + + Windows + + + + + 200 + 130 + 211 + 40 + + + + Hide Windows Taskbar + + + + + + 200 + 200 + 211 + 40 + + + + Show Windows Taskbar + + + + + + Run + + + + false + + + + 10 + 160 + 161 + 28 + + + + Run now + + + + + false + + + + 20 + 240 + 91 + 241 + + + + Days + + + + + 10 + 210 + 80 + 17 + + + + Sunday + + + + + + 10 + 90 + 80 + 17 + + + + Wednesday + + + + + + 10 + 60 + 80 + 17 + + + + Tuesday + + + + + + 10 + 120 + 80 + 17 + + + + Thursday + + + + + + 10 + 150 + 80 + 17 + + + + Friday + + + + + + 10 + 180 + 80 + 17 + + + + Saturday + + + + + + 10 + 30 + 80 + 17 + + + + Monday + + + + + + false + + + + 130 + 240 + 161 + 191 + + + + Times + + + + + 30 + 20 + 118 + 22 + + + + + + + 30 + 60 + 118 + 22 + + + + + + + 30 + 100 + 118 + 22 + + + + + + + 30 + 140 + 118 + 22 + + + + + + + 10 + 23 + 21 + 17 + + + + + + + + + + 10 + 63 + 21 + 17 + + + + + + + + + + 10 + 103 + 21 + 17 + + + + + + + + + + 10 + 143 + 21 + 17 + + + + + + + + + + + 10 + 20 + 161 + 28 + + + + Set Working Folder + + + + + + 190 + 20 + 321 + 31 + + + + (not set...) + + + + + + 300 + 210 + 311 + 331 + + + + + + + 300 + 170 + 41 + 31 + + + + Status: + + + + + + 350 + 170 + 271 + 31 + + + + ####### + + + + + + 20 + 70 + 120 + 20 + + + + <html><head/><body><p>If unchecked, will not show results during evaluation</p></body></html> + + + Server-less + + + false + + + + + + 20 + 100 + 120 + 20 + + + + <html><head/><body><p>If unchecked, will not show results during evaluation</p></body></html> + + + Run Latest + + + true + + + + + + 128 + 95 + 21 + 31 + + + + URL + + + + + false + + + + 160 + 100 + 451 + 21 + + + Evaluate - - - - 90 - 100 - 255 - 23 - - - - 24 - - - 90 - 50 - 131 + 200 + 180 + 120 20 @@ -164,8 +570,8 @@ - 200 - 40 + 330 + 170 101 40 @@ -177,14 +583,14 @@ - TestRail + Web Interface - 180 - 160 - 161 + 240 + 220 + 160 40 @@ -195,8 +601,8 @@ - 80 - 40 + 170 + 100 95 20 @@ -211,9 +617,9 @@ - 180 - 100 - 161 + 240 + 160 + 160 40 @@ -224,9 +630,9 @@ - 180 - 40 - 161 + 240 + 100 + 160 40 @@ -237,8 +643,8 @@ - 80 - 60 + 170 + 120 95 20 @@ -247,45 +653,86 @@ XML - - - - Windows - - + - 100 - 100 - 211 - 40 + 10 + 30 + 601 + 300 - - Hide Windows Taskbar + + TestRail - + - 100 - 170 - 211 - 40 + 10 + 350 + 601 + 151 - - Show Windows Taskbar + + Amazon Web Services + + + true + + + + 240 + 30 + 160 + 40 + + + + Create Web Page + + + + + + 150 + 42 + 81 + 17 + + + + Update AWS + + + + + + 20 + 90 + 561 + 21 + + + + groupBox + updateTestRailRunResultsButton + createPythonScriptRadioButton + createTestRailRunButton + createTestRailTestCasesButton + createXMLScriptRadioButton + groupBox_2 - 110 - 90 - 81 + 120 + 80 + 110 16 @@ -298,32 +745,12 @@ GitHub Branch - - - - 200 - 85 - 140 - 24 - - - - - - - 200 - 47 - 140 - 24 - - - - 110 - 50 - 81 + 120 + 40 + 110 16 @@ -336,13 +763,46 @@ GitHub User + + + + 80 + 760 + 255 + 23 + + + + 24 + + + + + + 220 + 40 + 161 + 21 + + + + + + + 220 + 80 + 161 + 21 + + + 0 0 - 432 + 720 21 @@ -388,6 +848,53 @@ + + userLineEdit + branchLineEdit + createTestsButton + createMDFileButton + createAllMDFilesButton + createTestsOutlineButton + createRecursiveScriptButton + createAllRecursiveScriptsButton + createTestAutoScriptButton + createAllTestAutoScriptsButton + hideTaskbarButton + showTaskbarButton + runNowButton + sundayCheckBox + wednesdayCheckBox + tuesdayCheckBox + thursdayCheckBox + fridayCheckBox + saturdayCheckBox + mondayCheckBox + timeEdit1 + timeEdit2 + timeEdit3 + timeEdit4 + timeEdit1checkBox + timeEdit2checkBox + timeEdit3checkBox + timeEdit4checkBox + setWorkingFolderButton + plainTextEdit + checkBoxServerless + checkBoxRunLatest + urlLineEdit + checkBoxInteractiveMode + evaluateTestsButton + updateTestRailRunResultsButton + createPythonScriptRadioButton + createTestRailRunButton + createTestRailTestCasesButton + createXMLScriptRadioButton + createWebPagePushButton + updateAWSCheckBox + awsURLLineEdit + closeButton + tabWidget + diff --git a/tools/auto-tester/src/ui/MismatchWindow.cpp b/tools/auto-tester/src/ui/MismatchWindow.cpp index 79d2ce9f61..58189b4795 100644 --- a/tools/auto-tester/src/ui/MismatchWindow.cpp +++ b/tools/auto-tester/src/ui/MismatchWindow.cpp @@ -22,6 +22,11 @@ MismatchWindow::MismatchWindow(QWidget *parent) : QDialog(parent) { } QPixmap MismatchWindow::computeDiffPixmap(QImage expectedImage, QImage resultImage) { + // Create an empty difference image if the images differ in size + if (expectedImage.height() != resultImage.height() || expectedImage.width() != resultImage.width()) { + return QPixmap(); + } + // This is an optimization, as QImage.setPixel() is embarrassingly slow unsigned char* buffer = new unsigned char[expectedImage.height() * expectedImage.width() * 3]; @@ -55,20 +60,20 @@ QPixmap MismatchWindow::computeDiffPixmap(QImage expectedImage, QImage resultIma return resultPixmap; } -void MismatchWindow::setTestFailure(TestFailure testFailure) { - errorLabel->setText("Similarity: " + QString::number(testFailure._error)); +void MismatchWindow::setTestResult(TestResult testResult) { + errorLabel->setText("Similarity: " + QString::number(testResult._error)); - imagePath->setText("Path to test: " + testFailure._pathname); + imagePath->setText("Path to test: " + testResult._pathname); - expectedFilename->setText(testFailure._expectedImageFilename); - resultFilename->setText(testFailure._actualImageFilename); + expectedFilename->setText(testResult._expectedImageFilename); + resultFilename->setText(testResult._actualImageFilename); - QPixmap expectedPixmap = QPixmap(testFailure._pathname + testFailure._expectedImageFilename); - QPixmap actualPixmap = QPixmap(testFailure._pathname + testFailure._actualImageFilename); + QPixmap expectedPixmap = QPixmap(testResult._pathname + testResult._expectedImageFilename); + QPixmap actualPixmap = QPixmap(testResult._pathname + testResult._actualImageFilename); _diffPixmap = computeDiffPixmap( - QImage(testFailure._pathname + testFailure._expectedImageFilename), - QImage(testFailure._pathname + testFailure._actualImageFilename) + QImage(testResult._pathname + testResult._expectedImageFilename), + QImage(testResult._pathname + testResult._actualImageFilename) ); expectedImage->setPixmap(expectedPixmap); diff --git a/tools/auto-tester/src/ui/MismatchWindow.h b/tools/auto-tester/src/ui/MismatchWindow.h index f203a2be6a..30c29076b3 100644 --- a/tools/auto-tester/src/ui/MismatchWindow.h +++ b/tools/auto-tester/src/ui/MismatchWindow.h @@ -20,7 +20,7 @@ class MismatchWindow : public QDialog, public Ui::MismatchWindow { public: MismatchWindow(QWidget *parent = Q_NULLPTR); - void setTestFailure(TestFailure testFailure); + void setTestResult(TestResult testResult); UserResponse getUserResponse() { return _userResponse; } diff --git a/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp b/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp index 414e4fca79..505e04b33e 100644 --- a/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp +++ b/tools/auto-tester/src/ui/TestRailResultsSelectorWindow.cpp @@ -25,6 +25,7 @@ void TestRailResultsSelectorWindow::reset() { userLineEdit->setDisabled(false); passwordLineEdit->setDisabled(false); projectIDLineEdit->setDisabled(false); + suiteIDLineEdit->setDisabled(false); OKButton->setDisabled(true); @@ -37,6 +38,7 @@ void TestRailResultsSelectorWindow::on_acceptButton_clicked() { userLineEdit->setDisabled(true); passwordLineEdit->setDisabled(true); projectIDLineEdit->setDisabled(true); + suiteIDLineEdit->setDisabled(true); OKButton->setDisabled(false); diff --git a/tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp b/tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp index 54a3985a8b..ac3419d46f 100644 --- a/tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp +++ b/tools/auto-tester/src/ui/TestRailRunSelectorWindow.cpp @@ -19,12 +19,12 @@ TestRailRunSelectorWindow::TestRailRunSelectorWindow(QWidget *parent) { projectIDLineEdit->setValidator(new QIntValidator(1, 999, this)); } - void TestRailRunSelectorWindow::reset() { urlLineEdit->setDisabled(false); userLineEdit->setDisabled(false); passwordLineEdit->setDisabled(false); projectIDLineEdit->setDisabled(false); + suiteIDLineEdit->setDisabled(false); OKButton->setDisabled(true); sectionsComboBox->setDisabled(true); @@ -35,6 +35,7 @@ void TestRailRunSelectorWindow::on_acceptButton_clicked() { userLineEdit->setDisabled(true); passwordLineEdit->setDisabled(true); projectIDLineEdit->setDisabled(true); + suiteIDLineEdit->setDisabled(true); OKButton->setDisabled(false); sectionsComboBox->setDisabled(false); diff --git a/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp b/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp index abb873ea14..638fe71819 100644 --- a/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp +++ b/tools/auto-tester/src/ui/TestRailTestCasesSelectorWindow.cpp @@ -25,6 +25,7 @@ void TestRailTestCasesSelectorWindow::reset() { userLineEdit->setDisabled(false); passwordLineEdit->setDisabled(false); projectIDLineEdit->setDisabled(false); + suiteIDLineEdit->setDisabled(false); OKButton->setDisabled(true); @@ -37,6 +38,7 @@ void TestRailTestCasesSelectorWindow::on_acceptButton_clicked() { userLineEdit->setDisabled(true); passwordLineEdit->setDisabled(true); projectIDLineEdit->setDisabled(true); + suiteIDLineEdit->setDisabled(true); OKButton->setDisabled(false); diff --git a/unpublishedScripts/marketplace/record/record.js b/unpublishedScripts/marketplace/record/record.js index 8e49589e3c..4786356fee 100644 --- a/unpublishedScripts/marketplace/record/record.js +++ b/unpublishedScripts/marketplace/record/record.js @@ -395,7 +395,7 @@ Script.clearInterval(updateTimer); Messages.messageReceived.disconnect(onMessageReceived); - Messages.subscribe(HIFI_RECORDER_CHANNEL); + Messages.unsubscribe(HIFI_RECORDER_CHANNEL); } return { diff --git a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml index 033039b87d..753771987a 100644 --- a/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml +++ b/unpublishedScripts/marketplace/spectator-camera/SpectatorCamera.qml @@ -16,8 +16,8 @@ import QtQuick 2.7 import QtQuick.Controls 2.2 import QtGraphicalEffects 1.0 -import "qrc:////qml//styles-uit" as HifiStylesUit -import "qrc:////qml//controls-uit" as HifiControlsUit +import stylesUit 1.0 as HifiStylesUit +import controlsUit 1.0 as HifiControlsUit import "qrc:////qml//controls" as HifiControls import "qrc:////qml//hifi" as Hifi