diff --git a/assignment-client/src/Agent.cpp b/assignment-client/src/Agent.cpp index d1c2c6597b..a42b78a6fa 100644 --- a/assignment-client/src/Agent.cpp +++ b/assignment-client/src/Agent.cpp @@ -343,7 +343,6 @@ void Agent::scriptRequestFinished() { void Agent::executeScript() { _scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload); - _scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do DependencyManager::get()->setScriptEngine(_scriptEngine); diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 8576e26fcd..a9629c0e4e 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -102,7 +102,7 @@ Column { 'include_actions=' + actions, 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), 'require_online=true', - 'protocol=' + encodeURIComponent(AddressManager.protocolVersion()), + 'protocol=' + encodeURIComponent(Window.protocolSignature()), 'page=' + pageNumber ]; var url = metaverseBase + 'user_stories?' + options.join('&'); diff --git a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml index 81d38bc0dd..b980c13e3c 100644 --- a/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml +++ b/interface/resources/qml/hifi/commerce/wallet/WalletHome.qml @@ -392,7 +392,6 @@ Item { width: 118; height: paintedHeight; wrapMode: Text.WordWrap; - font.bold: true; // Alignment horizontalAlignment: Text.AlignRight; } diff --git a/interface/resources/qml/hifi/overlays/ImageOverlay.qml b/interface/resources/qml/hifi/overlays/ImageOverlay.qml index 6899c38e67..cbcf6c7910 100644 --- a/interface/resources/qml/hifi/overlays/ImageOverlay.qml +++ b/interface/resources/qml/hifi/overlays/ImageOverlay.qml @@ -7,7 +7,7 @@ import "." Overlay { id: root - Image { + AnimatedImage { id: image property bool scaleFix: true property real xStart: 0 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9d17004c85..31c47a580b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -611,8 +611,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) { } }; reportAndQuit("--protocolVersion", [&](FILE* fp) { - DependencyManager::set(); - auto version = DependencyManager::get()->protocolVersion(); + auto version = protocolVersionsSignatureBase64(); fputs(version.toLatin1().data(), fp); }); reportAndQuit("--version", [&](FILE* fp) { @@ -2153,6 +2152,11 @@ void Application::cleanupBeforeQuit() { DependencyManager::destroy(); DependencyManager::destroy(); + // The PointerManager must be destroyed before the PickManager because when a Pointer is deleted, + // it accesses the PickManager to delete its associated Pick + DependencyManager::destroy(); + DependencyManager::destroy(); + qCDebug(interfaceapp) << "Application::cleanupBeforeQuit() complete"; } @@ -4439,8 +4443,9 @@ void Application::updateLOD(float deltaTime) const { float presentTime = getActiveDisplayPlugin()->getAveragePresentTime(); float engineRunTime = (float)(_renderEngine->getConfiguration().get()->getCPURunTime()); float gpuTime = getGPUContext()->getFrameTimerGPUAverage(); - float maxRenderTime = glm::max(gpuTime, glm::max(presentTime, engineRunTime)); - DependencyManager::get()->autoAdjustLOD(maxRenderTime, deltaTime); + auto lodManager = DependencyManager::get(); + lodManager->setRenderTimes(presentTime, engineRunTime, gpuTime); + lodManager->autoAdjustLOD(deltaTime); } else { DependencyManager::get()->resetLODAdjust(); } diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 087a93cffe..73547cdb5e 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -26,43 +26,50 @@ Setting::Handle hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DO LODManager::LODManager() { } -float LODManager::getLODDecreaseFPS() { +float LODManager::getLODDecreaseFPS() const { if (qApp->isHMDMode()) { return getHMDLODDecreaseFPS(); } return getDesktopLODDecreaseFPS(); } -float LODManager::getLODIncreaseFPS() { +float LODManager::getLODIncreaseFPS() const { if (qApp->isHMDMode()) { return getHMDLODIncreaseFPS(); } return getDesktopLODIncreaseFPS(); } -// We use a "time-weighted running average" of the renderTime and compare it against min/max thresholds +// We use a "time-weighted running average" of the maxRenderTime and compare it against min/max thresholds // to determine if we should adjust the level of detail (LOD). // // A time-weighted running average has a timescale which determines how fast the average tracks the measured // value in real-time. Given a step-function in the mesured value, and assuming measurements happen // faster than the runningAverage is computed, the error between the value and its runningAverage will be // reduced by 1/e every timescale of real-time that passes. -const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.1f; // sec +const float LOD_ADJUST_RUNNING_AVG_TIMESCALE = 0.08f; // sec // // Assuming the measured value is affected by logic invoked by the runningAverage bumping up against its // thresholds, we expect the adjustment to introduce a step-function. We want the runningAverage to settle // to the new value BEFORE we test it aginst its thresholds again. Hence we test on a period that is a few // multiples of the running average timescale: -const uint64_t LOD_AUTO_ADJUST_PERIOD = 5 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec +const uint64_t LOD_AUTO_ADJUST_PERIOD = 4 * (uint64_t)(LOD_ADJUST_RUNNING_AVG_TIMESCALE * (float)USECS_PER_MSEC); // usec const float LOD_AUTO_ADJUST_DECREMENT_FACTOR = 0.8f; const float LOD_AUTO_ADJUST_INCREMENT_FACTOR = 1.2f; -void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) { - // compute time-weighted running average renderTime +void LODManager::setRenderTimes(float presentTime, float engineRunTime, float gpuTime) { + _presentTime = presentTime; + _engineRunTime = engineRunTime; + _gpuTime = gpuTime; +} + +void LODManager::autoAdjustLOD(float realTimeDelta) { + float maxRenderTime = glm::max(glm::max(_presentTime, _engineRunTime), _gpuTime); + // compute time-weighted running average maxRenderTime // Note: we MUST clamp the blend to 1.0 for stability float blend = (realTimeDelta < LOD_ADJUST_RUNNING_AVG_TIMESCALE) ? realTimeDelta / LOD_ADJUST_RUNNING_AVG_TIMESCALE : 1.0f; - _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * renderTime; // msec + _avgRenderTime = (1.0f - blend) * _avgRenderTime + blend * maxRenderTime; // msec if (!_automaticLODAdjust) { // early exit return; @@ -84,6 +91,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) { << "targetFPS =" << getLODDecreaseFPS() << "octreeSizeScale =" << _octreeSizeScale; emit LODDecreased(); + // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime + // to provide an FPS just above the decrease threshold. It will drift close to its + // true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. + _avgRenderTime = (float)MSECS_PER_SECOND / (getLODDecreaseFPS() + 1.0f); } _decreaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } @@ -105,6 +116,10 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) { << "targetFPS =" << getLODDecreaseFPS() << "octreeSizeScale =" << _octreeSizeScale; emit LODIncreased(); + // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime + // to provide an FPS just below the increase threshold. It will drift close to its + // true value after a few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. + _avgRenderTime = (float)MSECS_PER_SECOND / (getLODIncreaseFPS() - 1.0f); } _increaseFPSExpiry = now + LOD_AUTO_ADJUST_PERIOD; } @@ -119,11 +134,6 @@ void LODManager::autoAdjustLOD(float renderTime, float realTimeDelta) { if (lodToolsDialog) { lodToolsDialog->reloadSliders(); } - // Assuming the LOD adjustment will work: we optimistically reset _avgRenderTime - // to be at middle of target zone. It will drift close to its true value within - // about three few LOD_ADJUST_TIMESCALEs and we'll adjust again as necessary. - float expectedFPS = 0.5f * (getLODIncreaseFPS() + getLODDecreaseFPS()); - _avgRenderTime = MSECS_PER_SECOND / expectedFPS; } } @@ -131,6 +141,18 @@ void LODManager::resetLODAdjust() { _decreaseFPSExpiry = _increaseFPSExpiry = usecTimestampNow() + LOD_AUTO_ADJUST_PERIOD; } +float LODManager::getLODLevel() const { + // simpleLOD is a linearized and normalized number that represents how much LOD is being applied. + // It ranges from: + // 1.0 = normal (max) level of detail + // 0.0 = min level of detail + // In other words: as LOD "drops" the value of simpleLOD will also "drop", and it cannot go lower than 0.0. + const float LOG_MIN_LOD_RATIO = logf(ADJUST_LOD_MIN_SIZE_SCALE / ADJUST_LOD_MAX_SIZE_SCALE); + float power = logf(_octreeSizeScale / ADJUST_LOD_MAX_SIZE_SCALE); + float simpleLOD = (LOG_MIN_LOD_RATIO - power) / LOG_MIN_LOD_RATIO; + return simpleLOD; +} + const float MIN_DECREASE_FPS = 0.5f; void LODManager::setDesktopLODDecreaseFPS(float fps) { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index cf38342db0..ca6be9380b 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -37,7 +37,7 @@ class AABox; class LODManager : public QObject, public Dependency { Q_OBJECT SINGLETON_DEPENDENCY - + public: Q_INVOKABLE void setAutomaticLODAdjust(bool value) { _automaticLODAdjust = value; } Q_INVOKABLE bool getAutomaticLODAdjust() const { return _automaticLODAdjust; } @@ -49,34 +49,56 @@ public: Q_INVOKABLE void setHMDLODDecreaseFPS(float value); Q_INVOKABLE float getHMDLODDecreaseFPS() const; Q_INVOKABLE float getHMDLODIncreaseFPS() const; - + // User Tweakable LOD Items Q_INVOKABLE QString getLODFeedbackText(); Q_INVOKABLE void setOctreeSizeScale(float sizeScale); Q_INVOKABLE float getOctreeSizeScale() const { return _octreeSizeScale; } - + Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - - Q_INVOKABLE float getLODDecreaseFPS(); - Q_INVOKABLE float getLODIncreaseFPS(); - + + Q_INVOKABLE float getLODDecreaseFPS() const; + Q_INVOKABLE float getLODIncreaseFPS() const; + + Q_PROPERTY(float presentTime READ getPresentTime) + Q_PROPERTY(float engineRunTime READ getEngineRunTime) + Q_PROPERTY(float gpuTime READ getGPUTime) + Q_PROPERTY(float avgRenderTime READ getAverageRenderTime) + Q_PROPERTY(float fps READ getMaxTheoreticalFPS) + Q_PROPERTY(float lodLevel READ getLODLevel) + + Q_PROPERTY(float lodDecreaseFPS READ getLODDecreaseFPS) + Q_PROPERTY(float lodIncreaseFPS READ getLODIncreaseFPS) + + float getPresentTime() const { return _presentTime; } + float getEngineRunTime() const { return _engineRunTime; } + float getGPUTime() const { return _gpuTime; } + static bool shouldRender(const RenderArgs* args, const AABox& bounds); - void autoAdjustLOD(float renderTime, float realTimeDelta); - + void setRenderTimes(float presentTime, float engineRunTime, float gpuTime); + void autoAdjustLOD(float realTimeDelta); + void loadSettings(); void saveSettings(); void resetLODAdjust(); - + + float getAverageRenderTime() const { return _avgRenderTime; }; + float getMaxTheoreticalFPS() const { return (float)MSECS_PER_SECOND / _avgRenderTime; }; + float getLODLevel() const; + signals: void LODIncreased(); void LODDecreased(); - + private: LODManager(); - + bool _automaticLODAdjust = true; - float _avgRenderTime { 0.0f }; + float _presentTime { 0.0f }; // msec + float _engineRunTime { 0.0f }; // msec + float _gpuTime { 0.0f }; // msec + float _avgRenderTime { 0.0f }; // msec float _desktopMaxRenderTime { DEFAULT_DESKTOP_MAX_RENDER_TIME }; float _hmdMaxRenderTime { DEFAULT_HMD_MAX_RENDER_TIME }; diff --git a/interface/src/commerce/Ledger.cpp b/interface/src/commerce/Ledger.cpp index 50ea6629cf..10ddd4c110 100644 --- a/interface/src/commerce/Ledger.cpp +++ b/interface/src/commerce/Ledger.cpp @@ -17,6 +17,7 @@ #include "Ledger.h" #include "CommerceLogging.h" #include +#include // inventory answers {status: 'success', data: {assets: [{id: "guid", title: "name", preview: "url"}....]}} // balance answers {status: 'success', data: {balance: integer}} @@ -122,24 +123,33 @@ QString hfcString(const QJsonValue& sentValue, const QJsonValue& receivedValue) int sent = sentValue.toInt(); int received = receivedValue.toInt(); if (sent <= 0 && received <= 0) { - return QString("-"); + return QString("0 HFC"); } QString result; if (sent > 0) { - result += QString("-%1 HFC").arg(sent); + result += QString("-%1 HFC").arg(sent); if (received > 0) { result += QString("
"); } } if (received > 0) { - result += QString("%1 HFC").arg(received); + result += QString("%1 HFC").arg(received); } return result; } static const QString USER_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/users/"; -QString userLink(const QString& username) { +static const QString PLACE_PAGE_BASE_URL = NetworkingConstants::METAVERSE_SERVER_URL().toString() + "/places/"; +static const QStringList KNOWN_USERS(QStringList() << "highfidelity" << "marketplace"); +QString userLink(const QString& username, const QString& placename) { if (username.isEmpty()) { - return QString("someone"); + if (placename.isEmpty()) { + return QString("someone"); + } else { + return QString("someone nearby").arg(PLACE_PAGE_BASE_URL, placename); + } + } + if (KNOWN_USERS.contains(username)) { + return username; } return QString("%2").arg(USER_PAGE_BASE_URL, username); } @@ -153,13 +163,13 @@ QString transactionString(const QJsonObject& valueObject) { QDateTime createdAt(QDateTime::fromSecsSinceEpoch(dateInteger, Qt::UTC)); QString result; - if (sentCerts <= 0 && receivedCerts <= 0) { + if (sentCerts <= 0 && receivedCerts <= 0 && !KNOWN_USERS.contains(valueObject["sender_name"].toString())) { // this is an hfc transfer. if (sent > 0) { - QString recipient = userLink(valueObject["recipient_name"].toString()); + QString recipient = userLink(valueObject["recipient_name"].toString(), valueObject["place_name"].toString()); result += QString("Money sent to %1").arg(recipient); } else { - QString sender = userLink(valueObject["sender_name"].toString()); + QString sender = userLink(valueObject["sender_name"].toString(), valueObject["place_name"].toString()); result += QString("Money from %1").arg(sender); } if (!message.isEmpty()) { @@ -168,8 +178,8 @@ QString transactionString(const QJsonObject& valueObject) { } else { result += valueObject["message"].toString(); } + // no matter what we append a smaller date to the bottom of this... - result += QString("
%1").arg(createdAt.toLocalTime().toString(Qt::DefaultLocaleShortDate)); return result; } @@ -310,6 +320,7 @@ void Ledger::transferHfcToNode(const QString& hfc_key, const QString& nodeID, co transaction["node_id"] = nodeID; transaction["quantity"] = amount; transaction["message"] = optionalMessage; + transaction["place_name"] = DependencyManager::get()->getPlaceName(); QJsonDocument transactionDoc{ transaction }; auto transactionString = transactionDoc.toJson(QJsonDocument::Compact); signedSend("transaction", transactionString, hfc_key, "transfer_hfc_to_node", "transferHfcToNodeSuccess", "transferHfcToNodeFailure"); diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index e50eb06355..69b1444841 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -390,6 +390,10 @@ QString WindowScriptingInterface::checkVersion() { return QCoreApplication::applicationVersion(); } +QString WindowScriptingInterface::protocolSignature() { + return protocolVersionsSignatureBase64(); +} + int WindowScriptingInterface::getInnerWidth() { return qApp->getDeviceSize().x; } diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index bfad5644bf..1225342d89 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -305,6 +305,13 @@ public slots: */ QString checkVersion(); + /**jsdoc + * Get the signature for Interface's protocol version. + * @function Window.protocolSignature + * @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using. + */ + QString protocolSignature(); + /**jsdoc * Copies text to the operating system's clipboard. * @function Window.copyToClipboard diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index a7c586df1f..5e38f28a06 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -386,8 +386,6 @@ void Circle3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index c3a772e565..f13f782482 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -154,8 +154,6 @@ void Cube3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index 679a4afbd2..621c19944b 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -132,8 +132,6 @@ void Grid3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index ca7af3a08b..df93245922 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -208,8 +208,6 @@ void Image3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index a8425d482f..7200abf74e 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -275,8 +275,6 @@ void Line3DOverlay::setProperties(const QVariantMap& originalProperties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index ec586771af..d29ee93e62 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -306,8 +306,6 @@ vectorType ModelOverlay::mapJoints(mapFunction function) const { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Overlay.cpp b/interface/src/ui/overlays/Overlay.cpp index 5cf9fc7c8b..3c952b8338 100644 --- a/interface/src/ui/overlays/Overlay.cpp +++ b/interface/src/ui/overlays/Overlay.cpp @@ -31,8 +31,7 @@ Overlay::Overlay() : _alphaPulse(0.0f), _colorPulse(0.0f), _color(DEFAULT_OVERLAY_COLOR), - _visible(true), - _anchor(NO_ANCHOR) + _visible(true) { } @@ -49,8 +48,7 @@ Overlay::Overlay(const Overlay* overlay) : _alphaPulse(overlay->_alphaPulse), _colorPulse(overlay->_colorPulse), _color(overlay->_color), - _visible(overlay->_visible), - _anchor(overlay->_anchor) + _visible(overlay->_visible) { } @@ -92,13 +90,6 @@ void Overlay::setProperties(const QVariantMap& properties) { bool visible = properties["visible"].toBool(); setVisible(visible); } - - if (properties["anchor"].isValid()) { - QString property = properties["anchor"].toString(); - if (property == "MyAvatar") { - setAnchor(MY_AVATAR); - } - } } // JSDoc for copying to @typedefs of overlay types that inherit Overlay. @@ -119,8 +110,6 @@ void Overlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. */ QVariant Overlay::getProperty(const QString& property) { if (property == "type") { @@ -150,9 +139,6 @@ QVariant Overlay::getProperty(const QString& property) { if (property == "visible") { return _visible; } - if (property == "anchor") { - return _anchor == MY_AVATAR ? "MyAvatar" : ""; - } return QVariant(); } diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 9b07f24600..e9271f3c3f 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -26,11 +26,6 @@ class Overlay : public QObject { Q_OBJECT public: - enum Anchor { - NO_ANCHOR, - MY_AVATAR - }; - typedef std::shared_ptr Pointer; typedef render::Payload Payload; typedef std::shared_ptr PayloadPointer; @@ -63,7 +58,6 @@ public: virtual bool isTransparent() { return getAlphaPulse() != 0.0f || getAlpha() != 1.0f; }; xColor getColor(); float getAlpha(); - Anchor getAnchor() const { return _anchor; } float getPulseMax() const { return _pulseMax; } float getPulseMin() const { return _pulseMin; } @@ -78,7 +72,6 @@ public: void setDrawHUDLayer(bool drawHUDLayer); void setColor(const xColor& color) { _color = color; } void setAlpha(float alpha) { _alpha = alpha; } - void setAnchor(Anchor anchor) { _anchor = anchor; } void setPulseMax(float value) { _pulseMax = value; } void setPulseMin(float value) { _pulseMin = value; } @@ -118,7 +111,6 @@ protected: xColor _color; bool _visible; // should the overlay be drawn at all - Anchor _anchor; unsigned int _stackOrder { 0 }; diff --git a/interface/src/ui/overlays/OverlayPanel.cpp b/interface/src/ui/overlays/OverlayPanel.cpp deleted file mode 100644 index 06480109ce..0000000000 --- a/interface/src/ui/overlays/OverlayPanel.cpp +++ /dev/null @@ -1,190 +0,0 @@ -// -// OverlayPanel.cpp -// interface/src/ui/overlays -// -// Created by Zander Otavka on 7/2/15. -// Copyright 2014 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 "OverlayPanel.h" - -#if OVERLAY_PANELS - -#include -#include -#include -#include - -#include "avatar/AvatarManager.h" -#include "avatar/MyAvatar.h" -#include "Base3DOverlay.h" - -PropertyBinding::PropertyBinding(QString avatar, QUuid entity) : - avatar(avatar), - entity(entity) -{ -} - -QVariant propertyBindingToVariant(const PropertyBinding& value) { - QVariantMap obj; - - if (value.avatar == "MyAvatar") { - obj["avatar"] = "MyAvatar"; - } else if (!value.entity.isNull()) { - obj["entity"] = value.entity; - } - - return obj; -} - -void propertyBindingFromVariant(const QVariant& objectVar, PropertyBinding& value) { - auto object = objectVar.toMap(); - auto avatar = object["avatar"]; - auto entity = object["entity"]; - - if (avatar.isValid() && !avatar.isNull()) { - value.avatar = avatar.toString(); - } else if (entity.isValid() && !entity.isNull()) { - value.entity = entity.toUuid(); - } -} - - -void OverlayPanel::addChild(OverlayID childId) { - if (!_children.contains(childId)) { - _children.append(childId); - } -} - -void OverlayPanel::removeChild(OverlayID childId) { - if (_children.contains(childId)) { - _children.removeOne(childId); - } -} - -QVariant OverlayPanel::getProperty(const QString &property) { - if (property == "anchorPosition") { - return vec3toVariant(getAnchorPosition()); - } - if (property == "anchorPositionBinding") { - return propertyBindingToVariant(PropertyBinding(_anchorPositionBindMyAvatar ? - "MyAvatar" : "", - _anchorPositionBindEntity)); - } - if (property == "anchorRotation") { - return quatToVariant(getAnchorRotation()); - } - if (property == "anchorRotationBinding") { - return propertyBindingToVariant(PropertyBinding(_anchorRotationBindMyAvatar ? - "MyAvatar" : "", - _anchorRotationBindEntity)); - } - if (property == "anchorScale") { - return vec3toVariant(getAnchorScale()); - } - if (property == "visible") { - return getVisible(); - } - if (property == "children") { - QVariantList array; - for (int i = 0; i < _children.length(); i++) { - array.append(OverlayIDtoScriptValue(nullptr, _children[i]).toVariant()); - } - return array; - } - - auto value = Billboardable::getProperty(property); - if (value.isValid()) { - return value; - } - return PanelAttachable::getProperty(property); -} - -void OverlayPanel::setProperties(const QVariantMap& properties) { - PanelAttachable::setProperties(properties); - Billboardable::setProperties(properties); - - auto anchorPosition = properties["anchorPosition"]; - if (anchorPosition.isValid()) { - setAnchorPosition(vec3FromVariant(anchorPosition)); - } - - auto anchorPositionBinding = properties["anchorPositionBinding"]; - if (anchorPositionBinding.isValid()) { - PropertyBinding binding = {}; - propertyBindingFromVariant(anchorPositionBinding, binding); - _anchorPositionBindMyAvatar = binding.avatar == "MyAvatar"; - _anchorPositionBindEntity = binding.entity; - } - - auto anchorRotation = properties["anchorRotation"]; - if (anchorRotation.isValid()) { - setAnchorRotation(quatFromVariant(anchorRotation)); - } - - auto anchorRotationBinding = properties["anchorRotationBinding"]; - if (anchorRotationBinding.isValid()) { - PropertyBinding binding = {}; - propertyBindingFromVariant(anchorPositionBinding, binding); - _anchorRotationBindMyAvatar = binding.avatar == "MyAvatar"; - _anchorRotationBindEntity = binding.entity; - } - - auto anchorScale = properties["anchorScale"]; - if (anchorScale.isValid()) { - setAnchorScale(vec3FromVariant(anchorScale)); - } - - auto visible = properties["visible"]; - if (visible.isValid()) { - setVisible(visible.toBool()); - } -} - -void OverlayPanel::applyTransformTo(Transform& transform, bool force) { - if (force || usecTimestampNow() > _transformExpiry) { - PanelAttachable::applyTransformTo(transform, true); - if (!getParentPanel()) { - if (_anchorPositionBindMyAvatar) { - transform.setTranslation(DependencyManager::get()->getMyAvatar() - ->getPosition()); - } else if (!_anchorPositionBindEntity.isNull()) { - EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); - entityTree->withReadLock([&] { - EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorPositionBindEntity); - if (foundEntity) { - transform.setTranslation(foundEntity->getPosition()); - } - }); - } else { - transform.setTranslation(getAnchorPosition()); - } - - if (_anchorRotationBindMyAvatar) { - transform.setRotation(DependencyManager::get()->getMyAvatar() - ->getOrientation()); - } else if (!_anchorRotationBindEntity.isNull()) { - EntityTreePointer entityTree = DependencyManager::get()->getEntityTree(); - entityTree->withReadLock([&] { - EntityItemPointer foundEntity = entityTree->findEntityByID(_anchorRotationBindEntity); - if (foundEntity) { - transform.setRotation(foundEntity->getRotation()); - } - }); - } else { - transform.setRotation(getAnchorRotation()); - } - - transform.setScale(getAnchorScale()); - - transform.postTranslate(getOffsetPosition()); - transform.postRotate(getOffsetRotation()); - transform.postScale(getOffsetScale()); - } - pointTransformAtCamera(transform, getOffsetRotation()); - } -} -#endif \ No newline at end of file diff --git a/interface/src/ui/overlays/OverlayPanel.h b/interface/src/ui/overlays/OverlayPanel.h deleted file mode 100644 index cff2bc224d..0000000000 --- a/interface/src/ui/overlays/OverlayPanel.h +++ /dev/null @@ -1,86 +0,0 @@ -// -// OverlayPanel.h -// interface/src/ui/overlays -// -// Created by Zander Otavka on 7/2/15. -// Copyright 2014 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_OverlayPanel_h -#define hifi_OverlayPanel_h - -#include - -#include -#include -#include - -#include "PanelAttachable.h" -#include "Billboardable.h" -#include "Overlay.h" - -#if OVERLAY_PANELS -class PropertyBinding { -public: - PropertyBinding() {} - PropertyBinding(QString avatar, QUuid entity); - QString avatar; - QUuid entity; -}; - -QVariant propertyBindingToVariant(const PropertyBinding& value); -void propertyBindingFromVariant(const QVariant& object, PropertyBinding& value); - - -class OverlayPanel : public QObject, public PanelAttachable, public Billboardable { - Q_OBJECT - -public: - typedef std::shared_ptr Pointer; - - void init(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; } - - // getters - glm::vec3 getAnchorPosition() const { return _anchorTransform.getTranslation(); } - glm::quat getAnchorRotation() const { return _anchorTransform.getRotation(); } - glm::vec3 getAnchorScale() const { return _anchorTransform.getScale(); } - bool getVisible() const { return _visible; } - - // setters - void setAnchorPosition(const glm::vec3& position) { _anchorTransform.setTranslation(position); } - void setAnchorRotation(const glm::quat& rotation) { _anchorTransform.setRotation(rotation); } - void setAnchorScale(float scale) { _anchorTransform.setScale(scale); } - void setAnchorScale(const glm::vec3& scale) { _anchorTransform.setScale(scale); } - void setVisible(bool visible) { _visible = visible; } - - const QList& getChildren() { return _children; } - void addChild(OverlayID childId); - void removeChild(OverlayID childId); - OverlayID popLastChild() { return _children.takeLast(); } - - void setProperties(const QVariantMap& properties); - QVariant getProperty(const QString& property); - - virtual void applyTransformTo(Transform& transform, bool force = false) override; - -private: - Transform _anchorTransform; - - bool _anchorPositionBindMyAvatar = false; - QUuid _anchorPositionBindEntity; - - bool _anchorRotationBindMyAvatar = false; - QUuid _anchorRotationBindEntity; - - bool _visible = true; - QList _children; - - QScriptEngine* _scriptEngine; -}; - -#endif - -#endif // hifi_OverlayPanel_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 052ef0b6d8..7f897aee4a 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -68,16 +68,10 @@ void Overlays::cleanupAllOverlays() { foreach(Overlay::Pointer overlay, overlaysWorld) { _overlaysToDelete.push_back(overlay); } -#if OVERLAY_PANELS - _panels.clear(); -#endif cleanupOverlaysToDelete(); } void Overlays::init() { -#if OVERLAY_PANELS - _scriptEngine = new QScriptEngine(); -#endif } void Overlays::update(float deltatime) { @@ -300,12 +294,6 @@ OverlayID Overlays::cloneOverlay(OverlayID id) { if (thisOverlay) { OverlayID cloneId = addOverlay(Overlay::Pointer(thisOverlay->createClone(), [](Overlay* ptr) { ptr->deleteLater(); })); -#if OVERLAY_PANELS - auto attachable = std::dynamic_pointer_cast(thisOverlay); - if (attachable && attachable->getParentPanel()) { - attachable->getParentPanel()->addChild(cloneId); - } -#endif return cloneId; } @@ -381,15 +369,6 @@ void Overlays::deleteOverlay(OverlayID id) { } } -#if OVERLAY_PANELS - auto attachable = std::dynamic_pointer_cast(overlayToDelete); - if (attachable && attachable->getParentPanel()) { - attachable->getParentPanel()->removeChild(id); - attachable->setParentPanel(nullptr); - } -#endif - - _overlaysToDelete.push_back(overlayToDelete); emit overlayDeleted(id); } @@ -424,49 +403,6 @@ QObject* Overlays::getOverlayObject(OverlayID id) { return nullptr; } -#if OVERLAY_PANELS -OverlayID Overlays::getParentPanel(OverlayID childId) const { - Overlay::Pointer overlay = getOverlay(childId); - auto attachable = std::dynamic_pointer_cast(overlay); - if (attachable) { - return _panels.key(attachable->getParentPanel()); - } else if (_panels.contains(childId)) { - return _panels.key(getPanel(childId)->getParentPanel()); - } - return UNKNOWN_OVERLAY_ID; -} - -void Overlays::setParentPanel(OverlayID childId, OverlayID panelId) { - auto attachable = std::dynamic_pointer_cast(getOverlay(childId)); - if (attachable) { - if (_panels.contains(panelId)) { - auto panel = getPanel(panelId); - panel->addChild(childId); - attachable->setParentPanel(panel); - } else { - auto panel = attachable->getParentPanel(); - if (panel) { - panel->removeChild(childId); - attachable->setParentPanel(nullptr); - } - } - } else if (_panels.contains(childId)) { - OverlayPanel::Pointer child = getPanel(childId); - if (_panels.contains(panelId)) { - auto panel = getPanel(panelId); - panel->addChild(childId); - child->setParentPanel(panel); - } else { - auto panel = child->getParentPanel(); - if (panel) { - panel->removeChild(childId); - child->setParentPanel(0); - } - } - } -} -#endif - OverlayID Overlays::getOverlayAtPoint(const glm::vec2& point) { if (!_enabled) { return UNKNOWN_OVERLAY_ID; @@ -717,62 +653,6 @@ QSizeF Overlays::textSize(OverlayID id, const QString& text) { return QSizeF(0.0f, 0.0f); } -#if OVERLAY_PANELS -OverlayID Overlays::addPanel(OverlayPanel::Pointer panel) { - QWriteLocker lock(&_lock); - - OverlayID thisID = QUuid::createUuid(); - _panels[thisID] = panel; - - return thisID; -} - -OverlayID Overlays::addPanel(const QVariant& properties) { - OverlayPanel::Pointer panel = std::make_shared(); - panel->init(_scriptEngine); - panel->setProperties(properties.toMap()); - return addPanel(panel); -} - -void Overlays::editPanel(OverlayID panelId, const QVariant& properties) { - if (_panels.contains(panelId)) { - _panels[panelId]->setProperties(properties.toMap()); - } -} - -OverlayPropertyResult Overlays::getPanelProperty(OverlayID panelId, const QString& property) { - OverlayPropertyResult result; - if (_panels.contains(panelId)) { - OverlayPanel::Pointer thisPanel = getPanel(panelId); - QReadLocker lock(&_lock); - result.value = thisPanel->getProperty(property); - } - return result; -} - - -void Overlays::deletePanel(OverlayID panelId) { - OverlayPanel::Pointer panelToDelete; - - { - QWriteLocker lock(&_lock); - if (_panels.contains(panelId)) { - panelToDelete = _panels.take(panelId); - } else { - return; - } - } - - while (!panelToDelete->getChildren().isEmpty()) { - OverlayID childId = panelToDelete->popLastChild(); - deleteOverlay(childId); - deletePanel(childId); - } - - emit panelDeleted(panelId); -} -#endif - bool Overlays::isAddedOverlay(OverlayID id) { if (QThread::currentThread() != thread()) { bool result; diff --git a/interface/src/ui/overlays/Overlays.h b/interface/src/ui/overlays/Overlays.h index 04c0d01fa2..fd57869048 100644 --- a/interface/src/ui/overlays/Overlays.h +++ b/interface/src/ui/overlays/Overlays.h @@ -27,7 +27,6 @@ #include "Overlay.h" #include "PanelAttachable.h" -#include "OverlayPanel.h" class PickRay; @@ -93,9 +92,6 @@ public: void enable(); Overlay::Pointer getOverlay(OverlayID id) const; -#if OVERLAY_PANELS - OverlayPanel::Pointer getPanel(OverlayID id) const { return _panels[id]; } -#endif /// adds an overlay that's already been created OverlayID addOverlay(Overlay* overlay) { return addOverlay(Overlay::Pointer(overlay)); } @@ -468,30 +464,6 @@ public slots: */ bool isAddedOverlay(OverlayID id); -#if OVERLAY_PANELS - OverlayID getParentPanel(OverlayID childId) const; - void setParentPanel(OverlayID childId, OverlayID panelId); - - /// adds a panel that has already been created - OverlayID addPanel(OverlayPanel::Pointer panel); - - /// creates and adds a panel based on a set of properties - OverlayID addPanel(const QVariant& properties); - - /// edit the properties of a panel - void editPanel(OverlayID panelId, const QVariant& properties); - - /// get a property of a panel - OverlayPropertyResult getPanelProperty(OverlayID panelId, const QString& property); - - /// deletes a panel and all child overlays - void deletePanel(OverlayID panelId); - - /// return true if there is a panel with that id else false - bool isAddedPanel(OverlayID id) { return _panels.contains(id); } - -#endif - /**jsdoc * Generate a mouse press event on an overlay. * @function Overlays.sendMousePressOnOverlay @@ -612,10 +584,6 @@ signals: */ void overlayDeleted(OverlayID id); -#if OVERLAY_PANELS - void panelDeleted(OverlayID id); -#endif - /**jsdoc * Triggered when a mouse press event occurs on an overlay. Only occurs for 3D overlays (unless you use * {@link Overlays.sendMousePressOnOverlay|sendMousePressOnOverlay} for a 2D overlay). @@ -732,15 +700,9 @@ private: QMap _overlaysHUD; QMap _overlaysWorld; -#if OVERLAY_PANELS - QMap _panels; -#endif QList _overlaysToDelete; unsigned int _stackOrder { 1 }; -#if OVERLAY_PANELS - QScriptEngine* _scriptEngine; -#endif bool _enabled = true; PointerEvent calculateOverlayPointerEvent(OverlayID overlayID, PickRay ray, RayToOverlayIntersectionResult rayPickResult, diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index fceb261503..449ac62998 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -65,23 +65,7 @@ namespace render { } template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) { if (args) { - if (overlay->getAnchor() == Overlay::MY_AVATAR) { - auto batch = args->_batch; - auto avatar = DependencyManager::get()->getMyAvatar(); - glm::quat myAvatarRotation = avatar->getWorldOrientation(); - glm::vec3 myAvatarPosition = avatar->getWorldPosition(); - float angle = glm::degrees(glm::angle(myAvatarRotation)); - glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getModelScale(); - Transform transform = Transform(); - transform.setTranslation(myAvatarPosition); - transform.setRotation(glm::angleAxis(angle, axis)); - transform.setScale(myAvatarScale); - batch->setModelTransform(transform); - overlay->render(args); - } else { - overlay->render(args); - } + overlay->render(args); } } template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay) { diff --git a/interface/src/ui/overlays/PanelAttachable.cpp b/interface/src/ui/overlays/PanelAttachable.cpp index bcd32b2850..b53474390c 100644 --- a/interface/src/ui/overlays/PanelAttachable.cpp +++ b/interface/src/ui/overlays/PanelAttachable.cpp @@ -13,18 +13,8 @@ #include -#include "OverlayPanel.h" - bool PanelAttachable::getParentVisible() const { -#if OVERLAY_PANELS - if (getParentPanel()) { - return getParentPanel()->getVisible() && getParentPanel()->getParentVisible(); - } else { - return true; - } -#else return true; -#endif } // JSDoc for copying to @typedefs of overlay types that inherit PanelAttachable. @@ -67,15 +57,6 @@ bool PanelAttachable::applyTransformTo(Transform& transform, bool force) { if (force || usecTimestampNow() > _transformExpiry) { const quint64 TRANSFORM_UPDATE_PERIOD = 100000; // frequency is 10 Hz _transformExpiry = usecTimestampNow() + TRANSFORM_UPDATE_PERIOD; -#if OVERLAY_PANELS - if (getParentPanel()) { - getParentPanel()->applyTransformTo(transform, true); - transform.postTranslate(getOffsetPosition()); - transform.postRotate(getOffsetRotation()); - transform.postScale(getOffsetScale()); - return true; - } -#endif } return false; } diff --git a/interface/src/ui/overlays/PanelAttachable.h b/interface/src/ui/overlays/PanelAttachable.h index 1598aa4700..95faf38cf2 100644 --- a/interface/src/ui/overlays/PanelAttachable.h +++ b/interface/src/ui/overlays/PanelAttachable.h @@ -30,8 +30,6 @@ #ifndef hifi_PanelAttachable_h #define hifi_PanelAttachable_h -#define OVERLAY_PANELS 0 - #include #include @@ -44,18 +42,12 @@ class OverlayPanel; class PanelAttachable { public: // getters -#if OVERLAY_PANELS - std::shared_ptr getParentPanel() const { return _parentPanel; } -#endif glm::vec3 getOffsetPosition() const { return _offset.getTranslation(); } glm::quat getOffsetRotation() const { return _offset.getRotation(); } glm::vec3 getOffsetScale() const { return _offset.getScale(); } bool getParentVisible() const; // setters -#if OVERLAY_PANELS - void setParentPanel(std::shared_ptr panel) { _parentPanel = panel; } -#endif void setOffsetPosition(const glm::vec3& position) { _offset.setTranslation(position); } void setOffsetRotation(const glm::quat& rotation) { _offset.setRotation(rotation); } void setOffsetScale(float scale) { _offset.setScale(scale); } @@ -71,9 +63,6 @@ protected: quint64 _transformExpiry = 0; private: -#if OVERLAY_PANELS - std::shared_ptr _parentPanel = nullptr; -#endif Transform _offset; }; diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp index c535b7e503..e765f3fc18 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp +++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp @@ -127,8 +127,6 @@ const render::ShapeKey Rectangle3DOverlay::getShapeKey() { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Shape3DOverlay.cpp b/interface/src/ui/overlays/Shape3DOverlay.cpp index 1ae0dc6fd3..97342a80ab 100644 --- a/interface/src/ui/overlays/Shape3DOverlay.cpp +++ b/interface/src/ui/overlays/Shape3DOverlay.cpp @@ -128,8 +128,6 @@ void Shape3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index 137d273c7d..3021aa4404 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -47,8 +47,6 @@ Sphere3DOverlay::Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay) : * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index f036516f1e..bed20be698 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -224,8 +224,6 @@ void Text3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 9f0189c047..8121b985cb 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -484,8 +484,6 @@ void Web3DOverlay::setProperties(const QVariantMap& properties) { * the pulse multiplier is applied out of phase with the pulse period. (The magnitude of the property isn't otherwise * used.) * @property {boolean} visible=true - If true, the overlay is rendered, otherwise it is not rendered. - * @property {string} anchor="" - If set to "MyAvatar" then the overlay is attached to your avatar, moving and - * rotating as you move your avatar. * * @property {string} name="" - A friendly name for the overlay. * @property {Vec3} position - The position of the overlay center. Synonyms: p1, point, and diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index 0f9573bb84..95a8a9f1fd 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -328,13 +328,15 @@ void Avatar::updateAvatarEntities() { AvatarEntityIDs recentlyDettachedAvatarEntities = getAndClearRecentlyDetachedIDs(); if (!recentlyDettachedAvatarEntities.empty()) { // only lock this thread when absolutely necessary + AvatarEntityMap avatarEntityData; _avatarEntitiesLock.withReadLock([&] { - foreach (auto entityID, recentlyDettachedAvatarEntities) { - if (!_avatarEntityData.contains(entityID)) { - entityTree->deleteEntity(entityID, true, true); - } - } + avatarEntityData = _avatarEntityData; }); + foreach (auto entityID, recentlyDettachedAvatarEntities) { + if (!avatarEntityData.contains(entityID)) { + entityTree->deleteEntity(entityID, true, true); + } + } // remove stale data hashes foreach (auto entityID, recentlyDettachedAvatarEntities) { diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 722ad416e4..fe5213baa8 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -2086,6 +2086,10 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi EntityDynamicPointer action = _objectActions[actionID]; auto removedActionType = action->getType(); + action->setOwnerEntity(nullptr); + action->setIsMine(false); + _objectActions.remove(actionID); + if ((removedActionType == DYNAMIC_TYPE_HOLD || removedActionType == DYNAMIC_TYPE_FAR_GRAB) && !stillHasGrabActions()) { _dirtyFlags &= ~Simulation::NO_BOOTSTRAPPING; _dirtyFlags |= Simulation::DIRTY_COLLISION_GROUP; // may need to not collide with own avatar @@ -2101,9 +2105,6 @@ bool EntityItem::removeActionInternal(const QUuid& actionID, EntitySimulationPoi // because they should have been set correctly when the action was added // and/or when children were linked } - action->setOwnerEntity(nullptr); - action->setIsMine(false); - _objectActions.remove(actionID); if (simulation) { action->removeFromSimulation(simulation); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index a19ed14d4a..e2a5ddf8b5 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -722,7 +722,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionless, bool, setCollisionless); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(ignoreForCollisions, bool, setCollisionless, getCollisionless); // legacy support COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionMask, uint8_t, setCollisionMask); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(collidesWith, CollisionMask); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(collidesWith, CollisionMask); COPY_PROPERTY_FROM_QSCRIPTVALUE_GETTER(collisionsWillMove, bool, setDynamic, getDynamic); // legacy support COPY_PROPERTY_FROM_QSCRIPTVALUE(dynamic, bool, setDynamic); COPY_PROPERTY_FROM_QSCRIPTVALUE(isSpotlight, bool, setIsSpotlight); @@ -737,7 +737,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(lineHeight, float, setLineHeight); COPY_PROPERTY_FROM_QSCRIPTVALUE(textColor, xColor, setTextColor); COPY_PROPERTY_FROM_QSCRIPTVALUE(backgroundColor, xColor, setBackgroundColor); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(shapeType, ShapeType); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(shapeType, ShapeType); COPY_PROPERTY_FROM_QSCRIPTVALUE(maxParticles, quint32, setMaxParticles); COPY_PROPERTY_FROM_QSCRIPTVALUE(lifespan, float, setLifespan); COPY_PROPERTY_FROM_QSCRIPTVALUE(isEmitting, bool, setIsEmitting); @@ -775,10 +775,10 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName); COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(hazeMode, HazeMode); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(keyLightMode, KeyLightMode); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(ambientLightMode, AmbientLightMode); - COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(skyboxMode, SkyboxMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(hazeMode, HazeMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(keyLightMode, KeyLightMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(ambientLightMode, AmbientLightMode); + COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(skyboxMode, SkyboxMode); COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl); COPY_PROPERTY_FROM_QSCRIPTVALUE(voxelVolumeSize, glmVec3, setVoxelVolumeSize); diff --git a/libraries/entities/src/EntityItemPropertiesMacros.h b/libraries/entities/src/EntityItemPropertiesMacros.h index 278d945ab0..f291973e52 100644 --- a/libraries/entities/src/EntityItemPropertiesMacros.h +++ b/libraries/entities/src/EntityItemPropertiesMacros.h @@ -367,7 +367,7 @@ inline xColor xColor_convertFromScriptValue(const QScriptValue& v, bool& isValid } \ } -#define COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(P, S) \ +#define COPY_PROPERTY_FROM_QSCRIPTVALUE_ENUM(P, S) \ QScriptValue P = object.property(#P); \ if (P.isValid()) { \ QString newValue = P.toVariant().toString(); \ diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 803e4ae9fd..183b3a7bf3 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -19,15 +19,6 @@ #include #include - -#if defined(Q_OS_ANDROID) -#define CPU_MIPMAPS 1 -#else -#define CPU_MIPMAPS 1 -#include -#endif - - #include #include #include @@ -37,6 +28,12 @@ using namespace gpu; +#if defined(Q_OS_ANDROID) +#define CPU_MIPMAPS 1 +#else +#define CPU_MIPMAPS 1 +#include +#endif static const glm::uvec2 SPARSE_PAGE_SIZE(128); static const glm::uvec2 MAX_TEXTURE_SIZE(4096); @@ -51,25 +48,21 @@ static std::atomic compressNormalTextures { false }; static std::atomic compressGrayscaleTextures { false }; static std::atomic compressCubeTextures { false }; -bool needsSparseRectification(const glm::uvec2& size) { - // Don't attempt to rectify small textures (textures less than the sparse page size in any dimension) - if (glm::any(glm::lessThan(size, SPARSE_PAGE_SIZE))) { - return false; +uint rectifyDimension(const uint& dimension) { + if (dimension < SPARSE_PAGE_SIZE.x) { + uint newSize = SPARSE_PAGE_SIZE.x; + while (dimension <= newSize / 2) { + newSize /= 2; + } + return newSize; + } else { + uint pages = (dimension / SPARSE_PAGE_SIZE.x) + (dimension % SPARSE_PAGE_SIZE.x == 0 ? 0 : 1); + return pages * SPARSE_PAGE_SIZE.x; } - - // Don't rectify textures that are already an exact multiple of sparse page size - if (glm::uvec2(0) == (size % SPARSE_PAGE_SIZE)) { - return false; - } - - // Texture is not sparse compatible, but is bigger than the sparse page size in both dimensions, rectify! - return true; } -glm::uvec2 rectifyToSparseSize(const glm::uvec2& size) { - glm::uvec2 pages = ((size / SPARSE_PAGE_SIZE) + glm::clamp(size % SPARSE_PAGE_SIZE, glm::uvec2(0), glm::uvec2(1))); - glm::uvec2 result = pages * SPARSE_PAGE_SIZE; - return result; +glm::uvec2 rectifySize(const glm::uvec2& size) { + return { rectifyDimension(size.x), rectifyDimension(size.y) }; } @@ -329,9 +322,12 @@ QImage processSourceImage(QImage&& srcImage, bool cubemap) { ++DECIMATED_TEXTURE_COUNT; } - if (!cubemap && needsSparseRectification(targetSize)) { - ++RECTIFIED_TEXTURE_COUNT; - targetSize = rectifyToSparseSize(targetSize); + if (!cubemap) { + auto rectifiedSize = rectifySize(targetSize); + if (rectifiedSize != targetSize) { + ++RECTIFIED_TEXTURE_COUNT; + targetSize = rectifiedSize; + } } if (DEV_DECIMATE_TEXTURES && glm::all(glm::greaterThanEqual(targetSize / SPARSE_PAGE_SIZE, glm::uvec2(2)))) { diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index 7302e0e997..0173a1fad7 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -73,6 +73,7 @@ public: * Get Interface's protocol version. * @function location.protocolVersion * @returns {string} A string uniquely identifying the version of the metaverse protocol that Interface is using. + * @deprecated This function is deprecated and will be removed. Use {@link Window.protocolSignature} instead. */ Q_INVOKABLE QString protocolVersion(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 1b80c3b3af..0950cb5556 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -63,13 +63,6 @@ LimitedNodeList::LimitedNodeList(int socketListenPort, int dtlsListenPort) : _packetStatTimer(), _permissions(NodePermissions()) { - static bool firstCall = true; - if (firstCall) { - NodeType::init(); - - firstCall = false; - } - qRegisterMetaType("ConnectionStep"); auto port = (socketListenPort != INVALID_PORT) ? socketListenPort : LIMITED_NODELIST_LOCAL_PORT.get(); _nodeSocket.bind(QHostAddress::AnyIPv4, port); diff --git a/libraries/networking/src/Node.cpp b/libraries/networking/src/Node.cpp index 25eef38dbd..bd895c8ef1 100644 --- a/libraries/networking/src/Node.cpp +++ b/libraries/networking/src/Node.cpp @@ -29,28 +29,25 @@ int NodePtrMetaTypeId = qRegisterMetaType("Node*"); int sharedPtrNodeMetaTypeId = qRegisterMetaType>("QSharedPointer"); int sharedNodePtrMetaTypeId = qRegisterMetaType("SharedNodePointer"); -void NodeType::init() { - QHash& TypeNameHash = Node::getTypeNameHash(); - - TypeNameHash.insert(NodeType::DomainServer, "Domain Server"); - TypeNameHash.insert(NodeType::EntityServer, "Entity Server"); - TypeNameHash.insert(NodeType::Agent, "Agent"); - TypeNameHash.insert(NodeType::AudioMixer, "Audio Mixer"); - TypeNameHash.insert(NodeType::AvatarMixer, "Avatar Mixer"); - TypeNameHash.insert(NodeType::MessagesMixer, "Messages Mixer"); - TypeNameHash.insert(NodeType::AssetServer, "Asset Server"); - TypeNameHash.insert(NodeType::EntityScriptServer, "Entity Script Server"); - TypeNameHash.insert(NodeType::UpstreamAudioMixer, "Upstream Audio Mixer"); - TypeNameHash.insert(NodeType::UpstreamAvatarMixer, "Upstream Avatar Mixer"); - TypeNameHash.insert(NodeType::DownstreamAudioMixer, "Downstream Audio Mixer"); - TypeNameHash.insert(NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer"); - TypeNameHash.insert(NodeType::Unassigned, "Unassigned"); -} +static const QHash TYPE_NAME_HASH { + { NodeType::DomainServer, "Domain Server" }, + { NodeType::EntityServer, "Entity Server" }, + { NodeType::Agent, "Agent" }, + { NodeType::AudioMixer, "Audio Mixer" }, + { NodeType::AvatarMixer, "Avatar Mixer" }, + { NodeType::MessagesMixer, "Messages Mixer" }, + { NodeType::AssetServer, "Asset Server" }, + { NodeType::EntityScriptServer, "Entity Script Server" }, + { NodeType::UpstreamAudioMixer, "Upstream Audio Mixer" }, + { NodeType::UpstreamAvatarMixer, "Upstream Avatar Mixer" }, + { NodeType::DownstreamAudioMixer, "Downstream Audio Mixer" }, + { NodeType::DownstreamAvatarMixer, "Downstream Avatar Mixer" }, + { NodeType::Unassigned, "Unassigned" } +}; const QString& NodeType::getNodeTypeName(NodeType_t nodeType) { - QHash& TypeNameHash = Node::getTypeNameHash(); - QHash::iterator matchedTypeName = TypeNameHash.find(nodeType); - return matchedTypeName != TypeNameHash.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME; + const auto matchedTypeName = TYPE_NAME_HASH.find(nodeType); + return matchedTypeName != TYPE_NAME_HASH.end() ? matchedTypeName.value() : UNKNOWN_NodeType_t_NAME; } bool NodeType::isUpstream(NodeType_t nodeType) { @@ -84,8 +81,7 @@ NodeType_t NodeType::downstreamType(NodeType_t primaryType) { } NodeType_t NodeType::fromString(QString type) { - QHash& TypeNameHash = Node::getTypeNameHash(); - return TypeNameHash.key(type, NodeType::Unassigned); + return TYPE_NAME_HASH.key(type, NodeType::Unassigned); } diff --git a/libraries/networking/src/Node.h b/libraries/networking/src/Node.h index 00d3c61fd0..93b6a649d4 100644 --- a/libraries/networking/src/Node.h +++ b/libraries/networking/src/Node.h @@ -89,11 +89,6 @@ public: bool isIgnoreRadiusEnabled() const { return _ignoreRadiusEnabled; } - static QHash& getTypeNameHash() { - static QHash TypeNameHash; - return TypeNameHash; - } - private: // privatize copy and assignment operator to disallow Node copying Node(const Node &otherNode); diff --git a/libraries/networking/src/NodeType.h b/libraries/networking/src/NodeType.h index 0130e92cfc..2b2cc4e011 100644 --- a/libraries/networking/src/NodeType.h +++ b/libraries/networking/src/NodeType.h @@ -31,8 +31,6 @@ namespace NodeType { const NodeType_t DownstreamAvatarMixer = 'w'; const NodeType_t Unassigned = 1; - void init(); - const QString& getNodeTypeName(NodeType_t nodeType); bool isUpstream(NodeType_t nodeType); bool isDownstream(NodeType_t nodeType); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index b46b267ff6..a3c01f7fb3 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -319,11 +319,13 @@ void DrawDeferred::run(const RenderContextPointer& renderContext, const Inputs& // Setup lighting model for all items; batch.setUniformBuffer(render::ShapePipeline::Slot::LIGHTING_MODEL, lightingModel->getParametersBuffer()); - // Setup haze iff curretn zone has haze + // Setup haze iff current zone has haze auto hazeStage = args->_scene->getStage(); if (hazeStage && hazeStage->_currentFrame._hazes.size() > 0) { graphics::HazePointer hazePointer = hazeStage->getHaze(hazeStage->_currentFrame._hazes.front()); - batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer()); + if (hazePointer) { + batch.setUniformBuffer(render::ShapePipeline::Slot::HAZE_MODEL, hazePointer->getHazeParametersBuffer()); + } } // From the lighting model define a global shapKey ORED with individiual keys diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index b010657049..eb279f18af 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -87,7 +87,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), Slot::MAP::LIGHT_AMBIENT)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeMaskMap"), Slot::MAP::FADE_MASK)); slotBindings.insert(gpu::Shader::Binding(std::string("fadeParametersBuffer"), Slot::BUFFER::FADE_PARAMETERS)); - slotBindings.insert(gpu::Shader::Binding(std::string("hazeParametersBuffer"), Slot::BUFFER::HAZE_MODEL)); + slotBindings.insert(gpu::Shader::Binding(std::string("hazeBuffer"), Slot::BUFFER::HAZE_MODEL)); gpu::Shader::makeProgram(*program, slotBindings); diff --git a/scripts/developer/utilities/render/lod.js b/scripts/developer/utilities/render/lod.js new file mode 100644 index 0000000000..dc0b99edc2 --- /dev/null +++ b/scripts/developer/utilities/render/lod.js @@ -0,0 +1,77 @@ +"use strict"; + +// +// lodi.js +// tablet-engine app +// +// 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 +// + +(function() { + var TABLET_BUTTON_NAME = "LOD"; + var QMLAPP_URL = Script.resolvePath("./lod.qml"); + var ICON_URL = Script.resolvePath("../../../system/assets/images/lod-i.svg"); + var ACTIVE_ICON_URL = Script.resolvePath("../../../system/assets/images/lod-a.svg"); + + var onScreen = false; + + function onClicked() { + if (onScreen) { + tablet.gotoHomeScreen(); + } else { + tablet.loadQMLSource(QMLAPP_URL); + } + } + + var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system"); + var button = tablet.addButton({ + text: TABLET_BUTTON_NAME, + icon: ICON_URL, + activeIcon: ACTIVE_ICON_URL, + sortOrder: 1 + }); + + var hasEventBridge = false; + + function wireEventBridge(on) { + if (!tablet) { + print("Warning in wireEventBridge(): 'tablet' undefined!"); + return; + } + if (on) { + if (!hasEventBridge) { + tablet.fromQml.connect(fromQml); + hasEventBridge = true; + } + } else { + if (hasEventBridge) { + tablet.fromQml.disconnect(fromQml); + hasEventBridge = false; + } + } + } + + function onScreenChanged(type, url) { + onScreen = (url === QMLAPP_URL); + button.editProperties({isActive: onScreen}); + wireEventBridge(onScreen); + } + + function fromQml(message) { + } + + button.clicked.connect(onClicked); + tablet.screenChanged.connect(onScreenChanged); + + Script.scriptEnding.connect(function () { + if (onScreen) { + tablet.gotoHomeScreen(); + } + button.clicked.disconnect(onClicked); + tablet.screenChanged.disconnect(onScreenChanged); + tablet.removeButton(button); + }); +}()); diff --git a/scripts/developer/utilities/render/lod.qml b/scripts/developer/utilities/render/lod.qml new file mode 100644 index 0000000000..d7b9f1cd57 --- /dev/null +++ b/scripts/developer/utilities/render/lod.qml @@ -0,0 +1,92 @@ +// +// lod.qml +// scripts/developer/utilities/render +// +// Created by Andrew Meadows on 2018.01.10 +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or https://www.apache.org/licenses/LICENSE-2.0.html +// +import QtQuick 2.5 +import QtQuick.Controls 1.4 +import "../lib/plotperf" + +Item { + id: lodIU + anchors.fill:parent + + Column { + id: stats + spacing: 8 + anchors.fill:parent + + function evalEvenHeight() { + // Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ? + return (height - spacing * (children.length - 1)) / children.length + } + + PlotPerf { + title: "Load Indicators" + height: parent.evalEvenHeight() + object: LODManager + valueScale: 1 + valueUnit: "ms" + plots: [ + { + prop: "presentTime", + label: "present", + color: "#FFFF00" + }, + { + prop: "engineRunTime", + label: "engineRun", + color: "#FF00FF" + }, + { + prop: "gpuTime", + label: "gpu", + color: "#00FFFF" + } + ] + } + PlotPerf { + title: "FPS" + height: parent.evalEvenHeight() + object: LODManager + valueScale: 1 + valueUnit: "Hz" + plots: [ + { + prop: "lodIncreaseFPS", + label: "LOD++", + color: "#66FF66" + }, + { + prop: "fps", + label: "FPS", + color: "#FFFFFF" + }, + { + prop: "lodDecreaseFPS", + label: "LOD--", + color: "#FF6666" + } + ] + } + PlotPerf { + title: "LOD" + height: parent.evalEvenHeight() + object: LODManager + valueScale: 0.1 + valueUnit: "" + plots: [ + { + prop: "lodLevel", + label: "LOD", + color: "#9999FF" + } + ] + } + } +} diff --git a/scripts/system/assets/images/lod-a.svg b/scripts/system/assets/images/lod-a.svg new file mode 100644 index 0000000000..6845e0ff78 --- /dev/null +++ b/scripts/system/assets/images/lod-a.svg @@ -0,0 +1,46 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/scripts/system/assets/images/lod-i.svg b/scripts/system/assets/images/lod-i.svg new file mode 100644 index 0000000000..f909f3b495 --- /dev/null +++ b/scripts/system/assets/images/lod-i.svg @@ -0,0 +1,46 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/scripts/system/tablet-goto.js b/scripts/system/tablet-goto.js index 2a0e827932..43dae9625a 100644 --- a/scripts/system/tablet-goto.js +++ b/scripts/system/tablet-goto.js @@ -136,7 +136,7 @@ 'include_actions=' + actions, 'restriction=' + (Account.isLoggedIn() ? 'open,hifi' : 'open'), 'require_online=true', - 'protocol=' + encodeURIComponent(location.protocolVersion()), + 'protocol=' + encodeURIComponent(Window.protocolSignature()), 'per_page=' + count ]; var url = Account.metaverseServerURL + '/api/v1/user_stories?' + options.join('&'); diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index d37be7c790..6a509afe4e 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -163,46 +163,31 @@ class MyTestWindow : public TestWindow { } }; -extern bool needsSparseRectification(const uvec2& size); -extern uvec2 rectifyToSparseSize(const uvec2& size); +extern uvec2 rectifySize(const uvec2& size); void testSparseRectify() { - std::vector> NEEDS_SPARSE_TESTS {{ + std::vector> SPARSE_SIZE_TESTS { // Already sparse - { {1024, 1024 }, false }, - { { 128, 128 }, false }, + { {1024, 1024 }, { 1024, 1024 } }, + { { 128, 128 }, { 128, 128 } }, // Too small in one dimension - { { 127, 127 }, false }, - { { 1, 1 }, false }, - { { 1000, 1 }, false }, - { { 1024, 1 }, false }, - { { 100, 100 }, false }, - // needs rectification - { { 1000, 1000 }, true }, - { { 1024, 1000 }, true }, - } }; - - for (const auto& test : NEEDS_SPARSE_TESTS) { - const auto& size = test.first; - const auto& expected = test.second; - auto result = needsSparseRectification(size); - Q_ASSERT(expected == result); - result = needsSparseRectification(uvec2(size.y, size.x)); - Q_ASSERT(expected == result); - } - - std::vector> SPARSE_SIZE_TESTS { { + { { 127, 127 }, { 128, 128 } }, + { { 1, 1 }, { 1, 1 } }, + { { 1000, 1 }, { 1024, 1 } }, + { { 1024, 1 }, { 1024, 1 } }, + { { 100, 100 }, { 128, 128 } }, + { { 57, 510 }, { 64, 512 } }, // needs rectification { { 1000, 1000 }, { 1024, 1024 } }, { { 1024, 1000 }, { 1024, 1024 } }, - } }; + }; for (const auto& test : SPARSE_SIZE_TESTS) { const auto& size = test.first; const auto& expected = test.second; - auto result = rectifyToSparseSize(size); + auto result = rectifySize(size); Q_ASSERT(expected == result); - result = rectifyToSparseSize(uvec2(size.y, size.x)); + result = rectifySize(uvec2(size.y, size.x)); Q_ASSERT(expected == uvec2(result.y, result.x)); } } diff --git a/tools/auto-tester/CMakeLists.txt b/tools/auto-tester/CMakeLists.txt index e5f2c1fb97..a875f5676a 100644 --- a/tools/auto-tester/CMakeLists.txt +++ b/tools/auto-tester/CMakeLists.txt @@ -1,47 +1,41 @@ -set(TARGET_NAME auto-tester) +set (TARGET_NAME auto-tester) project(${TARGET_NAME}) # Automatically run UIC and MOC. This replaces the older WRAP macros -SET(CMAKE_AUTOUIC ON) -SET(CMAKE_AUTOMOC ON) +SET (CMAKE_AUTOUIC ON) +SET (CMAKE_AUTOMOC ON) -setup_hifi_project(Core Widgets) -link_hifi_libraries() +setup_hifi_project (Core Widgets) +link_hifi_libraries () # FIX: Qt was built with -reduce-relocations if (Qt5_POSITION_INDEPENDENT_CODE) - SET(CMAKE_POSITION_INDEPENDENT_CODE ON) + SET (CMAKE_POSITION_INDEPENDENT_CODE ON) endif() # Qt includes -include_directories(${CMAKE_CURRENT_SOURCE_DIR}) -include_directories(${Qt5Core_INCLUDE_DIRS}) -include_directories(${Qt5Widgets_INCLUDE_DIRS}) +include_directories (${CMAKE_CURRENT_SOURCE_DIR}) +include_directories (${Qt5Core_INCLUDE_DIRS}) +include_directories (${Qt5Widgets_INCLUDE_DIRS}) -set(QT_LIBRARIES Qt5::Core Qt5::Widgets) - -# Find all sources files -file (GLOB_RECURSE SOURCES src/*.cpp) -file (GLOB_RECURSE HEADERS src/*.h) -file (GLOB_RECURSE UIS src/ui/*.ui) +set (QT_LIBRARIES Qt5::Core Qt5::Widgets) if (WIN32) # Do not show Console - set_property(TARGET auto-tester PROPERTY WIN32_EXECUTABLE true) + set_property (TARGET auto-tester PROPERTY WIN32_EXECUTABLE true) endif() -add_executable(PROJECT_NAME ${SOURCES} ${HEADERS} ${UIS}) +target_zlib() +add_dependency_external_projects (quazip) +find_package (QuaZip REQUIRED) +target_include_directories( ${TARGET_NAME} SYSTEM PUBLIC ${QUAZIP_INCLUDE_DIRS}) +target_link_libraries(${TARGET_NAME} ${QUAZIP_LIBRARIES}) -target_link_libraries(PROJECT_NAME ${QT_LIBRARIES}) - -# Copy required dll's. -add_custom_command(TARGET auto-tester POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ - COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ -) +package_libraries_for_deployment() if (WIN32) + add_paths_to_fixup_libs (${QUAZIP_DLL_PATH}) + find_program(WINDEPLOYQT_COMMAND windeployqt PATHS ${QT_DIR}/bin NO_DEFAULT_PATH) if (NOT WINDEPLOYQT_COMMAND) diff --git a/tools/auto-tester/src/ImageComparer.cpp b/tools/auto-tester/src/ImageComparer.cpp index 121c98e16e..94b95a5ab6 100644 --- a/tools/auto-tester/src/ImageComparer.cpp +++ b/tools/auto-tester/src/ImageComparer.cpp @@ -8,6 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #include "ImageComparer.h" +#include "common.h" #include @@ -26,11 +27,6 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co const double c1 = pow((K1 * L), 2); const double c2 = pow((K2 * L), 2); - // Coefficients for luminosity calculation - const double R_Y = 0.212655f; - const double G_Y = 0.715158f; - const double B_Y = 0.072187f; - // First go over all full 8x8 blocks // This is done in 3 loops // 1) Read the pixels into a linear array (an optimization) @@ -116,4 +112,4 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co } return ssim / windowCounter; -}; +}; \ No newline at end of file diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 8cb36fcfca..6c637ab404 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -13,18 +13,62 @@ #include #include +#include +#include + Test::Test() { - snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.+-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg"); + snapshotFilenameFormat = QRegularExpression("hifi-snap-by-.*-on-\\d\\d\\d\\d-\\d\\d-\\d\\d_\\d\\d-\\d\\d-\\d\\d.jpg"); expectedImageFilenameFormat = QRegularExpression("ExpectedImage_\\d+.jpg"); mismatchWindow.setModal(true); } -bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages) { +bool Test::createTestResultsFolderPathIfNeeded(QString directory) { + // The test results folder is located in the root of the tests (i.e. for recursive test evaluation) + if (testResultsFolderPath == "") { + testResultsFolderPath = directory + "/" + TEST_RESULTS_FOLDER; + QDir testResultsFolder(testResultsFolderPath); + + if (testResultsFolder.exists()) { + testResultsFolder.removeRecursively(); + } + + // Create a new test results folder + return QDir().mkdir(testResultsFolderPath); + } else { + return true; + } +} + +void Test::zipAndDeleteTestResultsFolder() { + QString zippedResultsFileName { testResultsFolderPath + ".zip" }; + QFileInfo fileInfo(zippedResultsFileName); + if (!fileInfo.exists()) { + QFile::remove(zippedResultsFileName); + } + + QDir testResultsFolder(testResultsFolderPath); + if (!testResultsFolder.isEmpty()) { + JlCompress::compressDir(testResultsFolderPath + ".zip", testResultsFolderPath); + } + + testResultsFolder.removeRecursively(); + + //In all cases, for the next evaluation + testResultsFolderPath = ""; + index = 1; +} + +bool Test::compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar) { + progressBar->setMinimum(0); + progressBar->setMaximum(expectedImages.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. - const double THRESHOLD{ 0.999 }; + const double THRESHOLD { 0.999 }; bool success{ true }; bool keepOn{ true }; for (int i = 0; keepOn && i < expectedImages.length(); ++i) { @@ -45,42 +89,107 @@ bool Test::compareImageLists(QStringList expectedImages, QStringList resultImage } if (similarityIndex < THRESHOLD) { - mismatchWindow.setTestFailure(TestFailure{ + TestFailure testFailure = TestFailure{ (float)similarityIndex, expectedImages[i].left(expectedImages[i].lastIndexOf("/") + 1), // path to the test (including trailing /) QFileInfo(expectedImages[i].toStdString().c_str()).fileName(), // filename of expected image QFileInfo(resultImages[i].toStdString().c_str()).fileName() // filename of result image - }); + }; - mismatchWindow.exec(); + mismatchWindow.setTestFailure(testFailure); - switch (mismatchWindow.getUserResponse()) { - case USER_RESPONSE_PASS: - break; - case USE_RESPONSE_FAIL: - success = false; - break; - case USER_RESPONSE_ABORT: - keepOn = false; - success = false; - break; - default: - assert(false); - break; + if (!interactiveMode) { + appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage()); + success = false; + } else { + mismatchWindow.exec(); + + switch (mismatchWindow.getUserResponse()) { + case USER_RESPONSE_PASS: + break; + case USE_RESPONSE_FAIL: + appendTestResultsToFile(testResultsFolderPath, testFailure, mismatchWindow.getComparisonImage()); + success = false; + break; + case USER_RESPONSE_ABORT: + keepOn = false; + success = false; + break; + default: + assert(false); + break; + } } } + + progressBar->setValue(i); } + progressBar->setVisible(false); return success; } -void Test::evaluateTests() { +void Test::appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage) { + if (!QDir().exists(testResultsFolderPath)) { + messageBox.critical(0, "Internal error", "Folder " + testResultsFolderPath + " not found"); + exit(-1); + } + + QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) }; + if (!QDir().mkdir(failureFolderPath)) { + messageBox.critical(0, "Internal error", "Failed to create folder " + failureFolderPath); + exit(-1); + } + ++index; + + QFile descriptionFile(failureFolderPath + "/" + TEST_RESULTS_FILENAME); + if (!descriptionFile.open(QIODevice::ReadWrite)) { + messageBox.critical(0, "Internal error", "Failed to create file " + TEST_RESULTS_FILENAME); + exit(-1); + } + + // 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; + + descriptionFile.close(); + + // Copy expected and actual images, and save the difference image + QString sourceFile; + QString destinationFile; + + sourceFile = testFailure._pathname + testFailure._expectedImageFilename; + destinationFile = failureFolderPath + "/" + "Expected Image.jpg"; + if (!QFile::copy(sourceFile, destinationFile)) { + messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + exit(-1); + } + + sourceFile = testFailure._pathname + testFailure._actualImageFilename; + destinationFile = failureFolderPath + "/" + "Actual Image.jpg"; + if (!QFile::copy(sourceFile, destinationFile)) { + messageBox.critical(0, "Internal error", "Failed to copy " + sourceFile + " to " + destinationFile); + exit(-1); + } + + comparisonImage.save(failureFolderPath + "/" + "Difference Image.jpg"); +} + +void Test::evaluateTests(bool interactiveMode, QProgressBar* progressBar) { // Get list of JPEG images in folder, sorted by name QString pathToImageDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder containing the test images", ".", QFileDialog::ShowDirsOnly); if (pathToImageDirectory == "") { return; } + // Leave if test results folder could not be created + if (!createTestResultsFolderPathIfNeeded(pathToImageDirectory)) { + return; + } + QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(pathToImageDirectory); // Separate images into two lists. The first is the expected images, the second is the test results @@ -107,36 +216,57 @@ void Test::evaluateTests() { exit(-1); } - bool success = compareImageLists(expectedImages, resultImages); + bool success = compareImageLists(expectedImages, resultImages, pathToImageDirectory, interactiveMode, progressBar); if (success) { messageBox.information(0, "Success", "All images are as expected"); } else { messageBox.information(0, "Failure", "One or more images are not as expected"); } + + zipAndDeleteTestResultsFolder(); +} + +bool Test::isAValidDirectory(QString pathname) { + // Only process directories + QDir dir(pathname); + if (!dir.exists()) { + return false; + } + + // Ignore '.', '..' directories + if (pathname[pathname.length() - 1] == '.') { + return false; + } + + return true; } // Two criteria are used to decide if a folder contains valid test results. // 1) a 'test'js' file exists in the folder // 2) the folder has the same number of actual and expected images -void Test::evaluateTestsRecursively() { +void Test::evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar) { // Select folder to start recursing from QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select folder that will contain the top level test script", ".", QFileDialog::ShowDirsOnly); if (topLevelDirectory == "") { return; } + // Leave if test results folder could not be created + if (!createTestResultsFolderPathIfNeeded(topLevelDirectory)) { + return; + } + bool success{ true }; QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); - if (directory[directory.length() - 1] == '.') { - // ignore '.', '..' directories + + if (!isAValidDirectory(directory)) { continue; } - // - const QString testPathname{ directory + "/" + testFilename }; + const QString testPathname{ directory + "/" + TEST_FILENAME }; QFileInfo fileInfo(testPathname); if (!fileInfo.exists()) { // Folder does not contain 'test.js' @@ -164,7 +294,7 @@ void Test::evaluateTestsRecursively() { } // Set success to false if any test has failed - success &= compareImageLists(expectedImages, resultImages); + success &= compareImageLists(expectedImages, resultImages, directory, interactiveMode, progressBar); } if (success) { @@ -172,6 +302,8 @@ void Test::evaluateTestsRecursively() { } else { messageBox.information(0, "Failure", "One or more images are not as expected"); } + + zipAndDeleteTestResultsFolder(); } void Test::importTest(QTextStream& textStream, const QString& testPathname, int testNumber) { @@ -191,7 +323,8 @@ void Test::createRecursiveScript() { if (!allTestsFilename.open(QIODevice::WriteOnly | QIODevice::Text)) { messageBox.critical(0, "Internal Error", - "Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\""); + "Failed to create \"allTests.js\" in directory \"" + topLevelDirectory + "\"" + ); exit(-1); } @@ -206,7 +339,7 @@ void Test::createRecursiveScript() { QVector testPathnames; // First test if top-level folder has a test.js file - const QString testPathname{ topLevelDirectory + "/" + testFilename }; + const QString testPathname{ topLevelDirectory + "/" + TEST_FILENAME }; QFileInfo fileInfo(testPathname); if (fileInfo.exists()) { // Current folder contains a test @@ -219,12 +352,14 @@ void Test::createRecursiveScript() { QDirIterator it(topLevelDirectory.toStdString().c_str(), QDirIterator::Subdirectories); while (it.hasNext()) { QString directory = it.next(); - if (directory[directory.length() - 1] == '.') { - // ignore '.', '..' directories + + // Only process directories + QDir dir(directory); + if (!isAValidDirectory(directory)) { continue; } - const QString testPathname{ directory + "/" + testFilename }; + const QString testPathname{ directory + "/" + TEST_FILENAME }; QFileInfo fileInfo(testPathname); if (fileInfo.exists()) { // Current folder contains a test @@ -264,7 +399,7 @@ void Test::createRecursiveScript() { // The script produced will look as follows: // if (test1HasNotStarted) { // test1HasNotStarted = false; - // test1.test(); + // test1.test("auto"); // print("******started test 1******"); // } // | @@ -287,7 +422,7 @@ void Test::createRecursiveScript() { textStream << tab << tab << "if (test" << i - 1 << ".complete && test" << i << "HasNotStarted) {" << endl; } textStream << tab << tab << tab << "test" << i << "HasNotStarted = false;" << endl; - textStream << tab << tab << tab << "test" << i << "." << testFunction << "();" << endl; + textStream << tab << tab << tab << "test" << i << "." << testFunction << "(\"auto\");" << endl; textStream << tab << tab << tab << "print(\"******started test " << i << "******\");" << endl; textStream << tab << tab << "}" << endl << endl; @@ -366,6 +501,41 @@ void Test::createTest() { messageBox.information(0, "Success", "Test images have been created"); } +void Test::deleteOldSnapshots() { + // Select folder to start recursing from + QString topLevelDirectory = QFileDialog::getExistingDirectory(nullptr, "Please select root folder for snapshot deletion", ".", QFileDialog::ShowDirsOnly); + if (topLevelDirectory == "") { + return; + } + + // Recurse over folders + 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; + } + + QStringList sortedImageFilenames = createListOfAllJPEGimagesInDirectory(directory); + + // Delete any file that is a snapshot (NOT the Expected Images) + QStringList expectedImages; + QStringList resultImages; + foreach(QString currentFilename, sortedImageFilenames) { + QString fullCurrentFilename = directory + "/" + currentFilename; + if (isInSnapshotFilenameFormat(currentFilename)) { + if (!QFile::remove(fullCurrentFilename)) { + messageBox.critical(0, "Error", "Could not delete existing file: " + currentFilename + "\nSnapshot deletion aborted"); + exit(-1); + } + } + } + } +} + QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory) { imageDirectory = QDir(pathToImageDirectory); QStringList nameFilters; @@ -374,6 +544,7 @@ QStringList Test::createListOfAllJPEGimagesInDirectory(QString pathToImageDirect return imageDirectory.entryList(nameFilters, QDir::Files, QDir::Name); } +// Use regular expressions to check if files are in specific format bool Test::isInSnapshotFilenameFormat(QString filename) { return (snapshotFilenameFormat.match(filename).hasMatch()); } diff --git a/tools/auto-tester/src/Test.h b/tools/auto-tester/src/Test.h index 1f7b1e92a7..aa1346fa2a 100644 --- a/tools/auto-tester/src/Test.h +++ b/tools/auto-tester/src/Test.h @@ -1,6 +1,5 @@ // // Test.h -// zone/ambientLightInheritence // // Created by Nissim Hadar on 2 Nov 2017. // Copyright 2013 High Fidelity, Inc. @@ -15,6 +14,7 @@ #include #include #include +#include #include "ImageComparer.h" #include "ui/MismatchWindow.h" @@ -23,10 +23,13 @@ class Test { public: Test(); - void evaluateTests(); - void evaluateTestsRecursively(); + void evaluateTests(bool interactiveMode, QProgressBar* progressBar); + void evaluateTestsRecursively(bool interactiveMode, QProgressBar* progressBar); void createRecursiveScript(); void createTest(); + void deleteOldSnapshots(); + + bool compareImageLists(QStringList expectedImages, QStringList resultImages, QString testDirectory, bool interactiveMode, QProgressBar* progressBar); QStringList createListOfAllJPEGimagesInDirectory(QString pathToImageDirectory); @@ -35,8 +38,17 @@ public: void importTest(QTextStream& textStream, const QString& testPathname, int testNumber); + void appendTestResultsToFile(QString testResultsFolderPath, TestFailure testFailure, QPixmap comparisonImage); + + bool createTestResultsFolderPathIfNeeded(QString directory); + void zipAndDeleteTestResultsFolder(); + + bool isAValidDirectory(QString pathname); + private: - const QString testFilename{ "test.js" }; + const QString TEST_FILENAME { "test.js" }; + const QString TEST_RESULTS_FOLDER { "TestResults" }; + const QString TEST_RESULTS_FILENAME { "TestResults.txt" }; QMessageBox messageBox; @@ -49,7 +61,9 @@ private: ImageComparer imageComparer; - bool compareImageLists(QStringList expectedImages, QStringList resultImages); + + QString testResultsFolderPath { "" }; + int index { 1 }; }; -#endif // hifi_test_h +#endif // hifi_test_h \ No newline at end of file diff --git a/tools/auto-tester/src/common.h b/tools/auto-tester/src/common.h index 126177358f..939814df62 100644 --- a/tools/auto-tester/src/common.h +++ b/tools/auto-tester/src/common.h @@ -34,4 +34,9 @@ enum UserResponse { USER_RESPONSE_ABORT }; -#endif // hifi_common_h +// Coefficients for luminosity calculation +const double R_Y = 0.212655f; +const double G_Y = 0.715158f; +const double B_Y = 0.072187f; + +#endif // hifi_common_h \ No newline at end of file diff --git a/tools/auto-tester/src/main.cpp b/tools/auto-tester/src/main.cpp index 6e5e06b732..45a3743482 100644 --- a/tools/auto-tester/src/main.cpp +++ b/tools/auto-tester/src/main.cpp @@ -17,4 +17,4 @@ int main(int argc, char *argv[]) { autoTester.show(); return application.exec(); -} +} \ No newline at end of file diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index 105baddb92..2834ff81e0 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -12,14 +12,18 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); + + ui.checkBoxInteractiveMode->setChecked(true); + + ui.progressBar->setVisible(false); } void AutoTester::on_evaluateTestsButton_clicked() { - test.evaluateTests(); + test.evaluateTests(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_evaluateTestsRecursivelyButton_clicked() { - test.evaluateTestsRecursively(); + test.evaluateTestsRecursively(ui.checkBoxInteractiveMode->isChecked(), ui.progressBar); } void AutoTester::on_createRecursiveScriptButton_clicked() { @@ -30,6 +34,10 @@ void AutoTester::on_createTestButton_clicked() { test.createTest(); } +void AutoTester::on_deleteOldSnapshotsButton_clicked() { + test.deleteOldSnapshots(); +} + void AutoTester::on_closeButton_clicked() { exit(0); } \ 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 acfea32ba1..35f609a89d 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -1,6 +1,5 @@ // // AutoTester.h -// zone/ambientLightInheritence // // Created by Nissim Hadar on 2 Nov 2017. // Copyright 2013 High Fidelity, Inc. @@ -22,10 +21,11 @@ public: AutoTester(QWidget *parent = Q_NULLPTR); private slots: -void on_evaluateTestsButton_clicked(); -void on_evaluateTestsRecursivelyButton_clicked(); -void on_createRecursiveScriptButton_clicked(); + void on_evaluateTestsButton_clicked(); + void on_evaluateTestsRecursivelyButton_clicked(); + void on_createRecursiveScriptButton_clicked(); void on_createTestButton_clicked(); + void on_deleteOldSnapshotsButton_clicked(); void on_closeButton_clicked(); private: diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index 7032ef9710..d06255acf6 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -6,8 +6,8 @@ 0 0 - 286 - 470 + 607 + 395 @@ -17,9 +17,9 @@ - 60 - 360 - 160 + 190 + 300 + 220 40 @@ -30,9 +30,9 @@ - 60 - 270 - 160 + 360 + 130 + 220 40 @@ -43,9 +43,9 @@ - 60 - 20 - 160 + 20 + 75 + 220 40 @@ -56,9 +56,9 @@ - 60 - 210 - 160 + 360 + 75 + 220 40 @@ -69,9 +69,9 @@ - 60 - 75 - 160 + 20 + 130 + 220 40 @@ -79,13 +79,55 @@ Evaluate Tests Recursively + + + + 23 + 40 + 131 + 20 + + + + <html><head/><body><p>If unchecked, will not show results during evaluation</p></body></html> + + + Interactive Mode + + + + + + 20 + 190 + 255 + 23 + + + + 24 + + + + + + 360 + 240 + 220 + 40 + + + + Delete Old Snapshots + + 0 0 - 286 + 607 21 @@ -103,4 +145,4 @@ - + \ No newline at end of file diff --git a/tools/auto-tester/src/ui/MismatchWindow.cpp b/tools/auto-tester/src/ui/MismatchWindow.cpp index 07664a1667..d880a1abdc 100644 --- a/tools/auto-tester/src/ui/MismatchWindow.cpp +++ b/tools/auto-tester/src/ui/MismatchWindow.cpp @@ -11,11 +11,48 @@ #include +#include + MismatchWindow::MismatchWindow(QWidget *parent) : QDialog(parent) { setupUi(this); expectedImage->setScaledContents(true); resultImage->setScaledContents(true); + diffImage->setScaledContents(true); +} + +QPixmap MismatchWindow::computeDiffPixmap(QImage expectedImage, QImage resultImage) { + // This is an optimization, as QImage.setPixel() is embarrassingly slow + unsigned char* buffer = new unsigned char[expectedImage.height() * expectedImage.width() * 3]; + + // loop over each pixel + for (int y = 0; y < expectedImage.height(); ++y) { + for (int x = 0; x < expectedImage.width(); ++x) { + QRgb pixelP = expectedImage.pixel(QPoint(x, y)); + QRgb pixelQ = resultImage.pixel(QPoint(x, y)); + + // Convert to luminance + double p = R_Y * qRed(pixelP) + G_Y * qGreen(pixelP) + B_Y * qBlue(pixelP); + double q = R_Y * qRed(pixelQ) + G_Y * qGreen(pixelQ) + B_Y * qBlue(pixelQ); + + // The intensity value is modified to increase the brightness of the displayed image + double absoluteDifference = fabs(p - q) / 255.0; + double modifiedDifference = sqrt(absoluteDifference); + + int difference = (int)(modifiedDifference * 255.0); + + buffer[3 * (x + y * expectedImage.width()) + 0] = difference; + buffer[3 * (x + y * expectedImage.width()) + 1] = difference; + buffer[3 * (x + y * expectedImage.width()) + 2] = difference; + } + } + + QImage diffImage(buffer, expectedImage.width(), expectedImage.height(), QImage::Format_RGB888); + QPixmap resultPixmap = QPixmap::fromImage(diffImage); + + delete[] buffer; + + return resultPixmap; } void MismatchWindow::setTestFailure(TestFailure testFailure) { @@ -24,10 +61,19 @@ void MismatchWindow::setTestFailure(TestFailure testFailure) { imagePath->setText("Path to test: " + testFailure._pathname); expectedFilename->setText(testFailure._expectedImageFilename); - expectedImage->setPixmap(QPixmap(testFailure._pathname + testFailure._expectedImageFilename)); - resultFilename->setText(testFailure._actualImageFilename); - resultImage->setPixmap(QPixmap(testFailure._pathname + testFailure._actualImageFilename)); + + QPixmap expectedPixmap = QPixmap(testFailure._pathname + testFailure._expectedImageFilename); + QPixmap actualPixmap = QPixmap(testFailure._pathname + testFailure._actualImageFilename); + + diffPixmap = computeDiffPixmap( + QImage(testFailure._pathname + testFailure._expectedImageFilename), + QImage(testFailure._pathname + testFailure._actualImageFilename) + ); + + expectedImage->setPixmap(expectedPixmap); + resultImage->setPixmap(actualPixmap); + diffImage->setPixmap(diffPixmap); } void MismatchWindow::on_passTestButton_clicked() { @@ -44,3 +90,7 @@ void MismatchWindow::on_abortTestsButton_clicked() { _userResponse = USER_RESPONSE_ABORT; close(); } + +QPixmap MismatchWindow::getComparisonImage() { + return diffPixmap; +} diff --git a/tools/auto-tester/src/ui/MismatchWindow.h b/tools/auto-tester/src/ui/MismatchWindow.h index 7c72b7b0b7..cdbdcb4098 100644 --- a/tools/auto-tester/src/ui/MismatchWindow.h +++ b/tools/auto-tester/src/ui/MismatchWindow.h @@ -25,6 +25,9 @@ public: UserResponse getUserResponse() { return _userResponse; } + QPixmap computeDiffPixmap(QImage expectedImage, QImage resultImage); + QPixmap getComparisonImage(); + private slots: void on_passTestButton_clicked(); void on_failTestButton_clicked(); @@ -32,7 +35,9 @@ private slots: private: UserResponse _userResponse{ USER_RESPONSE_INVALID }; + + QPixmap diffPixmap; }; -#endif // hifi_MismatchWindow_h +#endif // hifi_MismatchWindow_h \ No newline at end of file diff --git a/tools/auto-tester/src/ui/MismatchWindow.ui b/tools/auto-tester/src/ui/MismatchWindow.ui index cab6c61e1c..72f86261ab 100644 --- a/tools/auto-tester/src/ui/MismatchWindow.ui +++ b/tools/auto-tester/src/ui/MismatchWindow.ui @@ -6,8 +6,8 @@ 0 0 - 1585 - 694 + 1782 + 942 @@ -16,10 +16,10 @@ - 20 - 170 - 720 - 362 + 10 + 25 + 800 + 450 @@ -29,28 +29,41 @@ - 760 - 170 - 720 - 362 + 900 + 25 + 800 + 450 result image + + + + 540 + 480 + 800 + 450 + + + + diff image + + - 760 - 90 - 800 + 60 + 660 + 480 28 - 16 + 12 @@ -60,15 +73,15 @@ - 40 - 90 - 700 + 60 + 630 + 480 28 - 16 + 12 @@ -78,15 +91,15 @@ - 40 - 30 + 20 + 600 1200 28 - 16 + 12 @@ -97,7 +110,7 @@ 30 - 600 + 790 75 23 @@ -109,8 +122,8 @@ - 330 - 600 + 120 + 790 75 23 @@ -122,36 +135,62 @@ - 630 - 600 - 75 + 210 + 790 + 121 23 - Abort Tests + Abort current test - 810 - 600 - 720 + 30 + 850 + 500 28 - 16 + 12 similarity + + + + 30 + 5 + 151 + 16 + + + + Expected Image + + + + + + 930 + 5 + 151 + 16 + + + + Actual Image + + - + \ No newline at end of file diff --git a/tools/oven/src/DomainBaker.cpp b/tools/oven/src/DomainBaker.cpp index 535d9a49a9..edc2492e82 100644 --- a/tools/oven/src/DomainBaker.cpp +++ b/tools/oven/src/DomainBaker.cpp @@ -195,9 +195,9 @@ void DomainBaker::enumerateEntities() { auto filename = modelURL.fileName(); auto baseName = filename.left(filename.lastIndexOf('.')); auto subDirName = "/" + baseName; - int i = 0; + int i = 1; while (QDir(_contentOutputPath + subDirName).exists()) { - subDirName = "/" + baseName + "-" + i++; + subDirName = "/" + baseName + "-" + QString::number(i++); } QSharedPointer baker { new FBXBaker(modelURL, []() -> QThread* { diff --git a/unpublishedScripts/marketplace/camera-move/app-camera-move.js b/unpublishedScripts/marketplace/camera-move/app-camera-move.js index f58dd3d3bd..f9361c6091 100644 --- a/unpublishedScripts/marketplace/camera-move/app-camera-move.js +++ b/unpublishedScripts/marketplace/camera-move/app-camera-move.js @@ -133,7 +133,7 @@ var DEBUG_INFO = { Reticle: { supportsScale: 'scale' in Reticle, }, - protocolVersion: location.protocolVersion, + protocolVersion: Window.protocolSignature(), }; var globalState = { diff --git a/unpublishedScripts/marketplace/camera-move/modules/custom-settings-app/CustomSettingsApp.js b/unpublishedScripts/marketplace/camera-move/modules/custom-settings-app/CustomSettingsApp.js index c76adea940..95dba5c558 100644 --- a/unpublishedScripts/marketplace/camera-move/modules/custom-settings-app/CustomSettingsApp.js +++ b/unpublishedScripts/marketplace/camera-move/modules/custom-settings-app/CustomSettingsApp.js @@ -52,7 +52,7 @@ function CustomSettingsApp(options) { this.extraParams = Object.assign(options.extraParams || {}, { customSettingsVersion: CustomSettingsApp.version+'', - protocolVersion: location.protocolVersion && location.protocolVersion() + protocolVersion: Window.protocolSignature && Window.protocolSignature() }); var params = {