diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000000..f000a27017 --- /dev/null +++ b/.clang-format @@ -0,0 +1,39 @@ +Language: Cpp +Standard: Cpp11 +BasedOnStyle: "Chromium" +ColumnLimit: 128 +IndentWidth: 4 +UseTab: Never + +BreakBeforeBraces: Custom +BraceWrapping: + AfterEnum: true + AfterClass: false + AfterControlStatement: false + AfterFunction: false + AfterNamespace: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + SplitEmptyFunction: false + SplitEmptyNamespace: true + + +AccessModifierOffset: -4 +AllowShortFunctionsOnASingleLine: InlineOnly +BreakConstructorInitializers: BeforeColon +BreakConstructorInitializersBeforeComma: true +IndentCaseLabels: true +ReflowComments: false +Cpp11BracedListStyle: false +ContinuationIndentWidth: 4 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +CompactNamespaces: true +SortIncludes: false +SpaceBeforeAssignmentOperators: true +SpaceBeforeParens: ControlStatements + +PenaltyReturnTypeOnItsOwnLine: 1000 +PenaltyBreakBeforeFirstCallParameter: 1000 + diff --git a/cmake/macros/AutoScribeShader.cmake b/cmake/macros/AutoScribeShader.cmake index c5b35b7e90..1919ecf00a 100755 --- a/cmake/macros/AutoScribeShader.cmake +++ b/cmake/macros/AutoScribeShader.cmake @@ -118,6 +118,7 @@ macro(AUTOSCRIBE_SHADER_LIB) foreach(SHADER_FILE ${SHADER_SOURCE_FILES}) AUTOSCRIBE_SHADER(${SHADER_FILE} ${SHADER_INCLUDE_FILES}) file(TO_CMAKE_PATH "${AUTOSCRIBE_SHADER_RETURN}" AUTOSCRIBE_GENERATED_FILE) + set_property(SOURCE ${AUTOSCRIBE_GENERATED_FILE} PROPERTY SKIP_AUTOMOC ON) list(APPEND AUTOSCRIBE_SHADER_SRC ${AUTOSCRIBE_GENERATED_FILE}) endforeach() #message(${TARGET_NAME} ${AUTOSCRIBE_SHADER_SRC}) diff --git a/cmake/macros/SetupQt.cmake b/cmake/macros/SetupQt.cmake index bbdce06f37..ac67e12044 100644 --- a/cmake/macros/SetupQt.cmake +++ b/cmake/macros/SetupQt.cmake @@ -7,10 +7,12 @@ # function(set_from_env _RESULT_NAME _ENV_VAR_NAME _DEFAULT_VALUE) - if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "") - set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE) - else() - set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE) + if (NOT DEFINED ${_RESULT_NAME}) + if ("$ENV{${_ENV_VAR_NAME}}" STREQUAL "") + set (${_RESULT_NAME} ${_DEFAULT_VALUE} PARENT_SCOPE) + else() + set (${_RESULT_NAME} $ENV{${_ENV_VAR_NAME}} PARENT_SCOPE) + endif() endif() endfunction() diff --git a/interface/resources/html/raiseAndLowerKeyboard.js b/interface/resources/html/raiseAndLowerKeyboard.js index ad1d889556..2535416fd8 100644 --- a/interface/resources/html/raiseAndLowerKeyboard.js +++ b/interface/resources/html/raiseAndLowerKeyboard.js @@ -18,7 +18,7 @@ function shouldRaiseKeyboard() { var nodeName = document.activeElement.nodeName; var nodeType = document.activeElement.type; - if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url"].indexOf(nodeType) !== -1 + if (nodeName === "INPUT" && ["email", "number", "password", "tel", "text", "url", "search"].indexOf(nodeType) !== -1 || document.activeElement.nodeName === "TEXTAREA") { return true; } else { diff --git a/interface/resources/qml/controls-uit/Keyboard.qml b/interface/resources/qml/controls-uit/Keyboard.qml index f2ccb6973f..8d6634c9b4 100644 --- a/interface/resources/qml/controls-uit/Keyboard.qml +++ b/interface/resources/qml/controls-uit/Keyboard.qml @@ -13,6 +13,7 @@ import "." Rectangle { id: keyboardBase + objectName: "keyboard" anchors.left: parent.left anchors.right: parent.right @@ -27,6 +28,8 @@ Rectangle { readonly property int mirrorTextHeight: keyboardRowHeight + property bool password: false + property alias mirroredText: mirrorText.text property bool showMirrorText: true readonly property int raisedHeight: 200 @@ -112,16 +115,20 @@ Rectangle { color: "#252525" anchors.horizontalCenter: parent.horizontalCenter - TextEdit { + TextInput { id: mirrorText visible: showMirrorText - size: 13.5 + FontLoader { id: ralewaySemiBold; source: "../../fonts/Raleway-SemiBold.ttf"; } + font.family: ralewaySemiBold.name + font.pointSize: 13.5 + verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter color: "#FFFFFF"; anchors.fill: parent wrapMode: Text.WordWrap - readOnly: false // we need to leave this property read-only to allow control to accept QKeyEvent + readOnly: false // we need this to allow control to accept QKeyEvent selectByMouse: false + echoMode: password ? TextInput.Password : TextInput.Normal Keys.onPressed: { if (event.key == Qt.Key_Return || event.key == Qt.Key_Space) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 26e659e118..013e5c90a6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -212,6 +212,17 @@ #if defined(Q_OS_WIN) #include +#ifdef DEBUG_EVENT_QUEUE +// This is a HACK that uses private headers included with the qt source distrubution. +// To use this feature you need to add these directores to your include path: +// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1/QtCore +// E:/Qt/5.9.1/Src/qtbase/include/QtCore/5.9.1 +#define QT_BOOTSTRAPPED +#include +#include +#undef QT_BOOTSTRAPPED +#endif + extern "C" { _declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; } @@ -269,9 +280,7 @@ private: switch ((int)event->type()) { case ApplicationEvent::Render: render(); - // Ensure we never back up the render events. Each render should be triggered only in response - // to the NEXT render event after the last render occured - QCoreApplication::removePostedEvents(this, ApplicationEvent::Render); + qApp->_pendingRenderEvent.store(false); return true; default: @@ -2725,9 +2734,14 @@ bool Application::importFromZIP(const QString& filePath) { return true; } +// thread-safe void Application::onPresent(quint32 frameCount) { - postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); - if (_renderEventHandler && !isAboutToQuit()) { + bool expected = false; + if (_pendingIdleEvent.compare_exchange_strong(expected, true)) { + postEvent(this, new QEvent((QEvent::Type)ApplicationEvent::Idle), Qt::HighEventPriority); + } + expected = false; + if (_renderEventHandler && !isAboutToQuit() && _pendingRenderEvent.compare_exchange_strong(expected, true)) { postEvent(_renderEventHandler, new QEvent((QEvent::Type)ApplicationEvent::Render)); } } @@ -2794,7 +2808,26 @@ bool Application::handleFileOpenEvent(QFileOpenEvent* fileEvent) { return false; } +#ifdef DEBUG_EVENT_QUEUE +static int getEventQueueSize(QThread* thread) { + auto threadData = QThreadData::get2(thread); + QMutexLocker locker(&threadData->postEventList.mutex); + return threadData->postEventList.size(); +} + +static void dumpEventQueue(QThread* thread) { + auto threadData = QThreadData::get2(thread); + QMutexLocker locker(&threadData->postEventList.mutex); + qDebug() << "AJT: event list, size =" << threadData->postEventList.size(); + for (auto& postEvent : threadData->postEventList) { + QEvent::Type type = (postEvent.event ? postEvent.event->type() : QEvent::None); + qDebug() << "AJT: " << type; + } +} +#endif // DEBUG_EVENT_QUEUE + bool Application::event(QEvent* event) { + if (!Menu::getInstance()) { return false; } @@ -2814,8 +2847,18 @@ bool Application::event(QEvent* event) { // see (windowMinimizedChanged) case ApplicationEvent::Idle: idle(); - // Don't process extra idle events that arrived in the event queue while we were doing this idle - QCoreApplication::removePostedEvents(this, ApplicationEvent::Idle); + +#ifdef DEBUG_EVENT_QUEUE + { + int count = getEventQueueSize(QThread::currentThread()); + if (count > 400) { + dumpEventQueue(QThread::currentThread()); + } + } +#endif // DEBUG_EVENT_QUEUE + + _pendingIdleEvent.store(false); + return true; case QEvent::MouseMove: @@ -7218,7 +7261,7 @@ void Application::updateDisplayMode() { _offscreenContext->makeCurrent(); getApplicationCompositor().setDisplayPlugin(newDisplayPlugin); _displayPlugin = newDisplayPlugin; - connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent); + connect(_displayPlugin.get(), &DisplayPlugin::presented, this, &Application::onPresent, Qt::DirectConnection); auto desktop = offscreenUi->getDesktop(); if (desktop) { desktop->setProperty("repositionLocked", wasRepositionLocked); diff --git a/interface/src/Application.h b/interface/src/Application.h index 7075745a39..93a8abe6a1 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -708,5 +708,8 @@ private: QObject* _renderEventHandler{ nullptr }; friend class RenderEventHandler; + + std::atomic _pendingIdleEvent { false }; + std::atomic _pendingRenderEvent { false }; }; #endif // hifi_Application_h diff --git a/interface/src/Application_render.cpp b/interface/src/Application_render.cpp index 541197a660..44d9dfee03 100644 --- a/interface/src/Application_render.cpp +++ b/interface/src/Application_render.cpp @@ -72,6 +72,12 @@ void Application::paintGL() { { QMutexLocker viewLocker(&_renderArgsMutex); renderArgs = _appRenderArgs._renderArgs; + + // don't render if there is no context. + if (!_appRenderArgs._renderArgs._context) { + return; + } + HMDSensorPose = _appRenderArgs._headPose; eyeToWorld = _appRenderArgs._eyeToWorld; sensorToWorld = _appRenderArgs._sensorToWorld; diff --git a/interface/src/raypick/LaserPointer.cpp b/interface/src/raypick/LaserPointer.cpp index 3100a18dde..32c67be884 100644 --- a/interface/src/raypick/LaserPointer.cpp +++ b/interface/src/raypick/LaserPointer.cpp @@ -15,17 +15,18 @@ #include #include -#include "RayPickScriptingInterface.h" +#include "PickScriptingInterface.h" LaserPointer::LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled) : - Pointer(DependencyManager::get()->createRayPick(rayProps)), + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled) : + Pointer(DependencyManager::get()->createRayPick(rayProps)), _renderingEnabled(enabled), _renderStates(renderStates), _defaultRenderStates(defaultRenderStates), _faceAvatar(faceAvatar), _centerEndY(centerEndY), - _lockEnd(lockEnd) + _lockEnd(lockEnd), + _distanceScaleEnd(distanceScaleEnd) { for (auto& state : _renderStates) { if (!enabled || state.first != _currentRenderState) { @@ -89,6 +90,10 @@ void LaserPointer::editRenderState(const std::string& state, const QVariant& sta updateRenderStateOverlay(_renderStates[state].getStartID(), startProps); updateRenderStateOverlay(_renderStates[state].getPathID(), pathProps); updateRenderStateOverlay(_renderStates[state].getEndID(), endProps); + QVariant endDim = endProps.toMap()["dimensions"]; + if (endDim.isValid()) { + _renderStates[state].setEndDim(vec3FromVariant(endDim)); + } }); } @@ -153,10 +158,14 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter if (!renderState.getEndID().isNull()) { QVariantMap endProps; glm::quat faceAvatarRotation = DependencyManager::get()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))); + glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); + if (_distanceScaleEnd) { + dim = renderState.getEndDim() * glm::distance(pickRay.origin, endVec) * DependencyManager::get()->getMyAvatar()->getSensorToWorldScale(); + endProps.insert("dimensions", vec3toVariant(dim)); + } if (_centerEndY) { endProps.insert("position", end); } else { - glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value); glm::vec3 currentUpVector = faceAvatarRotation * Vectors::UP; endProps.insert("position", vec3toVariant(endVec + glm::vec3(currentUpVector.x * 0.5f * dim.y, currentUpVector.y * 0.5f * dim.y, currentUpVector.z * 0.5f * dim.y))); } @@ -234,6 +243,7 @@ RenderState::RenderState(const OverlayID& startID, const OverlayID& pathID, cons _pathIgnoreRays = qApp->getOverlays().getProperty(_pathID, "ignoreRayIntersection").value.toBool(); } if (!_endID.isNull()) { + _endDim = vec3FromVariant(qApp->getOverlays().getProperty(_endID, "dimensions").value); _endIgnoreRays = qApp->getOverlays().getProperty(_endID, "ignoreRayIntersection").value.toBool(); } } @@ -249,3 +259,35 @@ void RenderState::deleteOverlays() { qApp->getOverlays().deleteOverlay(_endID); } } + +RenderState LaserPointer::buildRenderState(const QVariantMap& propMap) { + QUuid startID; + if (propMap["start"].isValid()) { + QVariantMap startMap = propMap["start"].toMap(); + if (startMap["type"].isValid()) { + startMap.remove("visible"); + startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); + } + } + + QUuid pathID; + if (propMap["path"].isValid()) { + QVariantMap pathMap = propMap["path"].toMap(); + // right now paths must be line3ds + if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { + pathMap.remove("visible"); + pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); + } + } + + QUuid endID; + if (propMap["end"].isValid()) { + QVariantMap endMap = propMap["end"].toMap(); + if (endMap["type"].isValid()) { + endMap.remove("visible"); + endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); + } + } + + return RenderState(startID, pathID, endID); +} \ No newline at end of file diff --git a/interface/src/raypick/LaserPointer.h b/interface/src/raypick/LaserPointer.h index a0fd1b2417..dd1ee6de57 100644 --- a/interface/src/raypick/LaserPointer.h +++ b/interface/src/raypick/LaserPointer.h @@ -32,6 +32,9 @@ public: const bool& doesPathIgnoreRays() const { return _pathIgnoreRays; } const bool& doesEndIgnoreRays() const { return _endIgnoreRays; } + void setEndDim(const glm::vec3& endDim) { _endDim = endDim; } + const glm::vec3& getEndDim() const { return _endDim; } + void deleteOverlays(); private: @@ -41,6 +44,8 @@ private: bool _startIgnoreRays; bool _pathIgnoreRays; bool _endIgnoreRays; + + glm::vec3 _endDim; }; class LaserPointer : public Pointer { @@ -50,7 +55,7 @@ public: typedef std::unordered_map> DefaultRenderStateMap; LaserPointer(const QVariant& rayProps, const RenderStateMap& renderStates, const DefaultRenderStateMap& defaultRenderStates, - const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool enabled); + const bool faceAvatar, const bool centerEndY, const bool lockEnd, const bool distanceScaleEnd, const bool enabled); ~LaserPointer(); void enable() override; @@ -65,6 +70,8 @@ public: void update() override; + static RenderState buildRenderState(const QVariantMap& propMap); + private: bool _renderingEnabled; float _laserLength { 0.0f }; @@ -74,6 +81,7 @@ private: bool _faceAvatar; bool _centerEndY; bool _lockEnd; + bool _distanceScaleEnd; std::pair _objectLockEnd { std::pair(QUuid(), false)}; void updateRenderStateOverlay(const OverlayID& id, const QVariant& props); diff --git a/interface/src/raypick/LaserPointerScriptingInterface.cpp b/interface/src/raypick/LaserPointerScriptingInterface.cpp index 8f8f9d921a..533dffafb9 100644 --- a/interface/src/raypick/LaserPointerScriptingInterface.cpp +++ b/interface/src/raypick/LaserPointerScriptingInterface.cpp @@ -11,12 +11,8 @@ #include "LaserPointerScriptingInterface.h" -#include - -#include - +#include "RegisteredMetaTypes.h" #include "PointerScriptingInterface.h" -#include "Application.h" void LaserPointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); diff --git a/interface/src/raypick/PointerScriptingInterface.cpp b/interface/src/raypick/PointerScriptingInterface.cpp index 4e5d5f414f..8a87721ad9 100644 --- a/interface/src/raypick/PointerScriptingInterface.cpp +++ b/interface/src/raypick/PointerScriptingInterface.cpp @@ -9,10 +9,10 @@ #include "PointerScriptingInterface.h" #include - #include #include "Application.h" +#include "LaserPointer.h" void PointerScriptingInterface::setIgnoreItems(const QUuid& uid, const QScriptValue& ignoreItems) const { DependencyManager::get()->setIgnoreItems(uid, qVectorQUuidFromScriptValue(ignoreItems)); @@ -48,6 +48,11 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) lockEnd = propertyMap["lockEnd"].toBool(); } + bool distanceScaleEnd = false; + if (propertyMap["distanceScaleEnd"].isValid()) { + distanceScaleEnd = propertyMap["distanceScaleEnd"].toBool(); + } + bool enabled = false; if (propertyMap["enabled"].isValid()) { enabled = propertyMap["enabled"].toBool(); @@ -61,7 +66,7 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) QVariantMap renderStateMap = renderStateVariant.toMap(); if (renderStateMap["name"].isValid()) { std::string name = renderStateMap["name"].toString().toStdString(); - renderStates[name] = buildRenderState(renderStateMap); + renderStates[name] = LaserPointer::buildRenderState(renderStateMap); } } } @@ -76,13 +81,13 @@ QUuid PointerScriptingInterface::createLaserPointer(const QVariant& properties) if (renderStateMap["name"].isValid() && renderStateMap["distance"].isValid()) { std::string name = renderStateMap["name"].toString().toStdString(); float distance = renderStateMap["distance"].toFloat(); - defaultRenderStates[name] = std::pair(distance, buildRenderState(renderStateMap)); + defaultRenderStates[name] = std::pair(distance, LaserPointer::buildRenderState(renderStateMap)); } } } } - return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, enabled)); + return DependencyManager::get()->addPointer(std::make_shared(properties, renderStates, defaultRenderStates, faceAvatar, centerEndY, lockEnd, distanceScaleEnd, enabled)); } void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& renderState, const QVariant& properties) const { @@ -104,36 +109,4 @@ void PointerScriptingInterface::editRenderState(const QUuid& uid, const QString& } DependencyManager::get()->editRenderState(uid, renderState.toStdString(), startProps, pathProps, endProps); -} - -RenderState PointerScriptingInterface::buildRenderState(const QVariantMap& propMap) { - QUuid startID; - if (propMap["start"].isValid()) { - QVariantMap startMap = propMap["start"].toMap(); - if (startMap["type"].isValid()) { - startMap.remove("visible"); - startID = qApp->getOverlays().addOverlay(startMap["type"].toString(), startMap); - } - } - - QUuid pathID; - if (propMap["path"].isValid()) { - QVariantMap pathMap = propMap["path"].toMap(); - // right now paths must be line3ds - if (pathMap["type"].isValid() && pathMap["type"].toString() == "line3d") { - pathMap.remove("visible"); - pathID = qApp->getOverlays().addOverlay(pathMap["type"].toString(), pathMap); - } - } - - QUuid endID; - if (propMap["end"].isValid()) { - QVariantMap endMap = propMap["end"].toMap(); - if (endMap["type"].isValid()) { - endMap.remove("visible"); - endID = qApp->getOverlays().addOverlay(endMap["type"].toString(), endMap); - } - } - - return RenderState(startID, pathID, endID); } \ No newline at end of file diff --git a/interface/src/raypick/PointerScriptingInterface.h b/interface/src/raypick/PointerScriptingInterface.h index 8a3a316d9e..de45826d48 100644 --- a/interface/src/raypick/PointerScriptingInterface.h +++ b/interface/src/raypick/PointerScriptingInterface.h @@ -12,8 +12,7 @@ #include "DependencyManager.h" #include - -#include "LaserPointer.h" +#include class PointerScriptingInterface : public QObject, public Dependency { Q_OBJECT @@ -38,9 +37,6 @@ public slots: Q_INVOKABLE void setLockEndUUID(const QUuid& uid, const QUuid& objectID, bool isOverlay) const { DependencyManager::get()->setLockEndUUID(uid, objectID, isOverlay); } -private: - static RenderState buildRenderState(const QVariantMap& propMap); - }; #endif // hifi_PointerScriptingInterface_h diff --git a/interface/src/raypick/RayPickScriptingInterface.cpp b/interface/src/raypick/RayPickScriptingInterface.cpp index 92bf3ec521..b89f89aab5 100644 --- a/interface/src/raypick/RayPickScriptingInterface.cpp +++ b/interface/src/raypick/RayPickScriptingInterface.cpp @@ -14,6 +14,7 @@ #include #include "GLMHelpers.h" +#include "PickScriptingInterface.h" #include #include "StaticRayPick.h" diff --git a/interface/src/raypick/RayPickScriptingInterface.h b/interface/src/raypick/RayPickScriptingInterface.h index ed837afe49..e7c5dfd5dd 100644 --- a/interface/src/raypick/RayPickScriptingInterface.h +++ b/interface/src/raypick/RayPickScriptingInterface.h @@ -13,11 +13,8 @@ #include -#include +#include "RegisteredMetaTypes.h" #include -#include "RayPick.h" - -#include "PickScriptingInterface.h" class RayPickScriptingInterface : public QObject, public Dependency { Q_OBJECT diff --git a/libraries/audio/src/AudioDynamics.h b/libraries/audio/src/AudioDynamics.h index b7c168bfab..6f36605025 100644 --- a/libraries/audio/src/AudioDynamics.h +++ b/libraries/audio/src/AudioDynamics.h @@ -135,6 +135,7 @@ static const int32_t exp2Table[1 << EXP2_TABBITS][3] = { static const int IEEE754_FABS_MASK = 0x7fffffff; static const int IEEE754_MANT_BITS = 23; +static const int IEEE754_EXPN_BITS = 8; static const int IEEE754_EXPN_BIAS = 127; // @@ -152,7 +153,7 @@ static inline int32_t peaklog2(float* input) { // split into e and x - 1.0 int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; - int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; + int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate if (e > 31) { @@ -191,7 +192,7 @@ static inline int32_t peaklog2(float* input0, float* input1) { // split into e and x - 1.0 int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; - int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; + int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate if (e > 31) { @@ -234,7 +235,7 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa // split into e and x - 1.0 int32_t e = IEEE754_EXPN_BIAS - (peak >> IEEE754_MANT_BITS) + LOG2_HEADROOM; - int32_t x = (peak << (31 - IEEE754_MANT_BITS)) & 0x7fffffff; + int32_t x = (peak << IEEE754_EXPN_BITS) & 0x7fffffff; // saturate if (e > 31) { @@ -259,30 +260,30 @@ static inline int32_t peaklog2(float* input0, float* input1, float* input2, floa // Count Leading Zeros // Emulates the CLZ (ARM) and LZCNT (x86) instruction // -static inline int CLZ(uint32_t x) { +static inline int CLZ(uint32_t u) { - if (x == 0) { + if (u == 0) { return 32; } int e = 0; - if (x < 0x00010000) { - x <<= 16; + if (u < 0x00010000) { + u <<= 16; e += 16; } - if (x < 0x01000000) { - x <<= 8; + if (u < 0x01000000) { + u <<= 8; e += 8; } - if (x < 0x10000000) { - x <<= 4; + if (u < 0x10000000) { + u <<= 4; e += 4; } - if (x < 0x40000000) { - x <<= 2; + if (u < 0x40000000) { + u <<= 2; e += 2; } - if (x < 0x80000000) { + if (u < 0x80000000) { e += 1; } return e; @@ -290,19 +291,19 @@ static inline int CLZ(uint32_t x) { // // Compute -log2(x) for x=[0,1] in Q31, result in Q26 -// x = 0 returns 0x7fffffff -// x < 0 undefined +// x <= 0 returns 0x7fffffff // static inline int32_t fixlog2(int32_t x) { - if (x == 0) { + if (x <= 0) { return 0x7fffffff; } // split into e and x - 1.0 - int e = CLZ((uint32_t)x); - x <<= e; // normalize to [0x80000000, 0xffffffff] - x &= 0x7fffffff; // x - 1.0 + uint32_t u = (uint32_t)x; + int e = CLZ(u); + u <<= e; // normalize to [0x80000000, 0xffffffff] + x = u & 0x7fffffff; // x - 1.0 int k = x >> (31 - LOG2_TABBITS); @@ -320,13 +321,18 @@ static inline int32_t fixlog2(int32_t x) { // // Compute exp2(-x) for x=[0,32] in Q26, result in Q31 -// x < 0 undefined +// x <= 0 returns 0x7fffffff // static inline int32_t fixexp2(int32_t x) { + if (x <= 0) { + return 0x7fffffff; + } + // split into e and 1.0 - x - int e = x >> LOG2_FRACBITS; - x = ~(x << LOG2_INTBITS) & 0x7fffffff; + uint32_t u = (uint32_t)x; + int e = u >> LOG2_FRACBITS; + x = ~(u << LOG2_INTBITS) & 0x7fffffff; int k = x >> (31 - EXP2_TABBITS); diff --git a/libraries/audio/src/AudioGate.cpp b/libraries/audio/src/AudioGate.cpp index 13c794b923..5ef5ee25b5 100644 --- a/libraries/audio/src/AudioGate.cpp +++ b/libraries/audio/src/AudioGate.cpp @@ -40,7 +40,7 @@ class MonoDCBlock { public: void process(int32_t& x) { - x <<= 15; // scale to Q30 + x *= (1 << 15); // scale to Q30 x -= _dcOffset; // remove DC _dcOffset += x >> 13; // pole = (1.0 - 2^-13) = 0.9999 } @@ -53,8 +53,8 @@ class StereoDCBlock { public: void process(int32_t& x0, int32_t& x1) { - x0 <<= 15; - x1 <<= 15; + x0 *= (1 << 15); + x1 *= (1 << 15); x0 -= _dcOffset[0]; x1 -= _dcOffset[1]; @@ -71,10 +71,10 @@ class QuadDCBlock { public: void process(int32_t& x0, int32_t& x1, int32_t& x2, int32_t& x3) { - x0 <<= 15; - x1 <<= 15; - x2 <<= 15; - x3 <<= 15; + x0 *= (1 << 15); + x1 *= (1 << 15); + x2 *= (1 << 15); + x3 *= (1 << 15); x0 -= _dcOffset[0]; x1 -= _dcOffset[1]; @@ -100,10 +100,10 @@ protected: int _histogram[NHIST] = {}; // peakhold - int32_t _holdMin = 0x7fffffff; - int32_t _holdInc = 0x7fffffff; + uint32_t _holdMin = 0x7fffffff; + uint32_t _holdInc = 0x7fffffff; uint32_t _holdMax = 0x7fffffff; - int32_t _holdRel = 0x7fffffff; + uint32_t _holdRel = 0x7fffffff; int32_t _holdPeak = 0x7fffffff; // hysteresis @@ -177,18 +177,23 @@ void GateImpl::setThreshold(float threshold) { void GateImpl::setHold(float hold) { const double RELEASE = 100.0; // release = 100ms - const double PROGHOLD = 0.100; // progressive hold = 100ms + const double PROGHOLD = 100.0; // progressive hold = 100ms // pure hold = 1 to 1000ms hold = MAX(hold, 1.0f); hold = MIN(hold, 1000.0f); + // compute final tc _holdMin = msToTc(RELEASE, _sampleRate); - _holdInc = (int32_t)((_holdMin - 0x7fffffff) / (PROGHOLD * _sampleRate)); - _holdInc = MIN(_holdInc, -1); // prevent 0 on long releases - - _holdMax = 0x7fffffff - (uint32_t)(_holdInc * (double)hold/1000.0 * _sampleRate); + // compute tc increment, to progress from 0x7fffffff to _holdMin in PROGHOLD ms + double progSamples = PROGHOLD/1000.0 * _sampleRate; + _holdInc = (uint32_t)((0x7fffffff - _holdMin) / progSamples); + _holdInc = MAX(_holdInc, 1); // prevent 0 on long releases + + // compute initial tc, to progress from _holdMax to 0x7fffffff in hold ms + double holdSamples = (double)hold/1000.0 * _sampleRate; + _holdMax = 0x7fffffff + (uint32_t)(_holdInc * holdSamples); } // @@ -318,8 +323,6 @@ void GateImpl::processHistogram(int numFrames) { // smooth threshold update _threshAdapt = threshold + MULQ31((_threshAdapt - threshold), tcThreshold); - - //printf("threshold = %0.1f\n", (_threshAdapt - (LOG2_HEADROOM_Q15 << LOG2_FRACBITS)) * -6.02f / (1 << LOG2_FRACBITS)); } // @@ -336,10 +339,8 @@ int32_t GateImpl::peakhold(int32_t peak) { // (_holdRel > _holdMin) progressive hold // (_holdRel = _holdMin) release - _holdRel += _holdInc; // update progressive hold - _holdRel = MAX((uint32_t)_holdRel, (uint32_t)_holdMin); // saturate at final value - - int32_t tc = MIN((uint32_t)_holdRel, 0x7fffffff); + _holdRel -= _holdInc; // update progressive hold + int32_t tc = MIN(MAX(_holdRel, _holdMin), 0x7fffffff); // saturate to [_holdMin, 0x7fffffff] peak += MULQ31((_holdPeak - peak), tc); // apply release } else { diff --git a/libraries/audio/src/InboundAudioStream.cpp b/libraries/audio/src/InboundAudioStream.cpp index da8997895c..72acc7fcf6 100644 --- a/libraries/audio/src/InboundAudioStream.cpp +++ b/libraries/audio/src/InboundAudioStream.cpp @@ -46,6 +46,10 @@ static const int STATS_FOR_STATS_PACKET_WINDOW_SECONDS = 30; // _currentJitterBufferFrames is updated with the time-weighted avg and the running time-weighted avg is reset. static const quint64 FRAMES_AVAILABLE_STAT_WINDOW_USECS = 10 * USECS_PER_SECOND; +// When the audio codec is switched, temporary codec mismatch is expected due to packets in-flight. +// A SelectedAudioFormat packet is not sent until this threshold is exceeded. +static const int MAX_MISMATCHED_AUDIO_CODEC_COUNT = 10; + InboundAudioStream::InboundAudioStream(int numChannels, int numFrames, int numBlocks, int numStaticJitterBlocks) : _ringBuffer(numChannels * numFrames, numBlocks), _numChannels(numChannels), @@ -153,6 +157,7 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { // If we recieved a SilentAudioFrame from our sender, we might want to drop // some of the samples in order to catch up to our desired jitter buffer size. writeDroppableSilentFrames(networkFrames); + } else { // note: PCM and no codec are identical bool selectedPCM = _selectedCodecName == "pcm" || _selectedCodecName == ""; @@ -160,20 +165,33 @@ int InboundAudioStream::parseData(ReceivedMessage& message) { if (codecInPacket == _selectedCodecName || (packetPCM && selectedPCM)) { auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); parseAudioData(message.getType(), afterProperties); + _mismatchedAudioCodecCount = 0; + } else { - qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket << "writing silence"; + _mismatchedAudioCodecCount++; + qDebug(audio) << "Codec mismatch: expected" << _selectedCodecName << "got" << codecInPacket; - // Since the data in the stream is using a codec that we aren't prepared for, - // we need to let the codec know that we don't have data for it, this will - // allow the codec to interpolate missing data and produce a fade to silence. - lostAudioData(1); - - // inform others of the mismatch - auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); - if (sendingNode) { - emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); + if (packetPCM) { + // If there are PCM packets in-flight after the codec is changed, use them. + auto afterProperties = message.readWithoutCopy(message.getBytesLeftToRead()); + _ringBuffer.writeData(afterProperties.data(), afterProperties.size()); + } else { + // Since the data in the stream is using a codec that we aren't prepared for, + // we need to let the codec know that we don't have data for it, this will + // allow the codec to interpolate missing data and produce a fade to silence. + lostAudioData(1); } + if (_mismatchedAudioCodecCount > MAX_MISMATCHED_AUDIO_CODEC_COUNT) { + _mismatchedAudioCodecCount = 0; + + // inform others of the mismatch + auto sendingNode = DependencyManager::get()->nodeWithUUID(message.getSourceID()); + if (sendingNode) { + emit mismatchedAudioCodec(sendingNode, _selectedCodecName, codecInPacket); + qDebug(audio) << "Codec mismatch threshold exceeded, SelectedAudioFormat(" << _selectedCodecName << " ) sent"; + } + } } } break; diff --git a/libraries/audio/src/InboundAudioStream.h b/libraries/audio/src/InboundAudioStream.h index 9494b2f204..ecd1a118f9 100644 --- a/libraries/audio/src/InboundAudioStream.h +++ b/libraries/audio/src/InboundAudioStream.h @@ -186,6 +186,7 @@ protected: CodecPluginPointer _codec; QString _selectedCodecName; Decoder* _decoder { nullptr }; + int _mismatchedAudioCodecCount { 0 }; }; float calculateRepeatedFrameFadeFactor(int indexOfRepeat); diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 59ec4776a6..5959714cd8 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -983,6 +983,9 @@ public: glm::vec2 dstCoord; glm::ivec2 srcPixel; for (int y = 0; y < faceWidth; ++y) { + QRgb* destScanLineBegin = reinterpret_cast( image.scanLine(y) ); + QRgb* destPixelIterator = destScanLineBegin; + dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom for (int x = 0; x < faceWidth; ++x) { dstCoord.x = (x + 0.5f) * dstInvSize.x; @@ -995,13 +998,19 @@ public: srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight); if (((uint32)srcPixel.x < (uint32)source.width()) && ((uint32)srcPixel.y < (uint32)source.height())) { - image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y))); + // We can't directly use the pixel() method because that launches a pixel color conversion to output + // a correct RGBA8 color. But in our case we may have stored HDR values encoded in a RGB30 format which + // are not convertible by Qt. The same goes with the setPixel method, by the way. + const QRgb* sourcePixelIterator = reinterpret_cast(source.scanLine(srcPixel.y)); + sourcePixelIterator += srcPixel.x; + *destPixelIterator = *sourcePixelIterator; // Keep for debug, this is showing the dir as a color // glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256); // unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16); - // image.setPixel(x, y, val); + // *destPixelIterator = val; } + ++destPixelIterator; } } return image; @@ -1192,6 +1201,10 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& if ((srcImage.width() > 0) && (srcImage.height() > 0)) { QImage image = processSourceImage(srcImage, true); + if (image.format() != QIMAGE_HDR_FORMAT) { + image = convertToHDRFormat(image, HDR_FORMAT); + } + gpu::Element formatMip; gpu::Element formatGPU; if (isCubeTexturesCompressionEnabled()) { @@ -1229,13 +1242,6 @@ gpu::TexturePointer TextureUsage::processCubeTextureColorFromImage(const QImage& faces.push_back(faceImage); } } - - if (image.format() != QIMAGE_HDR_FORMAT) { - for (auto& face : faces) { - face = convertToHDRFormat(face, HDR_FORMAT); - } - } - } else { qCDebug(imagelogging) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str()); return nullptr; diff --git a/libraries/pointers/src/pointers/PickManager.h b/libraries/pointers/src/pointers/PickManager.h index f09f44621a..b8abb077c7 100644 --- a/libraries/pointers/src/pointers/PickManager.h +++ b/libraries/pointers/src/pointers/PickManager.h @@ -8,8 +8,6 @@ #ifndef hifi_PickManager_h #define hifi_PickManager_h -#include - #include #include "RegisteredMetaTypes.h" diff --git a/libraries/pointers/src/pointers/PointerManager.h b/libraries/pointers/src/pointers/PointerManager.h index db08199949..2ec5921e3c 100644 --- a/libraries/pointers/src/pointers/PointerManager.h +++ b/libraries/pointers/src/pointers/PointerManager.h @@ -12,13 +12,12 @@ #include #include -#include #include #include "Pointer.h" -class PointerManager : public QObject, public Dependency, protected ReadWriteLockable{ +class PointerManager : public QObject, public Dependency, protected ReadWriteLockable { Q_OBJECT SINGLETON_DEPENDENCY public: diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.cpp b/libraries/ui/src/ui/OffscreenQmlSurface.cpp index 6cf8a927ff..53e14b953c 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.cpp +++ b/libraries/ui/src/ui/OffscreenQmlSurface.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "types/FileTypeProfile.h" #include "types/HFWebEngineProfile.h" @@ -52,6 +53,53 @@ Q_LOGGING_CATEGORY(trace_render_qml, "trace.render.qml") Q_LOGGING_CATEGORY(trace_render_qml_gl, "trace.render.qml.gl") Q_LOGGING_CATEGORY(offscreenFocus, "hifi.offscreen.focus") + +class OffscreenQmlWhitelist : public Dependency, private ReadWriteLockable { + SINGLETON_DEPENDENCY + +public: + + void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback) { + withWriteLock([&] { + for (const auto& url : urls) { + _callbacks[url].push_back(callback); + } + }); + } + + QList getCallbacksForUrl(const QUrl& url) const { + return resultWithReadLock>([&] { + QList result; + auto itr = _callbacks.find(url); + if (_callbacks.end() != itr) { + result = *itr; + } + return result; + }); + } + +private: + + QHash> _callbacks; +}; + +QSharedPointer getQmlWhitelist() { + static std::once_flag once; + std::call_once(once, [&] { + DependencyManager::set(); + }); + + return DependencyManager::get(); +} + + +void OffscreenQmlSurface::addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback) { + getQmlWhitelist()->addWhitelistContextHandler(urls, callback); +} + + +QmlContextCallback OffscreenQmlSurface::DEFAULT_CONTEXT_CALLBACK = [](QQmlContext*, QObject*) {}; + struct TextureSet { // The number of surfaces with this size size_t count { 0 }; @@ -640,18 +688,26 @@ void OffscreenQmlSurface::setBaseUrl(const QUrl& baseUrl) { _qmlContext->setBaseUrl(baseUrl); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback) { if (QThread::currentThread() != thread()) { qCWarning(uiLogging) << "Called load on a non-surface thread"; } // Synchronous loading may take a while; restart the deadlock timer QMetaObject::invokeMethod(qApp, "updateHeartbeat", Qt::DirectConnection); + // Get any whitelist functionality + QList callbacks = getQmlWhitelist()->getCallbacksForUrl(qmlSource); + // If we have whitelisted content, we must load a new context + createNewContext |= !callbacks.empty(); + callbacks.push_back(onQmlLoadedCallback); + QQmlContext* targetContext = _qmlContext; if (_rootItem && createNewContext) { targetContext = new QQmlContext(targetContext); } + + // FIXME eliminate loading of relative file paths for QML QUrl finalQmlSource = qmlSource; if ((qmlSource.isRelative() && !qmlSource.isEmpty()) || qmlSource.scheme() == QLatin1String("file")) { finalQmlSource = _qmlContext->resolvedUrl(qmlSource); @@ -659,29 +715,32 @@ void OffscreenQmlSurface::load(const QUrl& qmlSource, bool createNewContext, std auto qmlComponent = new QQmlComponent(_qmlContext->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); if (qmlComponent->isLoading()) { - connect(qmlComponent, &QQmlComponent::statusChanged, this, - [this, qmlComponent, targetContext, onQmlLoadedCallback](QQmlComponent::Status) { - finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); + connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { + finishQmlLoad(qmlComponent, targetContext, callbacks); }); return; } - finishQmlLoad(qmlComponent, targetContext, onQmlLoadedCallback); + finishQmlLoad(qmlComponent, targetContext, callbacks); } -void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback) { +void OffscreenQmlSurface::loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { load(qmlSource, true, onQmlLoadedCallback); } -void OffscreenQmlSurface::load(const QUrl& qmlSource, std::function onQmlLoadedCallback) { +void OffscreenQmlSurface::load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback) { load(qmlSource, false, onQmlLoadedCallback); } +void OffscreenQmlSurface::load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback) { + return load(QUrl(qmlSourceFile), onQmlLoadedCallback); +} + void OffscreenQmlSurface::clearCache() { _qmlContext->engine()->clearComponentCache(); } -void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback) { +void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks) { disconnect(qmlComponent, &QQmlComponent::statusChanged, this, 0); if (qmlComponent->isError()) { for (const auto& error : qmlComponent->errors()) { @@ -716,7 +775,9 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext // Make sure we will call callback for this codepath // Call this before qmlComponent->completeCreate() otherwise ghost window appears if (newItem && _rootItem) { - onQmlLoadedCallback(qmlContext, newObject); + for (const auto& callback : callbacks) { + callback(qmlContext, newObject); + } } QObject* eventBridge = qmlContext->contextProperty("eventBridge").value(); @@ -751,8 +812,11 @@ void OffscreenQmlSurface::finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext _rootItem = newItem; _rootItem->setParentItem(_quickWindow->contentItem()); _rootItem->setSize(_quickWindow->renderTargetSize()); + // Call this callback after rootitem is set, otherwise VrMenu wont work - onQmlLoadedCallback(qmlContext, newObject); + for (const auto& callback : callbacks) { + callback(qmlContext, newObject); + } } void OffscreenQmlSurface::updateQuick() { @@ -1018,6 +1082,32 @@ void OffscreenQmlSurface::synthesizeKeyPress(QString key, QObject* targetOverrid } } +static void forEachKeyboard(QQuickItem* item, std::function function) { + QObject* itemObject = item; + while (itemObject) { + if (itemObject->parent()) { + itemObject = itemObject->parent(); + } else { + break; + } + } + + auto keyboards = itemObject->findChildren("keyboard"); + + for (auto keyboardObject : keyboards) { + auto keyboard = qobject_cast(keyboardObject); + if (keyboard == nullptr) { + continue; + } + + if (function) { + function(keyboard); + } + } +} + +static const int TEXTINPUT_PASSWORD = 2; + void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool numeric) { #if Q_OS_ANDROID return; @@ -1030,6 +1120,26 @@ void OffscreenQmlSurface::setKeyboardRaised(QObject* object, bool raised, bool n // if HMD is being worn, allow keyboard to open. allow it to close, HMD or not. if (!raised || qApp->property(hifi::properties::HMD).toBool()) { QQuickItem* item = dynamic_cast(object); + if (!item) { + return; + } + + auto echoMode = item->property("echoMode"); + bool isPasswordField = echoMode.isValid() && echoMode.toInt() == TEXTINPUT_PASSWORD; + + // we need to somehow pass 'isPasswordField' to visible keyboard so it will change its 'mirror text' to asterixes + // the issue in some cases there might be more than one keyboard in object tree and it is hard to understand which one is being used at the moment + // unfortunately attempts to check for visibility failed becuase visibility is not updated yet. So... I don't see other way than just update properties for all the keyboards + forEachKeyboard(item, [&](QQuickItem* keyboard) { + keyboard->setProperty("mirroredText", QVariant::fromValue(QString(""))); + keyboard->setProperty("password", isPasswordField); + }); + + // for future probably makes sense to consider one of the following: + // 1. make keyboard a singleton, which will be dynamically re-parented before showing + // 2. track currently visible keyboard somewhere, allow to subscribe for this signal + // any of above should also eliminate need in duplicated properties and code below + while (item) { // Numeric value may be set in parameter from HTML UI; for QML UI, detect numeric fields here. numeric = numeric || QString(item->metaObject()->className()).left(7) == "SpinBox"; diff --git a/libraries/ui/src/ui/OffscreenQmlSurface.h b/libraries/ui/src/ui/OffscreenQmlSurface.h index 990f81848d..74eafe9f13 100644 --- a/libraries/ui/src/ui/OffscreenQmlSurface.h +++ b/libraries/ui/src/ui/OffscreenQmlSurface.h @@ -35,12 +35,18 @@ class QQuickItem; // one copy in flight, and one copy being used by the receiver #define GPU_RESOURCE_BUFFER_SIZE 3 +using QmlContextCallback = std::function; + class OffscreenQmlSurface : public QObject { Q_OBJECT Q_PROPERTY(bool focusText READ isFocusText NOTIFY focusTextChanged) public: static void setSharedContext(QOpenGLContext* context); + static QmlContextCallback DEFAULT_CONTEXT_CALLBACK; + static void addWhitelistContextHandler(const std::initializer_list& urls, const QmlContextCallback& callback); + static void addWhitelistContextHandler(const QUrl& url, const QmlContextCallback& callback) { addWhitelistContextHandler({ { url } }, callback); }; + OffscreenQmlSurface(); virtual ~OffscreenQmlSurface(); @@ -50,12 +56,10 @@ public: void resize(const QSize& size, bool forceResize = false); QSize size() const; - Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QUrl& qmlSource, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}); - Q_INVOKABLE void load(const QString& qmlSourceFile, std::function onQmlLoadedCallback = [](QQmlContext*, QObject*) {}) { - return load(QUrl(qmlSourceFile), onQmlLoadedCallback); - } + Q_INVOKABLE void load(const QUrl& qmlSource, bool createNewContext, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void loadInNewContext(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QUrl& qmlSource, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); + Q_INVOKABLE void load(const QString& qmlSourceFile, const QmlContextCallback& onQmlLoadedCallback = DEFAULT_CONTEXT_CALLBACK); void clearCache(); void setMaxFps(uint8_t maxFps) { _maxFps = maxFps; } // Optional values for event handling @@ -120,7 +124,7 @@ protected: private: static QOpenGLContext* getSharedContext(); - void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, std::function onQmlLoadedCallback); + void finishQmlLoad(QQmlComponent* qmlComponent, QQmlContext* qmlContext, const QList& callbacks); QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject); void setupFbo(); bool allowNewFrame(uint8_t fps); diff --git a/scripts/developer/debugging/debugWindow.js b/scripts/developer/debugging/debugWindow.js index 6dd116089a..b16739b2b8 100644 --- a/scripts/developer/debugging/debugWindow.js +++ b/scripts/developer/debugging/debugWindow.js @@ -53,4 +53,8 @@ ScriptDiscoveryService.clearDebugWindow.connect(function() { window.clearDebugWindow(); }); +Script.scriptEnding.connect(function () { + window.close(); +}) + }()); diff --git a/scripts/system/controllers/controllerModules/farActionGrabEntity.js b/scripts/system/controllers/controllerModules/farActionGrabEntity.js index 79a7b70bae..7d2f62cc47 100644 --- a/scripts/system/controllers/controllerModules/farActionGrabEntity.js +++ b/scripts/system/controllers/controllerModules/farActionGrabEntity.js @@ -23,6 +23,8 @@ Script.include("/~/system/libraries/controllers.js"); (function() { var PICK_WITH_HAND_RAY = true; + var SEARCH_SPHERE_SIZE = 0.0132; + var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -37,6 +39,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -58,6 +61,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -135,10 +139,6 @@ Script.include("/~/system/libraries/controllers.js"); 100); this.updateLaserPointer = function(controllerData) { - var SEARCH_SPHERE_SIZE = 0.011; - var MIN_SPHERE_SIZE = 0.0005; - var radius = Math.max(1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance, MIN_SPHERE_SIZE) * MyAvatar.sensorToWorldScale; - var dim = {x: radius, y: radius, z: radius}; var mode = "hold"; if (!this.distanceHolding && !this.distanceRotating) { if (controllerData.triggerClicks[this.hand]) { @@ -150,16 +150,10 @@ Script.include("/~/system/libraries/controllers.js"); var laserPointerID = PICK_WITH_HAND_RAY ? this.laserPointer : this.headLaserPointer; if (mode === "full") { - var fullEndToEdit = PICK_WITH_HAND_RAY ? this.fullEnd : fullEnd; - fullEndToEdit.dimensions = dim; - LaserPointers.editRenderState(laserPointerID, mode, { path: fullPath, end: fullEndToEdit }); this.contextOverlayTimer = false; this.destroyContextOverlay(); - } else if (mode === "half") { - var halfEndToEdit = PICK_WITH_HAND_RAY ? this.halfEnd : halfEnd; - halfEndToEdit.dimensions = dim; - LaserPointers.editRenderState(laserPointerID, mode, {path: halfPath, end: halfEndToEdit}); } + LaserPointers.enableLaserPointer(laserPointerID); LaserPointers.setRenderState(laserPointerID, mode); if (this.distanceHolding || this.distanceRotating) { @@ -577,8 +571,6 @@ Script.include("/~/system/libraries/controllers.js"); LaserPointers.removeLaserPointer(this.laserPointer); }; - this.halfEnd = halfEnd; - this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, @@ -586,6 +578,7 @@ Script.include("/~/system/libraries/controllers.js"); posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, faceAvatar: true, + distanceScaleEnd: true, defaultRenderStates: defaultRenderStates }); } diff --git a/scripts/system/controllers/controllerModules/farTrigger.js b/scripts/system/controllers/controllerModules/farTrigger.js index 7975889bc8..a39124e76f 100644 --- a/scripts/system/controllers/controllerModules/farTrigger.js +++ b/scripts/system/controllers/controllerModules/farTrigger.js @@ -16,6 +16,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { + var SEARCH_SPHERE_SIZE = 0.0132; + var dim = {x: SEARCH_SPHERE_SIZE, y: SEARCH_SPHERE_SIZE, z: SEARCH_SPHERE_SIZE}; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -30,6 +32,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -51,6 +54,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -107,10 +111,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.updateLaserPointer = function(controllerData) { - var SEARCH_SPHERE_SIZE = 0.011; - var MIN_SPHERE_SIZE = 0.0005; - var radius = Math.max(1.2 * SEARCH_SPHERE_SIZE * this.intersectionDistance, MIN_SPHERE_SIZE); - var dim = {x: radius, y: radius, z: radius}; var mode = "none"; if (controllerData.triggerClicks[this.hand]) { mode = "full"; @@ -118,18 +118,8 @@ Script.include("/~/system/libraries/controllers.js"); mode = "half"; } - var laserPointerID = this.laserPointer; - if (mode === "full") { - var fullEndToEdit = this.fullEnd; - fullEndToEdit.dimensions = dim; - LaserPointers.editRenderState(laserPointerID, mode, {path: fullPath, end: fullEndToEdit}); - } else if (mode === "half") { - var halfEndToEdit = this.halfEnd; - halfEndToEdit.dimensions = dim; - LaserPointers.editRenderState(laserPointerID, mode, {path: halfPath, end: halfEndToEdit}); - } - LaserPointers.enableLaserPointer(laserPointerID); - LaserPointers.setRenderState(laserPointerID, mode); + LaserPointers.enableLaserPointer(this.laserPointer); + LaserPointers.setRenderState(this.laserPointer, mode); }; this.laserPointerOff = function() { @@ -192,8 +182,6 @@ Script.include("/~/system/libraries/controllers.js"); return makeRunningValues(true, [this.targetEntityID], []); }; - this.halfEnd = halfEnd; - this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND", filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, @@ -201,6 +189,7 @@ Script.include("/~/system/libraries/controllers.js"); posOffset: getGrabPointSphereOffset(this.handToController(), true), renderStates: renderStates, faceAvatar: true, + distanceScaleEnd: true, defaultRenderStates: defaultRenderStates }); diff --git a/scripts/system/controllers/controllerModules/hudOverlayPointer.js b/scripts/system/controllers/controllerModules/hudOverlayPointer.js index d579ce2611..875599fa47 100644 --- a/scripts/system/controllers/controllerModules/hudOverlayPointer.js +++ b/scripts/system/controllers/controllerModules/hudOverlayPointer.js @@ -22,6 +22,8 @@ (function() { Script.include("/~/system/libraries/controllers.js"); var ControllerDispatcherUtils = Script.require("/~/system/libraries/controllerDispatcherUtils.js"); + var END_RADIUS = 0.005; + var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -36,6 +38,7 @@ }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -57,6 +60,7 @@ }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -126,17 +130,6 @@ }; this.updateLaserPointer = function(controllerData) { - var RADIUS = 0.005; - var dim = { x: RADIUS, y: RADIUS, z: RADIUS }; - - if (this.mode === "full") { - this.fullEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd}); - } else if (this.mode === "half") { - this.halfEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd}); - } - LaserPointers.enableLaserPointer(this.laserPointer); LaserPointers.setRenderState(this.laserPointer, this.mode); }; @@ -212,8 +205,6 @@ LaserPointers.removeLaserPointer(this.laserPointer); }; - this.halfEnd = halfEnd; - this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", filter: Picks.PICK_HUD, diff --git a/scripts/system/controllers/controllerModules/inEditMode.js b/scripts/system/controllers/controllerModules/inEditMode.js index 34247b1d9d..e44c9f9848 100644 --- a/scripts/system/controllers/controllerModules/inEditMode.js +++ b/scripts/system/controllers/controllerModules/inEditMode.js @@ -18,6 +18,8 @@ Script.include("/~/system/libraries/controllers.js"); Script.include("/~/system/libraries/utils.js"); (function () { + var END_RADIUS = 0.005; + var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -32,6 +34,7 @@ Script.include("/~/system/libraries/utils.js"); }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -53,6 +56,7 @@ Script.include("/~/system/libraries/utils.js"); }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -121,17 +125,6 @@ Script.include("/~/system/libraries/utils.js"); }; this.updateLaserPointer = function(controllerData) { - var RADIUS = 0.005; - var dim = { x: RADIUS, y: RADIUS, z: RADIUS }; - - if (this.mode === "full") { - this.fullEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd}); - } else if (this.mode === "half") { - this.halfEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd}); - } - LaserPointers.enableLaserPointer(this.laserPointer); LaserPointers.setRenderState(this.laserPointer, this.mode); @@ -237,10 +230,6 @@ Script.include("/~/system/libraries/utils.js"); LaserPointers.removeLaserPointer(this.laserPointer); }; - - this.halfEnd = halfEnd; - this.fullEnd = fullEnd; - this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", filter: Picks.PICK_ENTITIES | Picks.PICK_OVERLAYS, diff --git a/scripts/system/controllers/controllerModules/overlayLaserInput.js b/scripts/system/controllers/controllerModules/overlayLaserInput.js index 0747985c7b..c517ab627e 100644 --- a/scripts/system/controllers/controllerModules/overlayLaserInput.js +++ b/scripts/system/controllers/controllerModules/overlayLaserInput.js @@ -17,6 +17,8 @@ Script.include("/~/system/libraries/controllers.js"); (function() { var TouchEventUtils = Script.require("/~/system/libraries/touchEventUtils.js"); + var END_RADIUS = 0.005; + var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -31,6 +33,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -52,6 +55,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -171,17 +175,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.updateLaserPointer = function(controllerData) { - var RADIUS = 0.005; - var dim = { x: RADIUS, y: RADIUS, z: RADIUS }; - - if (this.mode === "full") { - this.fullEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: this.fullEnd}); - } else if (this.mode === "half") { - this.halfEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: this.halfEnd}); - } - LaserPointers.enableLaserPointer(this.laserPointer); LaserPointers.setRenderState(this.laserPointer, this.mode); @@ -371,8 +364,6 @@ Script.include("/~/system/libraries/controllers.js"); LaserPointers.removeLaserPointer(this.laserPointer); }; - this.halfEnd = halfEnd; - this.fullEnd = fullEnd; this.laserPointer = LaserPointers.createLaserPointer({ joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND", filter: Picks.PICK_OVERLAYS, diff --git a/scripts/system/controllers/controllerModules/webEntityLaserInput.js b/scripts/system/controllers/controllerModules/webEntityLaserInput.js index 0076e1c865..32ff7cbf44 100644 --- a/scripts/system/controllers/controllerModules/webEntityLaserInput.js +++ b/scripts/system/controllers/controllerModules/webEntityLaserInput.js @@ -17,6 +17,8 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js"); Script.include("/~/system/libraries/controllers.js"); (function() { + var END_RADIUS = 0.005; + var dim = { x: END_RADIUS, y: END_RADIUS, z: END_RADIUS }; var halfPath = { type: "line3d", color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, @@ -31,6 +33,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var halfEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_HALF_SQUEEZE, alpha: 0.9, @@ -52,6 +55,7 @@ Script.include("/~/system/libraries/controllers.js"); }; var fullEnd = { type: "sphere", + dimensions: dim, solid: true, color: COLORS_GRAB_SEARCHING_FULL_SQUEEZE, alpha: 0.9, @@ -366,17 +370,6 @@ Script.include("/~/system/libraries/controllers.js"); }; this.updateLaserPointer = function(controllerData) { - var RADIUS = 0.005; - var dim = { x: RADIUS, y: RADIUS, z: RADIUS }; - - if (this.mode === "full") { - fullEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: fullPath, end: fullEnd}); - } else if (this.mode === "half") { - halfEnd.dimensions = dim; - LaserPointers.editRenderState(this.laserPointer, this.mode, {path: halfPath, end: halfEnd}); - } - LaserPointers.enableLaserPointer(this.laserPointer); LaserPointers.setRenderState(this.laserPointer, this.mode); };