diff --git a/interface/src/AboutUtil.cpp b/interface/src/AboutUtil.cpp index 5179897443..634e52b481 100644 --- a/interface/src/AboutUtil.cpp +++ b/interface/src/AboutUtil.cpp @@ -8,48 +8,46 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + +#include "AboutUtil.h" #include #include -#include "AboutUtil.h" -#include "BuildInfo.h" #include +#include + +#include "BuildInfo.h" #include "DependencyManager.h" #include "scripting/HMDScriptingInterface.h" #include "Application.h" -#include AboutUtil::AboutUtil(QObject *parent) : QObject(parent) { - QLocale locale_; - m_DateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy"). - toString(locale_.dateFormat(QLocale::ShortFormat)); + QLocale locale; + _dateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy"). + toString(locale.dateFormat(QLocale::ShortFormat)); } -AboutUtil *AboutUtil::getInstance() -{ +AboutUtil *AboutUtil::getInstance() { static AboutUtil instance; return &instance; } -QString AboutUtil::buildDate() const -{ - return m_DateConverted; +QString AboutUtil::getBuildDate() const { + return _dateConverted; } -QString AboutUtil::buildVersion() const -{ +QString AboutUtil::getBuildVersion() const { return BuildInfo::VERSION; } -QString AboutUtil::qtVersion() const -{ +QString AboutUtil::getQtVersion() const { return qVersion(); } void AboutUtil::openUrl(const QString& url) const { auto tabletScriptingInterface = DependencyManager::get(); - auto tablet = dynamic_cast(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); + auto tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system"); auto hmd = DependencyManager::get(); auto offscreenUi = DependencyManager::get(); diff --git a/interface/src/AboutUtil.h b/interface/src/AboutUtil.h index 9b65b887b9..06c04cc9df 100644 --- a/interface/src/AboutUtil.h +++ b/interface/src/AboutUtil.h @@ -16,27 +16,24 @@ #include class AboutUtil : public QObject { - Q_OBJECT - Q_PROPERTY(QString buildDate READ buildDate CONSTANT) - Q_PROPERTY(QString buildVersion READ buildVersion CONSTANT) - Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT) - - AboutUtil(QObject* parent = nullptr); + Q_PROPERTY(QString buildDate READ getBuildDate CONSTANT) + Q_PROPERTY(QString buildVersion READ getBuildVersion CONSTANT) + Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT) public: static AboutUtil* getInstance(); ~AboutUtil() {} - QString buildDate() const; - QString buildVersion() const; - QString qtVersion() const; + QString getBuildDate() const; + QString getBuildVersion() const; + QString getQtVersion() const; public slots: void openUrl(const QString &url) const; private: - - QString m_DateConverted; + AboutUtil(QObject* parent = nullptr); + QString _dateConverted; }; #endif // hifi_AboutUtil_h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a43c2fdc5f..c4f700fc20 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3645,7 +3645,6 @@ void Application::keyPressEvent(QKeyEvent* event) { _keysPressed.insert(event->key()); _controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts - // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface->isKeyCaptured(event)) { return; @@ -3730,6 +3729,13 @@ void Application::keyPressEvent(QKeyEvent* event) { } break; + case Qt::Key_R: + if (isMeta && !event->isAutoRepeat()) { + DependencyManager::get()->reloadAllScripts(); + DependencyManager::get()->clearCache(); + } + break; + case Qt::Key_Asterisk: Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); break; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 094b3bb67b..2e9c9fdecd 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -104,6 +104,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) { PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); _myAvatar->update(deltaTime); + render::Transaction transaction; + _myAvatar->updateRenderItem(transaction); + qApp->getMain3DScene()->enqueueTransaction(transaction); quint64 now = usecTimestampNow(); quint64 dt = now - _lastSendAvatarDataTime; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index d3ab739649..0783094e10 100755 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1127,7 +1127,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) { } void MyAvatar::setEnableMeshVisible(bool isEnabled) { - _skeletonModel->setVisibleInScene(isEnabled, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + return Avatar::setEnableMeshVisible(isEnabled); +} + +bool MyAvatar::getEnableMeshVisible() const { + return Avatar::getEnableMeshVisible(); } void MyAvatar::setEnableInverseKinematics(bool isEnabled) { @@ -1479,7 +1483,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) { _skeletonModelChangeCount++; int skeletonModelChangeCount = _skeletonModelChangeCount; Avatar::setSkeletonModelURL(skeletonModelURL); - _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene(), render::ItemKey::TAG_BITS_NONE, true); + _skeletonModel->setTagMask(render::hifi::TAG_NONE); + _skeletonModel->setGroupCulled(true); + _skeletonModel->setVisibleInScene(true, qApp->getMain3DScene()); + _headBoneSet.clear(); _cauterizationNeedsUpdate = true; @@ -2054,14 +2061,12 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) { _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("Face", Qt::CaseInsensitive) == 0) { - uint8_t modelRenderTagBits = shouldDrawHead ? render::ItemKey::TAG_BITS_0 : render::ItemKey::TAG_BITS_NONE; - modelRenderTagBits |= render::ItemKey::TAG_BITS_1; - _attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(), - modelRenderTagBits, false); + uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW; - uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1; - _attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(), - castShadowRenderTagBits, false); + _attachmentModels[i]->setTagMask(modelRenderTagBits); + _attachmentModels[i]->setGroupCulled(false); + _attachmentModels[i]->setCanCastShadow(true); + _attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene()); } } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bba840d185..514dd9dcaf 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -1159,7 +1159,7 @@ public slots: * @function MyAvatar.getEnableMeshVisible * @returns {boolean} true if your avatar's mesh is visible, otherwise false. */ - bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); } + bool getEnableMeshVisible() const override; /**jsdoc * Set whether or not your avatar mesh is visible. @@ -1171,7 +1171,7 @@ public slots: * MyAvatar.setEnableMeshVisible(true); * }, 10000); */ - void setEnableMeshVisible(bool isEnabled); + virtual void setEnableMeshVisible(bool isEnabled) override; /**jsdoc * @function MyAvatar.setEnableInverseKinematics diff --git a/interface/src/scripting/TestScriptingInterface.cpp b/interface/src/scripting/TestScriptingInterface.cpp index 700994c517..430441226f 100644 --- a/interface/src/scripting/TestScriptingInterface.cpp +++ b/interface/src/scripting/TestScriptingInterface.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -186,3 +187,7 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam file.write(jsonData); file.close(); } + +void TestScriptingInterface::showMaximized() { + qApp->getWindow()->showMaximized(); +} \ No newline at end of file diff --git a/interface/src/scripting/TestScriptingInterface.h b/interface/src/scripting/TestScriptingInterface.h index 5666417727..c47e39d1f3 100644 --- a/interface/src/scripting/TestScriptingInterface.h +++ b/interface/src/scripting/TestScriptingInterface.h @@ -27,70 +27,128 @@ public slots: /**jsdoc * Exits the application + * @function Test.quit */ void quit(); /**jsdoc * Waits for all texture transfers to be complete + * @function Test.waitForTextureIdle */ void waitForTextureIdle(); /**jsdoc * Waits for all pending downloads to be complete + * @function Test.waitForDownloadIdle */ void waitForDownloadIdle(); /**jsdoc * Waits for all file parsing operations to be complete + * @function Test.waitForProcessingIdle */ void waitForProcessingIdle(); /**jsdoc * Waits for all pending downloads, parsing and texture transfers to be complete + * @function Test.waitIdle */ void waitIdle(); + /**jsdoc + * Waits for establishment of connection to server + * @function Test.waitForConnection + * @param {int} maxWaitMs [default=10000] - Number of milliseconds to wait + */ bool waitForConnection(qint64 maxWaitMs = 10000); + /**jsdoc + * Waits a specific number of milliseconds + * @function Test.wait + * @param {int} milliseconds - Number of milliseconds to wait + */ void wait(int milliseconds); + /**jsdoc + * Waits for all pending downloads, parsing and texture transfers to be complete + * @function Test.loadTestScene + * @param {string} sceneFile - URL of scene to load + */ bool loadTestScene(QString sceneFile); + /**jsdoc + * Clears all caches + * @function Test.clear + */ void clear(); /**jsdoc * Start recording Chrome compatible tracing events * logRules can be used to specify a set of logging category rules to limit what gets captured + * @function Test.startTracing + * @param {string} logrules [defaultValue=""] - See implementation for explanation */ bool startTracing(QString logrules = ""); /**jsdoc * Stop recording Chrome compatible tracing events and serialize recorded events to a file * Using a filename with a .gz extension will automatically compress the output file + * @function Test.stopTracing + * @param {string} filename - Name of file to save to + * @returns {bool} True if successful. */ bool stopTracing(QString filename); + /**jsdoc + * Starts a specific trace event + * @function Test.startTraceEvent + * @param {string} name - Name of event + */ void startTraceEvent(QString name); + /**jsdoc + * Stop a specific name event + * Using a filename with a .gz extension will automatically compress the output file + * @function Test.endTraceEvent + * @param {string} filename - Name of event + */ void endTraceEvent(QString name); /**jsdoc * Write detailed timing stats of next physics stepSimulation() to filename + * @function Test.savePhysicsSimulationStats + * @param {string} filename - Name of file to save to */ void savePhysicsSimulationStats(QString filename); + /**jsdoc + * Profiles a specific function + * @function Test.savePhysicsSimulationStats + * @param {string} name - Name used to reference the function + * @param {function} function - Function to profile + */ Q_INVOKABLE void profileRange(const QString& name, QScriptValue function); /**jsdoc * Clear all caches (menu command Reload Content) + * @function Test.clearCaches */ void clearCaches(); /**jsdoc * Save a JSON object to a file in the test results location + * @function Test.saveObject + * @param {string} name - Name of the object + * @param {string} filename - Name of file to save to */ void saveObject(QVariant v, const QString& filename); + /**jsdoc + * Maximizes the window + * @function Test.showMaximized + */ + void showMaximized(); + private: bool waitForCondition(qint64 maxWaitMs, std::function condition); QString _testResultsLocation; diff --git a/interface/src/ui/overlays/ModelOverlay.cpp b/interface/src/ui/overlays/ModelOverlay.cpp index 27e3bd0e2d..a541b3365f 100644 --- a/interface/src/ui/overlays/ModelOverlay.cpp +++ b/interface/src/ui/overlays/ModelOverlay.cpp @@ -103,10 +103,9 @@ void ModelOverlay::update(float deltatime) { if (_visibleDirty) { _visibleDirty = false; // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true - _model->setVisibleInScene(getVisible(), scene, - render::ItemKey::TAG_BITS_0 | - (_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE), - false); + uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW); + _model->setTagMask(modelRenderTagMask, scene); + _model->setVisibleInScene(getVisible(), scene); } if (_drawInFrontDirty) { _drawInFrontDirty = false; diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 2f27d50f7e..890d5178e5 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -132,7 +132,6 @@ private: namespace render { template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay); template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay); - template <> int payloadGetLayer(const Overlay::Pointer& overlay); template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args); template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay); template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 185547a333..6b55b2b701 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -35,14 +35,18 @@ namespace render { auto builder = ItemKey::Builder().withTypeShape(); if (overlay->is3D()) { auto overlay3D = std::static_pointer_cast(overlay); - if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) { - builder.withLayered(); + if (overlay3D->getDrawInFront()) { + builder.withLayer(render::hifi::LAYER_3D_FRONT); + } else if (overlay3D->getDrawHUDLayer()) { + builder.withLayer(render::hifi::LAYER_3D_HUD); } + if (overlay->isTransparent()) { builder.withTransparent(); } } else { builder.withViewSpace(); + builder.withLayer(render::hifi::LAYER_2D); } if (!overlay->getVisible()) { @@ -50,30 +54,16 @@ namespace render { } // always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view - uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 | - (overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE); + uint32_t viewTagBits = render::hifi::TAG_MAIN_VIEW | + (overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE); - builder.withTagBits(viewTaskBits); + builder.withTagBits(viewTagBits); return builder.build(); } template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) { return overlay->getBounds(); } - template <> int payloadGetLayer(const Overlay::Pointer& overlay) { - if (overlay->is3D()) { - auto overlay3D = std::dynamic_pointer_cast(overlay); - if (overlay3D->getDrawInFront()) { - return Item::LAYER_3D_FRONT; - } else if (overlay3D->getDrawHUDLayer()) { - return Item::LAYER_3D_HUD; - } else { - return Item::LAYER_3D; - } - } else { - return Item::LAYER_2D; - } - } template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) { if (args) { overlay->render(args); @@ -83,7 +73,6 @@ namespace render { return overlay->getShapeKey(); } - template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) { return overlay->fetchMetaSubItems(subItems); } diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp index da829b23e4..5ce7637a3a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.cpp @@ -52,10 +52,15 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f); namespace render { template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { - return ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(ItemKey::TAG_BITS_0 | ItemKey::TAG_BITS_1).withMetaCullGroup(); + ItemKey::Builder keyBuilder = ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(render::hifi::TAG_ALL_VIEWS).withMetaCullGroup(); + auto avatarPtr = static_pointer_cast(avatar); + if (!avatarPtr->getEnableMeshVisible()) { + keyBuilder.withInvisible(); + } + return keyBuilder.build(); } template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { - return static_pointer_cast(avatar)->getBounds(); + return static_pointer_cast(avatar)->getRenderBounds(); } template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) { auto avatarPtr = static_pointer_cast(avatar); @@ -164,6 +169,11 @@ AABox Avatar::getBounds() const { return _skeletonModel->getRenderableMeshBound(); } + +AABox Avatar::getRenderBounds() const { + return _renderBound; +} + void Avatar::animateScaleChanges(float deltaTime) { if (_isAnimatingScale) { @@ -569,16 +579,26 @@ static TextRenderer3D* textRenderer(TextRendererType type) { void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) { auto avatarPayload = new render::Payload(self); - auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); - + auto avatarPayloadPointer = std::shared_ptr>(avatarPayload); if (_renderItemID == render::Item::INVALID_ITEM_ID) { _renderItemID = scene->allocateID(); } + // INitialize the _render bound as we are creating the avatar render item + _renderBound = getBounds(); transaction.resetItem(_renderItemID, avatarPayloadPointer); _skeletonModel->addToScene(scene, transaction); + _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); + _skeletonModel->setGroupCulled(true); + _skeletonModel->setCanCastShadow(true); + _skeletonModel->setVisibleInScene(_isMeshVisible, scene); + processMaterials(); for (auto& attachmentModel : _attachmentModels) { attachmentModel->addToScene(scene, transaction); + attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); + attachmentModel->setGroupCulled(false); + attachmentModel->setCanCastShadow(true); + attachmentModel->setVisibleInScene(_isMeshVisible, scene); } _mustFadeIn = true; @@ -637,7 +657,15 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe void Avatar::updateRenderItem(render::Transaction& transaction) { if (render::Item::isValidID(_renderItemID)) { - transaction.updateItem>(_renderItemID, [](render::Payload& p) {}); + auto renderBound = getBounds(); + transaction.updateItem(_renderItemID, + [renderBound](AvatarData& avatar) { + auto avatarPtr = dynamic_cast(&avatar); + if (avatarPtr) { + avatarPtr->_renderBound = renderBound; + } + } + ); } } @@ -759,6 +787,18 @@ void Avatar::render(RenderArgs* renderArgs) { } } + +void Avatar::setEnableMeshVisible(bool isEnabled) { + if (_isMeshVisible != isEnabled) { + _isMeshVisible = isEnabled; + _needMeshVisibleSwitch = true; + } +} + +bool Avatar::getEnableMeshVisible() const { + return _isMeshVisible; +} + void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { bool canTryFade{ false }; @@ -770,6 +810,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { _skeletonModel->removeFromScene(scene, transaction); _skeletonModel->addToScene(scene, transaction); + + _skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS); + _skeletonModel->setGroupCulled(true); + _skeletonModel->setCanCastShadow(true); + _skeletonModel->setVisibleInScene(_isMeshVisible, scene); + processMaterials(); canTryFade = true; _isAnimatingScale = true; @@ -778,9 +824,25 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) { if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { attachmentModel->removeFromScene(scene, transaction); attachmentModel->addToScene(scene, transaction); + + attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS); + attachmentModel->setGroupCulled(false); + attachmentModel->setCanCastShadow(true); + attachmentModel->setVisibleInScene(_isMeshVisible, scene); } } + if (_needMeshVisibleSwitch) { + _skeletonModel->setVisibleInScene(_isMeshVisible, scene); + for (auto attachmentModel : _attachmentModels) { + if (attachmentModel->isRenderable()) { + attachmentModel->setVisibleInScene(_isMeshVisible, scene); + } + } + updateRenderItem(transaction); + _needMeshVisibleSwitch = false; + } + if (_mustFadeIn && canTryFade) { // Do it now to be sure all the sub items are ready and the fade is sent to them too fade(transaction, render::Transition::USER_ENTER_DOMAIN); diff --git a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h index 0f48e03e55..10c1d9ead2 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/Avatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/Avatar.h @@ -74,7 +74,6 @@ public: virtual void instantiableAvatar() = 0; typedef render::Payload Payload; - typedef std::shared_ptr PayloadPointer; void init(); void updateAvatarEntities(); @@ -322,6 +321,7 @@ public: bool hasNewJointData() const { return _hasNewJointData; } float getBoundingRadius() const; + AABox getRenderBounds() const; // THis call is accessible from rendering thread only to report the bounding box of the avatar during the frame. void addToScene(AvatarSharedPointer self, const render::ScenePointer& scene); void ensureInScene(AvatarSharedPointer self, const render::ScenePointer& scene); @@ -356,6 +356,10 @@ public: virtual void setAvatarEntityDataChanged(bool value) override; + // Show hide the model representation of the avatar + virtual void setEnableMeshVisible(bool isEnabled); + virtual bool getEnableMeshVisible() const; + void addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override; void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override; @@ -532,6 +536,10 @@ protected: std::mutex _materialsLock; void processMaterials(); + + AABox _renderBound; + bool _isMeshVisible{ true }; + bool _needMeshVisibleSwitch{ true }; }; #endif // hifi_Avatar_h diff --git a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp index 428f86f0ab..de8c02f10e 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp +++ b/libraries/avatars-renderer/src/avatars-renderer/SkeletonModel.cpp @@ -35,7 +35,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : _useDualQuaternionSkinning = true; // Avatars all cast shadow - _canCastShadow = true; + setCanCastShadow(true); assert(_owningAvatar); } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index c4fa71a488..4026a94f65 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -1387,20 +1387,25 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce entity->stopModelOverrideIfNoParent(); // Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) - uint32_t viewTaskBits = _cauterized ? - render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero) - render::ItemKey::TAG_BITS_ALL; // draw in all views + auto tagMask = _cauterized ? + render::hifi::TAG_SECONDARY_VIEW : // draw in every view except the main one (view zero) + render::hifi::TAG_ALL_VIEWS; // draw in all views - if (model->isVisible() != _visible || model->getViewTagBits() != viewTaskBits) { + if (model->isVisible() != _visible) { // FIXME: this seems like it could be optimized if we tracked our last known visible state in // the renderable item. As it stands now the model checks it's visible/invisible state // so most of the time we don't do anything in this function. - model->setVisibleInScene(_visible, scene, viewTaskBits, false); + model->setVisibleInScene(_visible, scene); } + + if (model->getTagMask() != tagMask) { + model->setTagMask(tagMask, scene); + } + // TODO? early exit here when not visible? if (model->canCastShadow() != _canCastShadow) { - model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false); + model->setCanCastShadow(_canCastShadow, scene); } if (_needsCollisionGeometryUpdate) { diff --git a/libraries/entities/src/EntityScriptingInterface.cpp b/libraries/entities/src/EntityScriptingInterface.cpp index f751a4f8ed..98407a74c6 100644 --- a/libraries/entities/src/EntityScriptingInterface.cpp +++ b/libraries/entities/src/EntityScriptingInterface.cpp @@ -1688,15 +1688,21 @@ QVector EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) { if (!_entityTree) { return result; } - - EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID); - if (!entity) { - qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID; - return result; - } - _entityTree->withReadLock([&] { - entity->forEachChild([&](SpatiallyNestablePointer child) { + QSharedPointer parentFinder = DependencyManager::get(); + if (!parentFinder) { + return; + } + bool success; + SpatiallyNestableWeakPointer parentWP = parentFinder->find(parentID, success); + if (!success) { + return; + } + SpatiallyNestablePointer parent = parentWP.lock(); + if (!parent) { + return; + } + parent->forEachChild([&](SpatiallyNestablePointer child) { result.push_back(child->getID()); }); }); diff --git a/libraries/entities/src/EntityScriptingInterface.h b/libraries/entities/src/EntityScriptingInterface.h index 9acbc13251..e63f3ad855 100644 --- a/libraries/entities/src/EntityScriptingInterface.h +++ b/libraries/entities/src/EntityScriptingInterface.h @@ -1226,12 +1226,11 @@ public slots: /**jsdoc - * Get the IDs of entities, overlays, and avatars that are directly parented to an entity. To get all descendants of an - * entity, recurse on the IDs returned by the function. + * Get the IDs of entities, overlays, and avatars that are directly parented to an entity, overlay, or avatar model. Recurse on the IDs returned by the function to get all descendants of an entity, overlay, or avatar. * @function Entities.getChildrenIDs - * @param {Uuid} parentID - The ID of the entity to get the children IDs of. + * @param {Uuid} parentID - The ID of the entity, overlay, or avatar to get the children IDs of. * @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the parentID - * entity. Does not include children's children, etc. The array is empty if no children can be found or + * entity, overlay, or avatar. Does not include children's children, etc. The array is empty if no children can be found or * parentID cannot be found. * @example Report the children of an entity. * function createEntity(description, position, parent) { diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index e70e3e26d0..05f0ec12b5 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -743,6 +744,9 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI return; } + // Ensure openssl/Qt config is set up. + QSslConfiguration::defaultConfiguration(); + // make sure we don't already have an outbound keypair generation request if (!_isWaitingForKeypairResponse) { _isWaitingForKeypairResponse = true; @@ -751,94 +755,75 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI qCDebug(networking) << "Clearing current private key in DataServerAccountInfo"; _accountInfo.setPrivateKey(QByteArray()); - // setup a new QThread to generate the keypair on, in case it takes a while - QThread* generateThread = new QThread(this); - generateThread->setObjectName("Account Manager Generator Thread"); - - // setup a keypair generator + // Create a runnable keypair generated to create an RSA pair and exit. RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator; if (!isUserKeypair) { - keypairGenerator->setDomainID(domainID); _accountInfo.setDomainID(domainID); } - // start keypair generation when the thread starts - connect(generateThread, &QThread::started, keypairGenerator, &RSAKeypairGenerator::generateKeypair); - // handle success or failure of keypair generation - connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair); - connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, - this, &AccountManager::handleKeypairGenerationError); - - connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit); - connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater); - - keypairGenerator->moveToThread(generateThread); + connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, + &AccountManager::processGeneratedKeypair); + connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, this, + &AccountManager::handleKeypairGenerationError); qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair."; - generateThread->start(); + // Start on Qt's global thread pool. + QThreadPool::globalInstance()->start(keypairGenerator); } } -void AccountManager::processGeneratedKeypair() { +void AccountManager::processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey) { qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now."; - RSAKeypairGenerator* keypairGenerator = qobject_cast(sender()); + // hold the private key to later set our metaverse API account info if upload succeeds + _pendingPrivateKey = privateKey; - if (keypairGenerator) { - // hold the private key to later set our metaverse API account info if upload succeeds - _pendingPrivateKey = keypairGenerator->getPrivateKey(); + // upload the public key so data-web has an up-to-date key + const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key"; + const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; - // upload the public key so data-web has an up-to-date key - const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key"; - const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; - - QString uploadPath; - const auto& domainID = keypairGenerator->getDomainID(); - if (domainID.isNull()) { - uploadPath = USER_PUBLIC_KEY_UPDATE_PATH; - } else { - uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID)); - } - - // setup a multipart upload to send up the public key - QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); - - QHttpPart publicKeyPart; - publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - - publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, - QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); - publicKeyPart.setBody(keypairGenerator->getPublicKey()); - requestMultiPart->append(publicKeyPart); - - if (!domainID.isNull()) { - const auto& key = getTemporaryDomainKey(domainID); - QHttpPart apiKeyPart; - publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); - apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, - QVariant("form-data; name=\"api_key\"")); - apiKeyPart.setBody(key.toUtf8()); - requestMultiPart->append(apiKeyPart); - } - - // setup callback parameters so we know once the keypair upload has succeeded or failed - JSONCallbackParameters callbackParameters; - callbackParameters.jsonCallbackReceiver = this; - callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded"; - callbackParameters.errorCallbackReceiver = this; - callbackParameters.errorCallbackMethod = "publicKeyUploadFailed"; - - sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, - callbackParameters, QByteArray(), requestMultiPart); - - keypairGenerator->deleteLater(); + QString uploadPath; + const auto& domainID = _accountInfo.getDomainID(); + if (domainID.isNull()) { + uploadPath = USER_PUBLIC_KEY_UPDATE_PATH; } else { - qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator" - << "but the casted sender is NULL. Will not process generated keypair."; + uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID)); } + + // setup a multipart upload to send up the public key + QHttpMultiPart* requestMultiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType); + + QHttpPart publicKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + + publicKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"public_key\"; filename=\"public_key\"")); + publicKeyPart.setBody(publicKey); + requestMultiPart->append(publicKeyPart); + + // Currently broken? We don't have the temporary domain key. + if (!domainID.isNull()) { + const auto& key = getTemporaryDomainKey(domainID); + QHttpPart apiKeyPart; + publicKeyPart.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/octet-stream")); + apiKeyPart.setHeader(QNetworkRequest::ContentDispositionHeader, + QVariant("form-data; name=\"api_key\"")); + apiKeyPart.setBody(key.toUtf8()); + requestMultiPart->append(apiKeyPart); + } + + // setup callback parameters so we know once the keypair upload has succeeded or failed + JSONCallbackParameters callbackParameters; + callbackParameters.jsonCallbackReceiver = this; + callbackParameters.jsonCallbackMethod = "publicKeyUploadSucceeded"; + callbackParameters.errorCallbackReceiver = this; + callbackParameters.errorCallbackMethod = "publicKeyUploadFailed"; + + sendRequest(uploadPath, AccountManagerAuth::Optional, QNetworkAccessManager::PutOperation, + callbackParameters, QByteArray(), requestMultiPart); } void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) { @@ -877,6 +862,4 @@ void AccountManager::handleKeypairGenerationError() { // reset our waiting state for keypair response _isWaitingForKeypairResponse = false; - - sender()->deleteLater(); } diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 88ebaf5656..9068966512 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -128,7 +128,7 @@ signals: private slots: void processReply(); void handleKeypairGenerationError(); - void processGeneratedKeypair(); + void processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey); void publicKeyUploadSucceeded(QNetworkReply& reply); void publicKeyUploadFailed(QNetworkReply& reply); void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid()); diff --git a/libraries/networking/src/RSAKeypairGenerator.cpp b/libraries/networking/src/RSAKeypairGenerator.cpp index 8ca8b81ea3..e83615e3df 100644 --- a/libraries/networking/src/RSAKeypairGenerator.cpp +++ b/libraries/networking/src/RSAKeypairGenerator.cpp @@ -25,7 +25,10 @@ RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : QObject(parent) { - +} + +void RSAKeypairGenerator::run() { + generateKeypair(); } void RSAKeypairGenerator::generateKeypair() { @@ -92,5 +95,5 @@ void RSAKeypairGenerator::generateKeypair() { OPENSSL_free(publicKeyDER); OPENSSL_free(privateKeyDER); - emit generatedKeypair(); + emit generatedKeypair(_publicKey, _privateKey); } diff --git a/libraries/networking/src/RSAKeypairGenerator.h b/libraries/networking/src/RSAKeypairGenerator.h index 36f4a9550b..552f12395b 100644 --- a/libraries/networking/src/RSAKeypairGenerator.h +++ b/libraries/networking/src/RSAKeypairGenerator.h @@ -13,25 +13,20 @@ #define hifi_RSAKeypairGenerator_h #include +#include #include -class RSAKeypairGenerator : public QObject { +class RSAKeypairGenerator : public QObject, public QRunnable { Q_OBJECT public: - RSAKeypairGenerator(QObject* parent = 0); + RSAKeypairGenerator(QObject* parent = nullptr); - void setDomainID(const QUuid& domainID) { _domainID = domainID; } - const QUuid& getDomainID() const { return _domainID; } - - const QByteArray& getPublicKey() const { return _publicKey; } - const QByteArray& getPrivateKey() const { return _privateKey; } - -public slots: + virtual void run() override; void generateKeypair(); signals: void errorGeneratingKeypair(); - void generatedKeypair(); + void generatedKeypair(QByteArray publicKey, QByteArray privateKey); private: QUuid _domainID; diff --git a/libraries/physics/src/ObjectDynamic.cpp b/libraries/physics/src/ObjectDynamic.cpp index 3341025a8f..28323a8b92 100644 --- a/libraries/physics/src/ObjectDynamic.cpp +++ b/libraries/physics/src/ObjectDynamic.cpp @@ -159,6 +159,13 @@ void ObjectDynamic::removeFromSimulation(EntitySimulationPointer simulation) con simulation->removeDynamic(myID); } +void ObjectDynamic::setOwnerEntity(const EntityItemPointer ownerEntity) { + if (!ownerEntity) { + activateBody(); + } + _ownerEntity = ownerEntity; +} + EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const { EntityItemPointer ownerEntity; withReadLock([&]{ diff --git a/libraries/physics/src/ObjectDynamic.h b/libraries/physics/src/ObjectDynamic.h index 7fdf2e323a..bfee79aca9 100644 --- a/libraries/physics/src/ObjectDynamic.h +++ b/libraries/physics/src/ObjectDynamic.h @@ -33,7 +33,7 @@ public: virtual void removeFromSimulation(EntitySimulationPointer simulation) const override; virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; } - virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override { _ownerEntity = ownerEntity; } + virtual void setOwnerEntity(const EntityItemPointer ownerEntity) override; virtual void invalidate() {}; diff --git a/libraries/render-utils/src/CauterizedModel.cpp b/libraries/render-utils/src/CauterizedModel.cpp index 1596f7ba83..79e0637af4 100644 --- a/libraries/render-utils/src/CauterizedModel.cpp +++ b/libraries/render-utils/src/CauterizedModel.cpp @@ -215,10 +215,7 @@ void CauterizedModel::updateRenderItems() { modelTransform.setRotation(self->getRotation()); bool isWireframe = self->isWireframe(); - bool isVisible = self->isVisible(); - bool canCastShadow = self->canCastShadow(); - bool isLayeredInFront = self->isLayeredInFront(); - bool isLayeredInHUD = self->isLayeredInHUD(); + auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); bool enableCauterization = self->getEnableCauterization(); render::Transaction transaction; @@ -234,7 +231,7 @@ void CauterizedModel::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, - isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) { + isWireframe, renderItemKeyGlobalFlags, enableCauterization](CauterizedMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions, cauterizedMeshState.clusterDualQuaternions); @@ -276,8 +273,7 @@ void CauterizedModel::updateRenderItems() { data.updateTransformForCauterizedMesh(renderTransform); data.setEnableCauterization(enableCauterization); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL); - data.setLayer(isLayeredInFront, isLayeredInHUD); + data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); } diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 72a4b7e0a4..7cf8bc8297 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -79,28 +79,10 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) { _drawMaterials.remove(material); } -void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { - ItemKey::Builder builder; +void MeshPartPayload::updateKey(const render::ItemKey& key) { + ItemKey::Builder builder(key); builder.withTypeShape(); - if (!isVisible) { - builder.withInvisible(); - } - - builder.withTagBits(tagBits); - - if (isLayered) { - builder.withLayered(); - } - - if (canCastShadow) { - builder.withShadowCaster(); - } - - if (isGroupCulled) { - builder.withSubMetaCulled(); - } - if (topMaterialExists()) { auto matKey = _drawMaterials.top().material->getKey(); if (matKey.isTranslucent()) { @@ -200,12 +182,6 @@ template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointe } return Item::Bound(); } -template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload) { - if (payload) { - return payload->getLayer(); - } - return 0; -} template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) { if (payload) { @@ -332,28 +308,10 @@ void ModelMeshPartPayload::updateTransformForSkinnedMesh(const Transform& render } // Note that this method is called for models but not for shapes -void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { - ItemKey::Builder builder; +void ModelMeshPartPayload::updateKey(const render::ItemKey& key) { + ItemKey::Builder builder(key); builder.withTypeShape(); - if (!isVisible) { - builder.withInvisible(); - } - - builder.withTagBits(tagBits); - - if (isLayered) { - builder.withLayered(); - } - - if (canCastShadow) { - builder.withShadowCaster(); - } - - if (isGroupCulled) { - builder.withSubMetaCulled(); - } - if (_isBlendShaped || _isSkinned) { builder.withDeformed(); } @@ -368,20 +326,6 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas _itemKey = builder.build(); } -void ModelMeshPartPayload::setLayer(bool isLayeredInFront, bool isLayeredInHUD) { - if (isLayeredInFront) { - _layer = Item::LAYER_3D_FRONT; - } else if (isLayeredInHUD) { - _layer = Item::LAYER_3D_HUD; - } else { - _layer = Item::LAYER_3D; - } -} - -int ModelMeshPartPayload::getLayer() const { - return _layer; -} - void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) { if (invalidateShapeKey) { _shapeKey = ShapeKey::Builder::invalid(); diff --git a/libraries/render-utils/src/MeshPartPayload.h b/libraries/render-utils/src/MeshPartPayload.h index 08ad7a8311..5c7177e890 100644 --- a/libraries/render-utils/src/MeshPartPayload.h +++ b/libraries/render-utils/src/MeshPartPayload.h @@ -32,7 +32,7 @@ public: typedef render::Payload Payload; typedef Payload::DataPointer Pointer; - virtual void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false); + virtual void updateKey(const render::ItemKey& key); virtual void updateMeshPart(const std::shared_ptr& drawMesh, int partIndex); @@ -95,7 +95,7 @@ public: void notifyLocationChanged() override; - void updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled = false) override; + void updateKey(const render::ItemKey& key) override; // matrix palette skinning void updateClusterBuffer(const std::vector& clusterMatrices); @@ -105,11 +105,9 @@ public: void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); // Render Item interface - int getLayer() const; render::ShapeKey getShapeKey() const override; // shape interface void render(RenderArgs* args) override; - void setLayer(bool isLayeredInFront, bool isLayeredInHUD); void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning); // ModelMeshPartPayload functions to perform render @@ -139,13 +137,11 @@ private: gpu::BufferPointer _blendedVertexBuffer; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; - int _layer { render::Item::LAYER_3D }; }; namespace render { template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload); template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload); - template <> int payloadGetLayer(const ModelMeshPartPayload::Pointer& payload); template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 65b12ac0d4..7cfb1f6bc8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -103,11 +103,10 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) : _snapModelToRegistrationPoint(false), _snappedToRegistrationPoint(false), _url(HTTP_INVALID_COM), - _isVisible(true), - _canCastShadow(false), _blendNumber(0), _appliedBlendNumber(0), - _isWireframe(false) + _isWireframe(false), + _renderItemKeyGlobalFlags(render::ItemKey::Builder().withVisible().withTagBits(render::hifi::TAG_ALL_VIEWS).build()) { // we may have been created in the network thread, but we live in the main thread if (_viewState) { @@ -268,12 +267,7 @@ void Model::updateRenderItems() { modelTransform.setScale(glm::vec3(1.0f)); bool isWireframe = self->isWireframe(); - bool isVisible = self->isVisible(); - bool canCastShadow = self->canCastShadow(); - uint8_t viewTagBits = self->getViewTagBits(); - bool isLayeredInFront = self->isLayeredInFront(); - bool isLayeredInHUD = self->isLayeredInHUD(); - bool isGroupCulled = self->isGroupCulled(); + auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags(); render::Transaction transaction; for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { @@ -287,9 +281,7 @@ void Model::updateRenderItems() { bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); transaction.updateItem(itemID, [modelTransform, meshState, useDualQuaternionSkinning, - invalidatePayloadShapeKey, isWireframe, isVisible, - canCastShadow, viewTagBits, isLayeredInFront, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { + invalidatePayloadShapeKey, isWireframe, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) { if (useDualQuaternionSkinning) { data.updateClusterBuffer(meshState.clusterDualQuaternions); } else { @@ -313,8 +305,7 @@ void Model::updateRenderItems() { } data.updateTransformForSkinnedMesh(renderTransform, modelTransform); - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - data.setLayer(isLayeredInFront, isLayeredInHUD); + data.updateKey(renderItemKeyGlobalFlags); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); }); } @@ -322,8 +313,9 @@ void Model::updateRenderItems() { Transform collisionMeshOffset; collisionMeshOffset.setIdentity(); foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { - transaction.updateItem(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { + transaction.updateItem(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) { // update the model transform for this render item. + data.updateKey(renderItemKeyGlobalFlags); data.updateTransform(modelTransform, collisionMeshOffset); }); } @@ -773,110 +765,100 @@ void Model::calculateTriangleSets(const FBXGeometry& geometry) { } } -void Model::setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { - if (_isVisible != isVisible || _viewTagBits != viewTagBits || _isGroupCulled != isGroupCulled) { - _isVisible = isVisible; - _viewTagBits = viewTagBits; - _isGroupCulled = isGroupCulled; +void Model::updateRenderItemsKey(const render::ScenePointer& scene) { + if (!scene) { + _needsFixupInScene = true; + return; + } + auto renderItemsKey = _renderItemKeyGlobalFlags; + render::Transaction transaction; + foreach(auto item, _modelMeshRenderItemsMap.keys()) { + transaction.updateItem(item, [renderItemsKey](ModelMeshPartPayload& data) { + data.updateKey(renderItemsKey); + }); + } + foreach(auto item, _collisionRenderItemsMap.keys()) { + transaction.updateItem(item, [renderItemsKey](ModelMeshPartPayload& data) { + data.updateKey(renderItemsKey); + }); + } + scene->enqueueTransaction(transaction); +} - bool isLayeredInFront = _isLayeredInFront; - bool isLayeredInHUD = _isLayeredInHUD; - bool canCastShadow = _canCastShadow; - render::Transaction transaction; - foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - }); - } - foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - }); - } - scene->enqueueTransaction(transaction); +void Model::setVisibleInScene(bool visible, const render::ScenePointer& scene) { + if (Model::isVisible() != visible) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = (visible ? keyBuilder.withVisible() : keyBuilder.withInvisible()); + updateRenderItemsKey(scene); } } -void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { - if (_canCastShadow != canCastShadow) { - _canCastShadow = canCastShadow; +bool Model::isVisible() const { + return _renderItemKeyGlobalFlags.isVisible(); +} - bool isVisible = _isVisible; - bool isLayeredInFront = _isLayeredInFront; - bool isLayeredInHUD = _isLayeredInHUD; - - render::Transaction transaction; - foreach (auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, - [isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled); - }); - } - - scene->enqueueTransaction(transaction); +void Model::setCanCastShadow(bool castShadow, const render::ScenePointer& scene) { + if (Model::canCastShadow() != castShadow) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = (castShadow ? keyBuilder.withShadowCaster() : keyBuilder.withoutShadowCaster()); + updateRenderItemsKey(scene); } } -void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { - if (_isLayeredInFront != isLayeredInFront) { - _isLayeredInFront = isLayeredInFront; +bool Model::canCastShadow() const { + return _renderItemKeyGlobalFlags.isShadowCaster(); +} - bool isVisible = _isVisible; - bool canCastShadow = _canCastShadow; - uint8_t viewTagBits = _viewTagBits; - bool isLayeredInHUD = _isLayeredInHUD; - bool isGroupCulled = _isGroupCulled; - - render::Transaction transaction; - foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); - } - foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); - } - scene->enqueueTransaction(transaction); +void Model::setLayeredInFront(bool layeredInFront, const render::ScenePointer& scene) { + if (Model::isLayeredInFront() != layeredInFront) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = (layeredInFront ? keyBuilder.withLayer(render::hifi::LAYER_3D_FRONT) : keyBuilder.withoutLayer()); + updateRenderItemsKey(scene); } } -void Model::setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene) { - if (_isLayeredInHUD != isLayeredInHUD) { - _isLayeredInHUD = isLayeredInHUD; +bool Model::isLayeredInFront() const { + return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_FRONT); +} - bool isVisible = _isVisible; - bool canCastShadow = _canCastShadow; - uint8_t viewTagBits = _viewTagBits; - bool isLayeredInFront = _isLayeredInFront; - bool isGroupCulled = _isGroupCulled; - - render::Transaction transaction; - foreach(auto item, _modelMeshRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); - } - foreach(auto item, _collisionRenderItemsMap.keys()) { - transaction.updateItem(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow, - isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) { - data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); - data.setLayer(isLayeredInFront, isLayeredInHUD); - }); - } - scene->enqueueTransaction(transaction); +void Model::setLayeredInHUD(bool layeredInHUD, const render::ScenePointer& scene) { + if (Model::isLayeredInHUD() != layeredInHUD) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = (layeredInHUD ? keyBuilder.withLayer(render::hifi::LAYER_3D_HUD) : keyBuilder.withoutLayer()); + updateRenderItemsKey(scene); } } +bool Model::isLayeredInHUD() const { + return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_HUD); +} + +void Model::setTagMask(uint8_t mask, const render::ScenePointer& scene) { + if (Model::getTagMask() != mask) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = keyBuilder.withTagBits(mask); + updateRenderItemsKey(scene); + } +} +render::hifi::Tag Model::getTagMask() const { + return (render::hifi::Tag) _renderItemKeyGlobalFlags.getTagBits(); +} + +void Model::setGroupCulled(bool groupCulled, const render::ScenePointer& scene) { + if (Model::isGroupCulled() != groupCulled) { + auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags); + _renderItemKeyGlobalFlags = (groupCulled ? keyBuilder.withSubMetaCulled() : keyBuilder.withoutSubMetaCulled()); + updateRenderItemsKey(scene); + } +} +bool Model::isGroupCulled() const { + return _renderItemKeyGlobalFlags.isSubMetaCulled(); +} + +const render::ItemKey Model::getRenderItemKeyGlobalFlags() const { + return _renderItemKeyGlobalFlags; +} + bool Model::addToScene(const render::ScenePointer& scene, render::Transaction& transaction, render::Item::Status::Getters& statusGetters) { @@ -1676,20 +1658,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par for (auto shapeID : shapeIDs) { if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; - bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool canCastShadow = _canCastShadow; + auto renderItemsKey = _renderItemKeyGlobalFlags; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, + transaction.updateItem(itemID, [material, renderItemsKey, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.addMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); + data.updateKey(renderItemsKey); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } @@ -1704,19 +1682,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string if (shapeID < _modelMeshRenderItemIDs.size()) { auto itemID = _modelMeshRenderItemIDs[shapeID]; bool visible = isVisible(); - uint8_t viewTagBits = getViewTagBits(); - bool layeredInFront = isLayeredInFront(); - bool layeredInHUD = isLayeredInHUD(); - bool canCastShadow = _canCastShadow; + auto renderItemsKey = _renderItemKeyGlobalFlags; bool wireframe = isWireframe(); auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool useDualQuaternionSkinning = _useDualQuaternionSkinning; - transaction.updateItem(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, + transaction.updateItem(itemID, [material, visible, renderItemsKey, invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { data.removeMaterial(material); // if the material changed, we might need to update our item key or shape key - data.updateKey(visible, layeredInFront || layeredInHUD, canCastShadow, viewTagBits); + data.updateKey(renderItemsKey); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning); }); } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 2b14a7c055..4180288106 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -33,6 +33,7 @@ #include #include +#include "RenderHifi.h" #include "GeometryCache.h" #include "TextureCache.h" #include "Rig.h" @@ -87,13 +88,27 @@ public: const QUrl& getURL() const { return _url; } // new Scene/Engine rendering support - void setVisibleInScene(bool isVisible, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + void setVisibleInScene(bool isVisible, const render::ScenePointer& scene = nullptr); + bool isVisible() const; - bool canCastShadow() const { return _canCastShadow; } - void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); + render::hifi::Tag getTagMask() const; + void setTagMask(uint8_t mask, const render::ScenePointer& scene = nullptr); + + bool isGroupCulled() const; + void setGroupCulled(bool isGroupCulled, const render::ScenePointer& scene = nullptr); + + bool canCastShadow() const; + void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene = nullptr); + + void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene = nullptr); + void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene = nullptr); + + bool isLayeredInFront() const; + bool isLayeredInHUD() const; + + // Access the current RenderItemKey Global Flags used by the model and applied to the render items representing the parts of the model. + const render::ItemKey getRenderItemKeyGlobalFlags() const; - void setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene); - void setLayeredInHUD(bool isLayeredInHUD, const render::ScenePointer& scene); bool needsFixupInScene() const; bool needsReload() const { return _needsReload; } @@ -108,13 +123,7 @@ public: void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction); bool isRenderable() const; - bool isVisible() const { return _isVisible; } - uint8_t getViewTagBits() const { return _viewTagBits; } - - bool isLayeredInFront() const { return _isLayeredInFront; } - bool isLayeredInHUD() const { return _isLayeredInHUD; } - - bool isGroupCulled() const { return _isGroupCulled; } + void updateRenderItemsKey(const render::ScenePointer& scene); virtual void updateRenderItems(); void setRenderItemsNeedUpdate(); @@ -404,10 +413,6 @@ protected: QVector _blendshapeCoefficients; QUrl _url; - bool _isVisible; - uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL }; - - bool _canCastShadow; gpu::Buffers _blendedVertexBuffers; @@ -471,10 +476,16 @@ protected: int _renderInfoDrawCalls { 0 }; int _renderInfoHasTransparent { false }; - bool _isLayeredInFront { false }; - bool _isLayeredInHUD { false }; - - bool _isGroupCulled{ false }; + // This Render ItemKey Global Flags capture the Model wide global set of flags that should be communicated to all the render items representing the Model. + // The flags concerned are: + // - isVisible: if true the Model is visible globally in the scene, regardless of the other flags in the item keys (tags or layer or shadow caster). + // - TagBits: the view mask defined through the TagBits telling in which view the Model is rendered if visible. + // - Layer: In which Layer this Model lives. + // - CastShadow: if true and visible and rendered in the view, the Model cast shadows if in a Light volume casting shadows. + // - CullGroup: if true, the render items representing the parts of the Model are culled by a single Meta render item that knows about them, they are not culled individually. + // For this to work, a Meta RI must exists and knows about the RIs of this Model. + // + render::ItemKey _renderItemKeyGlobalFlags; bool shouldInvalidatePayloadShapeKey(int meshIndex); diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index 3ea56f8542..47cab54d09 100644 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -27,6 +27,7 @@ #include #include +#include "RenderHifi.h" #include "RenderCommonTask.h" #include "LightingModel.h" #include "StencilMaskPass.h" @@ -200,8 +201,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren const auto overlaysInFrontRangeTimer = task.addJob("BeginOverlaysInFrontRangeTimer", "BeginOverlaysInFrontRangeTimer"); // Layered Overlays - const auto filteredOverlaysOpaque = task.addJob("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT); - const auto filteredOverlaysTransparent = task.addJob("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT); + const auto filteredOverlaysOpaque = task.addJob("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT); + const auto filteredOverlaysTransparent = task.addJob("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT); const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN(0); const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN(0); diff --git a/libraries/render-utils/src/RenderForwardTask.cpp b/libraries/render-utils/src/RenderForwardTask.cpp index 4388a39cf3..09a2afb711 100755 --- a/libraries/render-utils/src/RenderForwardTask.cpp +++ b/libraries/render-utils/src/RenderForwardTask.cpp @@ -23,6 +23,7 @@ #include +#include "RenderHifi.h" #include "StencilMaskPass.h" #include "ZoneRenderer.h" #include "FadeEffect.h" @@ -79,8 +80,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend task.addJob("PrepareStencil", framebuffer); // Layered Overlays - const auto filteredOverlaysOpaque = task.addJob("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT); - const auto filteredOverlaysTransparent = task.addJob("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT); + const auto filteredOverlaysOpaque = task.addJob("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT); + const auto filteredOverlaysTransparent = task.addJob("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT); const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN(0); const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN(0); diff --git a/libraries/render-utils/src/RenderHifi.h b/libraries/render-utils/src/RenderHifi.h new file mode 100644 index 0000000000..c489a0ad1d --- /dev/null +++ b/libraries/render-utils/src/RenderHifi.h @@ -0,0 +1,43 @@ +// +// RenderHifi.h +// libraries/render-utils/src +// +// Created by Sam Gateau on 5/30/2018. +// Copyright 2018 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +#ifndef hifi_RenderHifi_h +#define hifi_RenderHifi_h + +#include + + + +// In the library render-utils we are specializing the generic components of the render library to create the custom hifi render engine +// Objects and types serving this goal are define in the namespace render.hifi +// TODO: extend the namespace to all the classes where it make sense in render-utils +namespace render { + namespace hifi { + + // Tag is the alias names of render::ItemKey::Tag combinations used in the Hifi Render Engine + enum Tag : uint8_t { + TAG_NONE = render::ItemKey::TAG_BITS_NONE, // No Tags at all + TAG_MAIN_VIEW = render::ItemKey::TAG_BITS_0, // Main view + TAG_SECONDARY_VIEW = render::ItemKey::TAG_BITS_1, // Secondary View + TAG_ALL_VIEWS = TAG_MAIN_VIEW | TAG_SECONDARY_VIEW, // All views + }; + + // Layer is the alias names of the render::ItemKey::Layer used in the Hifi Render Engine + enum Layer : uint8_t { + LAYER_3D = render::ItemKey::LAYER_DEFAULT, + LAYER_3D_FRONT = render::ItemKey::LAYER_1, + LAYER_3D_HUD = render::ItemKey::LAYER_2, + LAYER_2D = render::ItemKey::LAYER_3, + LAYER_BACKGROUND = render::ItemKey::LAYER_BACKGROUND, + }; + } +} + +#endif // hifi_RenderHifi_h diff --git a/libraries/render/src/render/CullTask.cpp b/libraries/render/src/render/CullTask.cpp index b5819f114f..3f55e6dedc 100644 --- a/libraries/render/src/render/CullTask.cpp +++ b/libraries/render/src/render/CullTask.cpp @@ -368,9 +368,9 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input RenderArgs* args = renderContext->args; const auto& inShapes = inputs.get0(); - const auto& cullFilter = inputs.get1(); - const auto& boundsFilter = inputs.get2(); - const auto& antiFrustum = inputs.get3(); + const auto& cullFilter = inputs.get1(); + const auto& boundsFilter = inputs.get2(); + const auto& antiFrustum = inputs.get3(); auto& outShapes = outputs.edit0(); auto& outBounds = outputs.edit1(); @@ -380,7 +380,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { auto& details = args->_details.edit(_detailType); Test test(_cullFunctor, args, details, antiFrustum); - auto scene = args->_scene; + auto scene = args->_scene; for (auto& inItems : inShapes) { auto key = inItems.first; @@ -395,26 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input if (antiFrustum == nullptr) { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } } } } else { for (auto& item : inItems.second) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { - const auto shapeKey = scene->getItem(item.id).getKey(); - if (cullFilter.test(shapeKey)) { - outItems->second.emplace_back(item); - } - if (boundsFilter.test(shapeKey)) { - outBounds += item.bound; - } - } + const auto shapeKey = scene->getItem(item.id).getKey(); + if (cullFilter.test(shapeKey)) { + outItems->second.emplace_back(item); + } + if (boundsFilter.test(shapeKey)) { + outBounds += item.bound; + } + } } } details._rendered += (int)outItems->second.size(); @@ -487,6 +487,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext, if (filter.test(item.getKey())) { ItemBound itemBound(id, item.getBound()); outItems.emplace_back(itemBound); + } } } diff --git a/libraries/render/src/render/Item.cpp b/libraries/render/src/render/Item.cpp index 9c5efb9fa7..532964777f 100644 --- a/libraries/render/src/render/Item.cpp +++ b/libraries/render/src/render/Item.cpp @@ -29,25 +29,9 @@ const float Item::Status::Value::CYAN = 180.0f; const float Item::Status::Value::BLUE = 240.0f; const float Item::Status::Value::MAGENTA = 300.0f; -const int Item::LAYER_2D = 0; -const int Item::LAYER_3D = 1; -const int Item::LAYER_3D_FRONT = 2; -const int Item::LAYER_3D_HUD = 3; - -const uint8_t ItemKey::TAG_BITS_ALL { 0xFF }; -const uint8_t ItemKey::TAG_BITS_NONE { 0x00 }; -const uint8_t ItemKey::TAG_BITS_0 { 0x01 }; -const uint8_t ItemKey::TAG_BITS_1 { 0x02 }; -const uint8_t ItemKey::TAG_BITS_2 { 0x04 }; -const uint8_t ItemKey::TAG_BITS_3 { 0x08 }; -const uint8_t ItemKey::TAG_BITS_4 { 0x10 }; -const uint8_t ItemKey::TAG_BITS_5 { 0x20 }; -const uint8_t ItemKey::TAG_BITS_6 { 0x40 }; -const uint8_t ItemKey::TAG_BITS_7 { 0x80 }; - const uint32_t ItemKey::KEY_TAG_BITS_MASK = ((uint32_t) ItemKey::TAG_BITS_ALL) << FIRST_TAG_BIT; - +const uint32_t ItemKey::KEY_LAYER_BITS_MASK = ((uint32_t)ItemKey::LAYER_BITS_ALL) << FIRST_LAYER_BIT; void Item::Status::Value::setScale(float scale) { _scale = (std::numeric_limits::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f)); diff --git a/libraries/render/src/render/Item.h b/libraries/render/src/render/Item.h index b8a3fbf0f8..1dfef73686 100644 --- a/libraries/render/src/render/Item.h +++ b/libraries/render/src/render/Item.h @@ -52,23 +52,45 @@ public: TAG_6, TAG_7, - NUM_TAGS + NUM_TAGS, + + // Tag bits are derived from the Tag enum + TAG_BITS_ALL = 0xFF, + TAG_BITS_NONE = 0x00, + TAG_BITS_0 = 0x01, + TAG_BITS_1 = 0x02, + TAG_BITS_2 = 0x04, + TAG_BITS_3 = 0x08, + TAG_BITS_4 = 0x10, + TAG_BITS_5 = 0x20, + TAG_BITS_6 = 0x40, + TAG_BITS_7 = 0x80, + }; + + // Items are organized in layers, an item belongs to one of the 8 Layers available. + // By default an item is in the 'LAYER_DEFAULT' meaning that it is NOT layered. + // THere is NO ordering relationship between layers. + enum Layer : uint8_t { + LAYER_DEFAULT = 0, // layer 0 aka Default is a 'NOT' layer, items are not considered layered, this is the default value + LAYER_1, + LAYER_2, + LAYER_3, + LAYER_4, + LAYER_5, + LAYER_6, + LAYER_BACKGROUND, // Last Layer is the background by convention + + NUM_LAYERS, + + // Layer bits are derived from the Layer enum, the number of bits needed to represent integer 0 to NUM_LAYERS + NUM_LAYER_BITS = 3, + LAYER_BITS_ALL = 0x07, }; - // Tag bits are derived from the Tag enum - const static uint8_t TAG_BITS_ALL; - const static uint8_t TAG_BITS_NONE; - const static uint8_t TAG_BITS_0; - const static uint8_t TAG_BITS_1; - const static uint8_t TAG_BITS_2; - const static uint8_t TAG_BITS_3; - const static uint8_t TAG_BITS_4; - const static uint8_t TAG_BITS_5; - const static uint8_t TAG_BITS_6; - const static uint8_t TAG_BITS_7; enum FlagBit : uint32_t { - TYPE_SHAPE = 0, // Item is a Shape - TYPE_LIGHT, // Item is a Light + TYPE_SHAPE = 0, // Item is a Shape: Implements the Shape Interface that draw a Geometry rendered with a Material + TYPE_LIGHT, // Item is a Light: Implements the Light Interface that + TYPE_CAMERA, // Item is a Camera: Implements the Camera Interface TYPE_META, // Item is a Meta: meanning it s used to represent a higher level object, potentially represented by other render items TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work... @@ -77,13 +99,15 @@ public: DEFORMED, // Deformed within bound, not solid INVISIBLE, // Visible or not in the scene? SHADOW_CASTER, // Item cast shadows - LAYERED, // Item belongs to one of the layers different from the default layer META_CULL_GROUP, // As a meta item, the culling of my sub items is based solely on my bounding box and my visibility in the view SUB_META_CULLED, // As a sub item of a meta render item set as cull group, need to be set to my culling to the meta render it FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, + FIRST_LAYER_BIT, // 8 Exclusive Layers (encoded in 3 bits) available to organize the items in layers, an item can only belong to ONE layer + LAST_LAYER_BIT = FIRST_LAYER_BIT + NUM_LAYER_BITS, + __SMALLER, // Reserved bit for spatialized item to indicate that it is smaller than expected in the cell in which it belongs (probably because it overlaps over several smaller cells) NUM_FLAGS, // Not a valid flag @@ -96,6 +120,12 @@ public: return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT); } + // All the bits touching layer bits sets to true + const static uint32_t KEY_LAYER_BITS_MASK; + static uint32_t evalLayerBitsWithKeyBits(uint8_t layer, const uint32_t keyBits) { + return (keyBits & ~KEY_LAYER_BITS_MASK) | (((uint32_t)layer & LAYER_BITS_ALL) << FIRST_LAYER_BIT); + } + // The key is the Flags Flags _flags; @@ -124,19 +154,24 @@ public: Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); return (*this); } - Builder& withLayered() { _flags.set(LAYERED); return (*this); } + Builder& withoutShadowCaster() { _flags.reset(SHADOW_CASTER); return (*this); } Builder& withMetaCullGroup() { _flags.set(META_CULL_GROUP); return (*this); } + Builder& withoutMetaCullGroup() { _flags.reset(META_CULL_GROUP); return (*this); } Builder& withSubMetaCulled() { _flags.set(SUB_META_CULLED); return (*this); } + Builder& withoutSubMetaCulled() { _flags.reset(SUB_META_CULLED); return (*this); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); } // Set ALL the tags in one call using the Tag bits Builder& withTagBits(uint8_t tagBits) { _flags = evalTagBitsWithKeyBits(tagBits, _flags.to_ulong()); return (*this); } + Builder& withLayer(uint8_t layer) { _flags = evalLayerBitsWithKeyBits(layer, _flags.to_ulong()); return (*this); } + Builder& withoutLayer() { return withLayer(LAYER_DEFAULT); } + // Convenient standard keys that we will keep on using all over the place static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder light() { return Builder().withTypeLight(); } - static Builder background() { return Builder().withViewSpace().withLayered(); } + static Builder background() { return Builder().withViewSpace().withLayer(LAYER_BACKGROUND); } }; ItemKey(const Builder& builder) : ItemKey(builder._flags) {} @@ -161,9 +196,6 @@ public: bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } - bool isLayered() const { return _flags[LAYERED]; } - bool isSpatial() const { return !isLayered(); } - bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; } void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(META_CULL_GROUP)); } @@ -173,6 +205,11 @@ public: bool isTag(Tag tag) const { return _flags[FIRST_TAG_BIT + tag]; } uint8_t getTagBits() const { return ((_flags.to_ulong() & KEY_TAG_BITS_MASK) >> FIRST_TAG_BIT); } + uint8_t getLayer() const { return ((_flags.to_ulong() & KEY_LAYER_BITS_MASK) >> FIRST_LAYER_BIT); } + bool isLayer(uint8_t layer) const { return getLayer() == layer; } + bool isLayered() const { return getLayer() != LAYER_DEFAULT; } + bool isSpatial() const { return !isLayered(); } + // Probably not public, flags used by the scene bool isSmall() const { return _flags[__SMALLER]; } void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__SMALLER)); } @@ -230,9 +267,6 @@ public: Builder& withNoShadowCaster() { _value.reset(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } Builder& withShadowCaster() { _value.set(ItemKey::SHADOW_CASTER); _mask.set(ItemKey::SHADOW_CASTER); return (*this); } - Builder& withoutLayered() { _value.reset(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } - Builder& withLayered() { _value.set(ItemKey::LAYERED); _mask.set(ItemKey::LAYERED); return (*this); } - Builder& withoutMetaCullGroup() { _value.reset(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } Builder& withMetaCullGroup() { _value.set(ItemKey::META_CULL_GROUP); _mask.set(ItemKey::META_CULL_GROUP); return (*this); } @@ -244,6 +278,9 @@ public: // Set ALL the tags in one call using the Tag bits and the Tag bits touched Builder& withTagBits(uint8_t tagBits, uint8_t tagMask) { _value = ItemKey::evalTagBitsWithKeyBits(tagBits, _value.to_ulong()); _mask = ItemKey::evalTagBitsWithKeyBits(tagMask, _mask.to_ulong()); return (*this); } + Builder& withoutLayered() { _value = ItemKey::evalLayerBitsWithKeyBits(ItemKey::LAYER_DEFAULT, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } + Builder& withLayer(uint8_t layer) { _value = ItemKey::evalLayerBitsWithKeyBits(layer, _value.to_ulong()); _mask |= ItemKey::KEY_LAYER_BITS_MASK; return (*this); } + Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); } // Convenient standard keys that we will keep on using all over the place @@ -252,9 +289,7 @@ public: static Builder transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); } static Builder light() { return Builder().withTypeLight(); } static Builder meta() { return Builder().withTypeMeta(); } - static Builder background() { return Builder().withViewSpace().withLayered(); } - static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); } - static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); } + static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); } static Builder nothing() { return Builder().withNothing(); } }; @@ -377,7 +412,6 @@ public: public: virtual const ItemKey getKey() const = 0; virtual const Bound getBound() const = 0; - virtual int getLayer() const = 0; virtual void render(RenderArgs* args) = 0; virtual const ShapeKey getShapeKey() const = 0; @@ -422,13 +456,8 @@ public: // Get the bound of the item expressed in world space (or eye space depending on the key.isWorldSpace()) const Bound getBound() const { return _payload->getBound(); } - // Get the layer where the item belongs. - int getLayer() const { return _payload->getLayer(); } - - static const int LAYER_2D; - static const int LAYER_3D; - static const int LAYER_3D_FRONT; - static const int LAYER_3D_HUD; + // Get the layer where the item belongs, simply reflecting the key. + int getLayer() const { return _key.getLayer(); } // Render call for the item void render(RenderArgs* args) const { _payload->render(args); } @@ -478,7 +507,6 @@ inline QDebug operator<<(QDebug debug, const Item& item) { // Item shared interface supported by the payload template const ItemKey payloadGetKey(const std::shared_ptr& payloadData) { return ItemKey(); } template const Item::Bound payloadGetBound(const std::shared_ptr& payloadData) { return Item::Bound(); } -template int payloadGetLayer(const std::shared_ptr& payloadData) { return 0; } template void payloadRender(const std::shared_ptr& payloadData, RenderArgs* args) { } // Shape type interface @@ -505,7 +533,6 @@ public: // Payload general interface virtual const ItemKey getKey() const override { return payloadGetKey(_data); } virtual const Item::Bound getBound() const override { return payloadGetBound(_data); } - virtual int getLayer() const override { return payloadGetLayer(_data); } virtual void render(RenderArgs* args) override { payloadRender(_data, args); } diff --git a/libraries/shared/src/shared/QtHelpers.h b/libraries/shared/src/shared/QtHelpers.h index 2133119324..3387be6909 100644 --- a/libraries/shared/src/shared/QtHelpers.h +++ b/libraries/shared/src/shared/QtHelpers.h @@ -48,6 +48,6 @@ bool blockingInvokeMethod( } } #define BLOCKING_INVOKE_METHOD(obj, member, ...) \ - hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__) + ::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__) #endif diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index b0cbf0e246..59a51830be 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -23,6 +23,7 @@ var DEFAULT_SCRIPTS_COMBINED = [ "system/makeUserConnection.js", "system/tablet-goto.js", "system/marketplaces/marketplaces.js", + "system/notifications.js", "system/commerce/wallet.js", "system/edit.js", "system/dialTone.js", diff --git a/scripts/system/notifications.js b/scripts/system/notifications.js index a28f343ad3..0778e2a44b 100644 --- a/scripts/system/notifications.js +++ b/scripts/system/notifications.js @@ -79,11 +79,7 @@ var frame = 0; var ctrlIsPressed = false; var ready = true; - var MENU_NAME = 'Tools > Notifications'; - var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds"; var NOTIFICATION_MENU_ITEM_POST = " Notifications"; - var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; - var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; var NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications"; var NotificationType = { @@ -401,11 +397,6 @@ alpha: backgroundAlpha }; - if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) && - Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) { - randomSounds.playRandom(); - } - return notify(noticeProperties, buttonProperties, height, imageProperties); } @@ -618,30 +609,6 @@ } } - function setup() { - var type; - Menu.addMenu(MENU_NAME); - var checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING); - checked = checked === '' ? true : checked; - Menu.addMenuItem({ - menuName: MENU_NAME, - menuItemName: PLAY_NOTIFICATION_SOUNDS_MENU_ITEM, - isCheckable: true, - isChecked: Settings.getValue(PLAY_NOTIFICATION_SOUNDS_SETTING) - }); - Menu.addSeparator(MENU_NAME, "Play sounds for:"); - for (type in NotificationType.properties) { - checked = Settings.getValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + (parseInt(type, 10) + 1)); - checked = checked === '' ? true : checked; - Menu.addMenuItem({ - menuName: MENU_NAME, - menuItemName: NotificationType.properties[type].text + NOTIFICATION_MENU_ITEM_POST, - isCheckable: true, - isChecked: checked - }); - } - } - // When our script shuts down, we should clean up all of our overlays function scriptEnding() { var notificationIndex; @@ -649,27 +616,14 @@ Overlays.deleteOverlay(notifications[notificationIndex]); Overlays.deleteOverlay(buttons[notificationIndex]); } - Menu.removeMenu(MENU_NAME); Messages.unsubscribe(NOTIFICATIONS_MESSAGE_CHANNEL); } - function menuItemEvent(menuItem) { - if (menuItem === PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) { - Settings.setValue(PLAY_NOTIFICATION_SOUNDS_SETTING, Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM)); - return; - } - var notificationType = NotificationType.getTypeFromMenuItem(menuItem); - if (notificationType !== notificationType.UNKNOWN) { - Settings.setValue(PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE + notificationType, Menu.isOptionChecked(menuItem)); - } - } - Controller.keyPressEvent.connect(keyPressEvent); Controller.mousePressEvent.connect(mousePressEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); - Menu.menuItemEvent.connect(menuItemEvent); Window.domainConnectionRefused.connect(onDomainConnectionRefused); Window.stillSnapshotTaken.connect(onSnapshotTaken); Window.snapshot360Taken.connect(onSnapshotTaken); @@ -684,7 +638,4 @@ Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); Messages.messageReceived.connect(onMessageReceived); - - setup(); - }()); // END LOCAL_SCOPE diff --git a/tests/animation/src/RotationConstraintTests.cpp b/tests/animation/src/RotationConstraintTests.cpp index f8f94e8bee..c1b6bc5dba 100644 --- a/tests/animation/src/RotationConstraintTests.cpp +++ b/tests/animation/src/RotationConstraintTests.cpp @@ -47,7 +47,6 @@ void RotationConstraintTests::testElbowConstraint() { glm::quat inputRotation = referenceRotation; glm::quat outputRotation = inputRotation; bool updated = elbow.apply(outputRotation); - QVERIFY(updated == false); glm::quat expectedRotation = referenceRotation; QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); } @@ -62,7 +61,6 @@ void RotationConstraintTests::testElbowConstraint() { glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat outputRotation = inputRotation; bool updated = elbow.apply(outputRotation); - QVERIFY(updated == false); QCOMPARE_WITH_ABS_ERROR(inputRotation, outputRotation, EPSILON); } } @@ -72,7 +70,6 @@ void RotationConstraintTests::testElbowConstraint() { glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat outputRotation = inputRotation; bool updated = elbow.apply(outputRotation); - QVERIFY(updated == true); glm::quat expectedRotation = glm::angleAxis(minAngle, hingeAxis) * referenceRotation; QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); } @@ -82,7 +79,6 @@ void RotationConstraintTests::testElbowConstraint() { glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat outputRotation = inputRotation; bool updated = elbow.apply(outputRotation); - QVERIFY(updated == true); glm::quat expectedRotation = glm::angleAxis(maxAngle, hingeAxis) * referenceRotation; QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); } @@ -94,7 +90,6 @@ void RotationConstraintTests::testElbowConstraint() { glm::quat inputRotation = glm::angleAxis(someAngle, twistVector) * referenceRotation; glm::quat outputRotation = inputRotation; bool updated = elbow.apply(outputRotation); - QVERIFY(updated == true); glm::quat expectedRotation = referenceRotation; QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); } diff --git a/tools/auto-tester/src/ImageComparer.cpp b/tools/auto-tester/src/ImageComparer.cpp index eb892484a2..3afdeaec0a 100644 --- a/tools/auto-tester/src/ImageComparer.cpp +++ b/tools/auto-tester/src/ImageComparer.cpp @@ -15,6 +15,12 @@ // Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity // The value is computed for the luminance component and the average value is returned double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const { + // Make sure the image is 8 bits per colour + QImage::Format format = expectedImage.format(); + if (format != QImage::Format::Format_ARGB32) { + throw -1; + } + const int L = 255; // (2^number of bits per pixel) - 1 const double K1 { 0.01 }; const double K2 { 0.03 }; @@ -54,8 +60,8 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co // Collect pixels into linear arrays int i{ 0 }; - for (int xx = 0; xx < WIN_SIZE; ++xx) { - for (int yy = 0; yy < WIN_SIZE; ++yy) { + for (int xx = 0; xx < WIN_SIZE && x + xx < expectedImage.width(); ++xx) { + for (int yy = 0; yy < WIN_SIZE && y + yy < expectedImage.height(); ++yy) { // Get pixels QRgb pixelP = expectedImage.pixel(QPoint(x + xx, y + yy)); QRgb pixelQ = resultImage.pixel(QPoint(x + xx, y + yy)); diff --git a/tools/auto-tester/src/Test.cpp b/tools/auto-tester/src/Test.cpp index 23d097b855..1a25cc5c0e 100644 --- a/tools/auto-tester/src/Test.cpp +++ b/tools/auto-tester/src/Test.cpp @@ -63,7 +63,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar) // 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.99 }; + const double THRESHOLD { 0.9995 }; bool success{ true }; bool keepOn{ true }; for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) { @@ -131,7 +131,9 @@ void Test::appendTestResultsToFile(const QString& testResultsFolderPath, TestFai exit(-1); } - QString failureFolderPath { testResultsFolderPath + "/" + "Failure_" + QString::number(index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) }; + QString err = QString::number(testFailure._error).left(6); + + QString failureFolderPath { testResultsFolderPath + "/" + err + "-Failure_" + QString::number(index) + "--" + testFailure._actualImageFilename.left(testFailure._actualImageFilename.length() - 4) }; if (!QDir().mkdir(failureFolderPath)) { QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); exit(-1); @@ -395,9 +397,9 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact const QString DATE_TIME_FORMAT("MMM d yyyy, h:mm"); textStream << "// This is an automatically generated file, created by auto-tester on " << QDateTime::currentDateTime().toString(DATE_TIME_FORMAT) << endl << endl; - textStream << "user = \"" + GIT_HUB_USER + "/\"" << endl; - textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\"" << endl; - textStream << "branch = \"" + GIT_HUB_BRANCH + "/\"" << endl << endl; + textStream << "user = \"" + GIT_HUB_USER + "/\";" << endl; + textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\";" << endl; + textStream << "branch = \"" + GIT_HUB_BRANCH + "/\";" << endl << endl; textStream << "var autoTester = Script.require(\"https://github.com/" + GIT_HUB_USER + "/hifi_tests/blob/" + GIT_HUB_BRANCH + "/tests/utils/autoTester.js?raw=true\");" << endl << endl; diff --git a/tools/auto-tester/src/ui/AutoTester.cpp b/tools/auto-tester/src/ui/AutoTester.cpp index ea2633edf4..14329e36c2 100644 --- a/tools/auto-tester/src/ui/AutoTester.cpp +++ b/tools/auto-tester/src/ui/AutoTester.cpp @@ -10,6 +10,11 @@ // #include "AutoTester.h" +#ifdef Q_OS_WIN +#include +#include +#endif + AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); ui.checkBoxInteractiveMode->setChecked(true); @@ -20,6 +25,11 @@ AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { connect(ui.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked); connect(ui.actionAbout, &QAction::triggered, this, &AutoTester::about); +#ifndef Q_OS_WIN + ui.hideTaskbarButton->setVisible(false); + ui.showTaskbarButton->setVisible(false); +#endif + test = new Test(); } @@ -56,6 +66,30 @@ void AutoTester::on_createTestsOutlineButton_clicked() { test->createTestsOutline(); } +// To toggle between show and hide +// if (uState & ABS_AUTOHIDE) on_showTaskbarButton_clicked(); +// else on_hideTaskbarButton_clicked(); +// +void AutoTester::on_hideTaskbarButton_clicked() { +#ifdef Q_OS_WIN + APPBARDATA abd = { sizeof abd }; + UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd); + LPARAM param = uState & ABS_ALWAYSONTOP; + abd.lParam = ABS_AUTOHIDE | param; + SHAppBarMessage(ABM_SETSTATE, &abd); +#endif +} + +void AutoTester::on_showTaskbarButton_clicked() { +#ifdef Q_OS_WIN + APPBARDATA abd = { sizeof abd }; + UINT uState = (UINT)SHAppBarMessage(ABM_GETSTATE, &abd); + LPARAM param = uState & ABS_ALWAYSONTOP; + abd.lParam = param; + SHAppBarMessage(ABM_SETSTATE, &abd); +#endif +} + void AutoTester::on_closeButton_clicked() { exit(0); } @@ -95,7 +129,7 @@ void AutoTester::saveImage(int index) { pixmap.loadFromData(downloaders[index]->downloadedData()); QImage image = pixmap.toImage(); - image = image.convertToFormat(QImage::Format_RGB32); + image = image.convertToFormat(QImage::Format_ARGB32); QString fullPathname = _directoryName + "/" + _filenames[index]; if (!image.save(fullPathname, 0, 100)) { diff --git a/tools/auto-tester/src/ui/AutoTester.h b/tools/auto-tester/src/ui/AutoTester.h index 5991afed1b..7b419a9af8 100644 --- a/tools/auto-tester/src/ui/AutoTester.h +++ b/tools/auto-tester/src/ui/AutoTester.h @@ -36,6 +36,10 @@ private slots: void on_createMDFileButton_clicked(); void on_createAllMDFilesButton_clicked(); void on_createTestsOutlineButton_clicked(); + + void on_hideTaskbarButton_clicked(); + void on_showTaskbarButton_clicked(); + void on_closeButton_clicked(); void saveImage(int index); diff --git a/tools/auto-tester/src/ui/AutoTester.ui b/tools/auto-tester/src/ui/AutoTester.ui index c9ea229012..236138acf4 100644 --- a/tools/auto-tester/src/ui/AutoTester.ui +++ b/tools/auto-tester/src/ui/AutoTester.ui @@ -147,6 +147,32 @@ Create Tests Outline + + + + 490 + 280 + 91 + 40 + + + + Show Taskbar + + + + + + 490 + 230 + 91 + 40 + + + + Hide Taskbar + +