Merge branch 'master' of github.com:highfidelity/hifi into infinite-scroll

This commit is contained in:
howard-stearns 2018-06-01 09:58:08 -07:00
commit 84f5f0a653
43 changed files with 647 additions and 522 deletions

View file

@ -8,48 +8,46 @@
// Distributed under the Apache License, Version 2.0. // Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// //
#include "AboutUtil.h"
#include <QDate> #include <QDate>
#include <QLocale> #include <QLocale>
#include "AboutUtil.h"
#include "BuildInfo.h"
#include <ui/TabletScriptingInterface.h> #include <ui/TabletScriptingInterface.h>
#include <OffscreenQmlDialog.h>
#include "BuildInfo.h"
#include "DependencyManager.h" #include "DependencyManager.h"
#include "scripting/HMDScriptingInterface.h" #include "scripting/HMDScriptingInterface.h"
#include "Application.h" #include "Application.h"
#include <OffscreenQmlDialog.h>
AboutUtil::AboutUtil(QObject *parent) : QObject(parent) { AboutUtil::AboutUtil(QObject *parent) : QObject(parent) {
QLocale locale_; QLocale locale;
m_DateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy"). _dateConverted = QDate::fromString(BuildInfo::BUILD_TIME, "dd/MM/yyyy").
toString(locale_.dateFormat(QLocale::ShortFormat)); toString(locale.dateFormat(QLocale::ShortFormat));
} }
AboutUtil *AboutUtil::getInstance() AboutUtil *AboutUtil::getInstance() {
{
static AboutUtil instance; static AboutUtil instance;
return &instance; return &instance;
} }
QString AboutUtil::buildDate() const QString AboutUtil::getBuildDate() const {
{ return _dateConverted;
return m_DateConverted;
} }
QString AboutUtil::buildVersion() const QString AboutUtil::getBuildVersion() const {
{
return BuildInfo::VERSION; return BuildInfo::VERSION;
} }
QString AboutUtil::qtVersion() const QString AboutUtil::getQtVersion() const {
{
return qVersion(); return qVersion();
} }
void AboutUtil::openUrl(const QString& url) const { void AboutUtil::openUrl(const QString& url) const {
auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>(); auto tabletScriptingInterface = DependencyManager::get<TabletScriptingInterface>();
auto tablet = dynamic_cast<TabletProxy*>(tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system")); auto tablet = tabletScriptingInterface->getTablet("com.highfidelity.interface.tablet.system");
auto hmd = DependencyManager::get<HMDScriptingInterface>(); auto hmd = DependencyManager::get<HMDScriptingInterface>();
auto offscreenUi = DependencyManager::get<OffscreenUi>(); auto offscreenUi = DependencyManager::get<OffscreenUi>();

View file

@ -16,27 +16,24 @@
#include <QObject> #include <QObject>
class AboutUtil : public QObject { class AboutUtil : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(QString buildDate READ buildDate CONSTANT) Q_PROPERTY(QString buildDate READ getBuildDate CONSTANT)
Q_PROPERTY(QString buildVersion READ buildVersion CONSTANT) Q_PROPERTY(QString buildVersion READ getBuildVersion CONSTANT)
Q_PROPERTY(QString qtVersion READ qtVersion CONSTANT) Q_PROPERTY(QString qtVersion READ getQtVersion CONSTANT)
AboutUtil(QObject* parent = nullptr);
public: public:
static AboutUtil* getInstance(); static AboutUtil* getInstance();
~AboutUtil() {} ~AboutUtil() {}
QString buildDate() const; QString getBuildDate() const;
QString buildVersion() const; QString getBuildVersion() const;
QString qtVersion() const; QString getQtVersion() const;
public slots: public slots:
void openUrl(const QString &url) const; void openUrl(const QString &url) const;
private: private:
AboutUtil(QObject* parent = nullptr);
QString m_DateConverted; QString _dateConverted;
}; };
#endif // hifi_AboutUtil_h #endif // hifi_AboutUtil_h

View file

@ -3645,7 +3645,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
_keysPressed.insert(event->key()); _keysPressed.insert(event->key());
_controllerScriptingInterface->emitKeyPressEvent(event); // send events to any registered scripts _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 one of our scripts have asked to capture this event, then stop processing it
if (_controllerScriptingInterface->isKeyCaptured(event)) { if (_controllerScriptingInterface->isKeyCaptured(event)) {
return; return;
@ -3730,6 +3729,13 @@ void Application::keyPressEvent(QKeyEvent* event) {
} }
break; break;
case Qt::Key_R:
if (isMeta && !event->isAutoRepeat()) {
DependencyManager::get<ScriptEngines>()->reloadAllScripts();
DependencyManager::get<OffscreenUi>()->clearCache();
}
break;
case Qt::Key_Asterisk: case Qt::Key_Asterisk:
Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox); Menu::getInstance()->triggerOption(MenuOption::DefaultSkybox);
break; break;

View file

@ -104,6 +104,9 @@ void AvatarManager::updateMyAvatar(float deltaTime) {
PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()"); PerformanceWarning warn(showWarnings, "AvatarManager::updateMyAvatar()");
_myAvatar->update(deltaTime); _myAvatar->update(deltaTime);
render::Transaction transaction;
_myAvatar->updateRenderItem(transaction);
qApp->getMain3DScene()->enqueueTransaction(transaction);
quint64 now = usecTimestampNow(); quint64 now = usecTimestampNow();
quint64 dt = now - _lastSendAvatarDataTime; quint64 dt = now - _lastSendAvatarDataTime;

View file

@ -1127,7 +1127,11 @@ void MyAvatar::setEnableDebugDrawIKChains(bool isEnabled) {
} }
void MyAvatar::setEnableMeshVisible(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) { void MyAvatar::setEnableInverseKinematics(bool isEnabled) {
@ -1479,7 +1483,10 @@ void MyAvatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
_skeletonModelChangeCount++; _skeletonModelChangeCount++;
int skeletonModelChangeCount = _skeletonModelChangeCount; int skeletonModelChangeCount = _skeletonModelChangeCount;
Avatar::setSkeletonModelURL(skeletonModelURL); 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(); _headBoneSet.clear();
_cauterizationNeedsUpdate = true; _cauterizationNeedsUpdate = true;
@ -2054,14 +2061,12 @@ void MyAvatar::preDisplaySide(const RenderArgs* renderArgs) {
_attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("RightEye", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 || _attachmentData[i].jointName.compare("HeadTop_End", Qt::CaseInsensitive) == 0 ||
_attachmentData[i].jointName.compare("Face", 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; uint8_t modelRenderTagBits = shouldDrawHead ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_SECONDARY_VIEW;
modelRenderTagBits |= render::ItemKey::TAG_BITS_1;
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene(),
modelRenderTagBits, false);
uint8_t castShadowRenderTagBits = render::ItemKey::TAG_BITS_0 | render::ItemKey::TAG_BITS_1; _attachmentModels[i]->setTagMask(modelRenderTagBits);
_attachmentModels[i]->setCanCastShadow(true, qApp->getMain3DScene(), _attachmentModels[i]->setGroupCulled(false);
castShadowRenderTagBits, false); _attachmentModels[i]->setCanCastShadow(true);
_attachmentModels[i]->setVisibleInScene(true, qApp->getMain3DScene());
} }
} }
} }

View file

@ -1159,7 +1159,7 @@ public slots:
* @function MyAvatar.getEnableMeshVisible * @function MyAvatar.getEnableMeshVisible
* @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>. * @returns {boolean} <code>true</code> if your avatar's mesh is visible, otherwise <code>false</code>.
*/ */
bool getEnableMeshVisible() const { return _skeletonModel->isVisible(); } bool getEnableMeshVisible() const override;
/**jsdoc /**jsdoc
* Set whether or not your avatar mesh is visible. * Set whether or not your avatar mesh is visible.
@ -1171,7 +1171,7 @@ public slots:
* MyAvatar.setEnableMeshVisible(true); * MyAvatar.setEnableMeshVisible(true);
* }, 10000); * }, 10000);
*/ */
void setEnableMeshVisible(bool isEnabled); virtual void setEnableMeshVisible(bool isEnabled) override;
/**jsdoc /**jsdoc
* @function MyAvatar.setEnableInverseKinematics * @function MyAvatar.setEnableInverseKinematics

View file

@ -14,6 +14,7 @@
#include <shared/FileUtils.h> #include <shared/FileUtils.h>
#include <shared/QtHelpers.h> #include <shared/QtHelpers.h>
#include <DependencyManager.h> #include <DependencyManager.h>
#include <MainWindow.h>
#include <OffscreenUi.h> #include <OffscreenUi.h>
#include <StatTracker.h> #include <StatTracker.h>
#include <Trace.h> #include <Trace.h>
@ -186,3 +187,7 @@ void TestScriptingInterface::saveObject(QVariant variant, const QString& filenam
file.write(jsonData); file.write(jsonData);
file.close(); file.close();
} }
void TestScriptingInterface::showMaximized() {
qApp->getWindow()->showMaximized();
}

View file

@ -27,70 +27,128 @@ public slots:
/**jsdoc /**jsdoc
* Exits the application * Exits the application
* @function Test.quit
*/ */
void quit(); void quit();
/**jsdoc /**jsdoc
* Waits for all texture transfers to be complete * Waits for all texture transfers to be complete
* @function Test.waitForTextureIdle
*/ */
void waitForTextureIdle(); void waitForTextureIdle();
/**jsdoc /**jsdoc
* Waits for all pending downloads to be complete * Waits for all pending downloads to be complete
* @function Test.waitForDownloadIdle
*/ */
void waitForDownloadIdle(); void waitForDownloadIdle();
/**jsdoc /**jsdoc
* Waits for all file parsing operations to be complete * Waits for all file parsing operations to be complete
* @function Test.waitForProcessingIdle
*/ */
void waitForProcessingIdle(); void waitForProcessingIdle();
/**jsdoc /**jsdoc
* Waits for all pending downloads, parsing and texture transfers to be complete * Waits for all pending downloads, parsing and texture transfers to be complete
* @function Test.waitIdle
*/ */
void 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); 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); 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); bool loadTestScene(QString sceneFile);
/**jsdoc
* Clears all caches
* @function Test.clear
*/
void clear(); void clear();
/**jsdoc /**jsdoc
* Start recording Chrome compatible tracing events * Start recording Chrome compatible tracing events
* logRules can be used to specify a set of logging category rules to limit what gets captured * 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 = ""); bool startTracing(QString logrules = "");
/**jsdoc /**jsdoc
* Stop recording Chrome compatible tracing events and serialize recorded events to a file * 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 * 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); bool stopTracing(QString filename);
/**jsdoc
* Starts a specific trace event
* @function Test.startTraceEvent
* @param {string} name - Name of event
*/
void startTraceEvent(QString name); 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); void endTraceEvent(QString name);
/**jsdoc /**jsdoc
* Write detailed timing stats of next physics stepSimulation() to filename * 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); 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); Q_INVOKABLE void profileRange(const QString& name, QScriptValue function);
/**jsdoc /**jsdoc
* Clear all caches (menu command Reload Content) * Clear all caches (menu command Reload Content)
* @function Test.clearCaches
*/ */
void clearCaches(); void clearCaches();
/**jsdoc /**jsdoc
* Save a JSON object to a file in the test results location * 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); void saveObject(QVariant v, const QString& filename);
/**jsdoc
* Maximizes the window
* @function Test.showMaximized
*/
void showMaximized();
private: private:
bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition); bool waitForCondition(qint64 maxWaitMs, std::function<bool()> condition);
QString _testResultsLocation; QString _testResultsLocation;

View file

@ -103,10 +103,9 @@ void ModelOverlay::update(float deltatime) {
if (_visibleDirty) { if (_visibleDirty) {
_visibleDirty = false; _visibleDirty = false;
// don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true // don't show overlays in mirrors or spectator-cam unless _isVisibleInSecondaryCamera is true
_model->setVisibleInScene(getVisible(), scene, uint8_t modelRenderTagMask = (_isVisibleInSecondaryCamera ? render::hifi::TAG_ALL_VIEWS : render::hifi::TAG_MAIN_VIEW);
render::ItemKey::TAG_BITS_0 | _model->setTagMask(modelRenderTagMask, scene);
(_isVisibleInSecondaryCamera ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE), _model->setVisibleInScene(getVisible(), scene);
false);
} }
if (_drawInFrontDirty) { if (_drawInFrontDirty) {
_drawInFrontDirty = false; _drawInFrontDirty = false;

View file

@ -132,7 +132,6 @@ private:
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay); template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay);
template <> const Item::Bound payloadGetBound(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 <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args);
template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay); template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay);
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems); template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems);

View file

@ -35,14 +35,18 @@ namespace render {
auto builder = ItemKey::Builder().withTypeShape(); auto builder = ItemKey::Builder().withTypeShape();
if (overlay->is3D()) { if (overlay->is3D()) {
auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay); auto overlay3D = std::static_pointer_cast<Base3DOverlay>(overlay);
if (overlay3D->getDrawInFront() || overlay3D->getDrawHUDLayer()) { if (overlay3D->getDrawInFront()) {
builder.withLayered(); builder.withLayer(render::hifi::LAYER_3D_FRONT);
} else if (overlay3D->getDrawHUDLayer()) {
builder.withLayer(render::hifi::LAYER_3D_HUD);
} }
if (overlay->isTransparent()) { if (overlay->isTransparent()) {
builder.withTransparent(); builder.withTransparent();
} }
} else { } else {
builder.withViewSpace(); builder.withViewSpace();
builder.withLayer(render::hifi::LAYER_2D);
} }
if (!overlay->getVisible()) { if (!overlay->getVisible()) {
@ -50,30 +54,16 @@ namespace render {
} }
// always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view // always visible in primary view. if isVisibleInSecondaryCamera, also draw in secondary view
uint32_t viewTaskBits = render::ItemKey::TAG_BITS_0 | uint32_t viewTagBits = render::hifi::TAG_MAIN_VIEW |
(overlay->getIsVisibleInSecondaryCamera() ? render::ItemKey::TAG_BITS_1 : render::ItemKey::TAG_BITS_NONE); (overlay->getIsVisibleInSecondaryCamera() ? render::hifi::TAG_SECONDARY_VIEW : render::hifi::TAG_NONE);
builder.withTagBits(viewTaskBits); builder.withTagBits(viewTagBits);
return builder.build(); return builder.build();
} }
template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) { template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) {
return overlay->getBounds(); return overlay->getBounds();
} }
template <> int payloadGetLayer(const Overlay::Pointer& overlay) {
if (overlay->is3D()) {
auto overlay3D = std::dynamic_pointer_cast<Base3DOverlay>(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) { template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args) {
if (args) { if (args) {
overlay->render(args); overlay->render(args);
@ -83,7 +73,6 @@ namespace render {
return overlay->getShapeKey(); return overlay->getShapeKey();
} }
template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) { template <> uint32_t metaFetchMetaSubItems(const Overlay::Pointer& overlay, ItemIDs& subItems) {
return overlay->fetchMetaSubItems(subItems); return overlay->fetchMetaSubItems(subItems);
} }

View file

@ -52,10 +52,15 @@ const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) { 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>(avatar);
if (!avatarPtr->getEnableMeshVisible()) {
keyBuilder.withInvisible();
}
return keyBuilder.build();
} }
template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) { template <> const Item::Bound payloadGetBound(const AvatarSharedPointer& avatar) {
return static_pointer_cast<Avatar>(avatar)->getBounds(); return static_pointer_cast<Avatar>(avatar)->getRenderBounds();
} }
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) { template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
auto avatarPtr = static_pointer_cast<Avatar>(avatar); auto avatarPtr = static_pointer_cast<Avatar>(avatar);
@ -164,6 +169,11 @@ AABox Avatar::getBounds() const {
return _skeletonModel->getRenderableMeshBound(); return _skeletonModel->getRenderableMeshBound();
} }
AABox Avatar::getRenderBounds() const {
return _renderBound;
}
void Avatar::animateScaleChanges(float deltaTime) { void Avatar::animateScaleChanges(float deltaTime) {
if (_isAnimatingScale) { if (_isAnimatingScale) {
@ -569,16 +579,26 @@ static TextRenderer3D* textRenderer(TextRendererType type) {
void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) { void Avatar::addToScene(AvatarSharedPointer self, const render::ScenePointer& scene, render::Transaction& transaction) {
auto avatarPayload = new render::Payload<AvatarData>(self); auto avatarPayload = new render::Payload<AvatarData>(self);
auto avatarPayloadPointer = Avatar::PayloadPointer(avatarPayload); auto avatarPayloadPointer = std::shared_ptr<render::Payload<AvatarData>>(avatarPayload);
if (_renderItemID == render::Item::INVALID_ITEM_ID) { if (_renderItemID == render::Item::INVALID_ITEM_ID) {
_renderItemID = scene->allocateID(); _renderItemID = scene->allocateID();
} }
// INitialize the _render bound as we are creating the avatar render item
_renderBound = getBounds();
transaction.resetItem(_renderItemID, avatarPayloadPointer); transaction.resetItem(_renderItemID, avatarPayloadPointer);
_skeletonModel->addToScene(scene, transaction); _skeletonModel->addToScene(scene, transaction);
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setCanCastShadow(true);
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
processMaterials(); processMaterials();
for (auto& attachmentModel : _attachmentModels) { for (auto& attachmentModel : _attachmentModels) {
attachmentModel->addToScene(scene, transaction); attachmentModel->addToScene(scene, transaction);
attachmentModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
attachmentModel->setGroupCulled(false);
attachmentModel->setCanCastShadow(true);
attachmentModel->setVisibleInScene(_isMeshVisible, scene);
} }
_mustFadeIn = true; _mustFadeIn = true;
@ -637,7 +657,15 @@ void Avatar::removeFromScene(AvatarSharedPointer self, const render::ScenePointe
void Avatar::updateRenderItem(render::Transaction& transaction) { void Avatar::updateRenderItem(render::Transaction& transaction) {
if (render::Item::isValidID(_renderItemID)) { if (render::Item::isValidID(_renderItemID)) {
transaction.updateItem<render::Payload<AvatarData>>(_renderItemID, [](render::Payload<AvatarData>& p) {}); auto renderBound = getBounds();
transaction.updateItem<AvatarData>(_renderItemID,
[renderBound](AvatarData& avatar) {
auto avatarPtr = dynamic_cast<Avatar*>(&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) { void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
bool canTryFade{ false }; bool canTryFade{ false };
@ -770,6 +810,12 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) { if (_skeletonModel->isRenderable() && _skeletonModel->needsFixupInScene()) {
_skeletonModel->removeFromScene(scene, transaction); _skeletonModel->removeFromScene(scene, transaction);
_skeletonModel->addToScene(scene, transaction); _skeletonModel->addToScene(scene, transaction);
_skeletonModel->setTagMask(render::hifi::TAG_ALL_VIEWS);
_skeletonModel->setGroupCulled(true);
_skeletonModel->setCanCastShadow(true);
_skeletonModel->setVisibleInScene(_isMeshVisible, scene);
processMaterials(); processMaterials();
canTryFade = true; canTryFade = true;
_isAnimatingScale = true; _isAnimatingScale = true;
@ -778,9 +824,25 @@ void Avatar::fixupModelsInScene(const render::ScenePointer& scene) {
if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) { if (attachmentModel->isRenderable() && attachmentModel->needsFixupInScene()) {
attachmentModel->removeFromScene(scene, transaction); attachmentModel->removeFromScene(scene, transaction);
attachmentModel->addToScene(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) { if (_mustFadeIn && canTryFade) {
// Do it now to be sure all the sub items are ready and the fade is sent to them too // 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); fade(transaction, render::Transition::USER_ENTER_DOMAIN);

View file

@ -74,7 +74,6 @@ public:
virtual void instantiableAvatar() = 0; virtual void instantiableAvatar() = 0;
typedef render::Payload<AvatarData> Payload; typedef render::Payload<AvatarData> Payload;
typedef std::shared_ptr<render::Item::PayloadInterface> PayloadPointer;
void init(); void init();
void updateAvatarEntities(); void updateAvatarEntities();
@ -322,6 +321,7 @@ public:
bool hasNewJointData() const { return _hasNewJointData; } bool hasNewJointData() const { return _hasNewJointData; }
float getBoundingRadius() const; 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 addToScene(AvatarSharedPointer self, const render::ScenePointer& scene);
void ensureInScene(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; 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 addMaterial(graphics::MaterialLayer material, const std::string& parentMaterialName) override;
void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override; void removeMaterial(graphics::MaterialPointer material, const std::string& parentMaterialName) override;
@ -532,6 +536,10 @@ protected:
std::mutex _materialsLock; std::mutex _materialsLock;
void processMaterials(); void processMaterials();
AABox _renderBound;
bool _isMeshVisible{ true };
bool _needMeshVisibleSwitch{ true };
}; };
#endif // hifi_Avatar_h #endif // hifi_Avatar_h

View file

@ -35,7 +35,7 @@ SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) :
_useDualQuaternionSkinning = true; _useDualQuaternionSkinning = true;
// Avatars all cast shadow // Avatars all cast shadow
_canCastShadow = true; setCanCastShadow(true);
assert(_owningAvatar); assert(_owningAvatar);
} }

View file

@ -1387,20 +1387,25 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
entity->stopModelOverrideIfNoParent(); entity->stopModelOverrideIfNoParent();
// Default behavior for model is to not be visible in main view if cauterized (aka parented to the avatar's neck joint) // 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 ? auto tagMask = _cauterized ?
render::ItemKey::TAG_BITS_1 : // draw in every view except the main one (view zero) render::hifi::TAG_SECONDARY_VIEW : // draw in every view except the main one (view zero)
render::ItemKey::TAG_BITS_ALL; // draw in all views 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 // 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 // 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. // 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? // TODO? early exit here when not visible?
if (model->canCastShadow() != _canCastShadow) { if (model->canCastShadow() != _canCastShadow) {
model->setCanCastShadow(_canCastShadow, scene, viewTaskBits, false); model->setCanCastShadow(_canCastShadow, scene);
} }
if (_needsCollisionGeometryUpdate) { if (_needsCollisionGeometryUpdate) {

View file

@ -1688,15 +1688,21 @@ QVector<QUuid> EntityScriptingInterface::getChildrenIDs(const QUuid& parentID) {
if (!_entityTree) { if (!_entityTree) {
return result; return result;
} }
EntityItemPointer entity = _entityTree->findEntityByEntityItemID(parentID);
if (!entity) {
qCDebug(entities) << "EntityScriptingInterface::getChildrenIDs - no entity with ID" << parentID;
return result;
}
_entityTree->withReadLock([&] { _entityTree->withReadLock([&] {
entity->forEachChild([&](SpatiallyNestablePointer child) { QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
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()); result.push_back(child->getID());
}); });
}); });

View file

@ -1226,12 +1226,11 @@ public slots:
/**jsdoc /**jsdoc
* Get the IDs of entities, overlays, and avatars that are directly parented to an entity. To get all descendants of an * 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.
* entity, recurse on the IDs returned by the function.
* @function Entities.getChildrenIDs * @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 <code>parentID</code> * @returns {Uuid[]} An array of entity, overlay, and avatar IDs that are parented directly to the <code>parentID</code>
* 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
* <code>parentID</code> cannot be found. * <code>parentID</code> cannot be found.
* @example <caption>Report the children of an entity.</caption> * @example <caption>Report the children of an entity.</caption>
* function createEntity(description, position, parent) { * function createEntity(description, position, parent) {

View file

@ -22,6 +22,7 @@
#include <QtCore/QStringList> #include <QtCore/QStringList>
#include <QtCore/QStandardPaths> #include <QtCore/QStandardPaths>
#include <QtCore/QUrlQuery> #include <QtCore/QUrlQuery>
#include <QtCore/QThreadPool>
#include <QtNetwork/QHttpMultiPart> #include <QtNetwork/QHttpMultiPart>
#include <QtNetwork/QNetworkRequest> #include <QtNetwork/QNetworkRequest>
#include <qthread.h> #include <qthread.h>
@ -743,6 +744,9 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
return; return;
} }
// Ensure openssl/Qt config is set up.
QSslConfiguration::defaultConfiguration();
// make sure we don't already have an outbound keypair generation request // make sure we don't already have an outbound keypair generation request
if (!_isWaitingForKeypairResponse) { if (!_isWaitingForKeypairResponse) {
_isWaitingForKeypairResponse = true; _isWaitingForKeypairResponse = true;
@ -751,94 +755,75 @@ void AccountManager::generateNewKeypair(bool isUserKeypair, const QUuid& domainI
qCDebug(networking) << "Clearing current private key in DataServerAccountInfo"; qCDebug(networking) << "Clearing current private key in DataServerAccountInfo";
_accountInfo.setPrivateKey(QByteArray()); _accountInfo.setPrivateKey(QByteArray());
// setup a new QThread to generate the keypair on, in case it takes a while // Create a runnable keypair generated to create an RSA pair and exit.
QThread* generateThread = new QThread(this);
generateThread->setObjectName("Account Manager Generator Thread");
// setup a keypair generator
RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator; RSAKeypairGenerator* keypairGenerator = new RSAKeypairGenerator;
if (!isUserKeypair) { if (!isUserKeypair) {
keypairGenerator->setDomainID(domainID);
_accountInfo.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 // handle success or failure of keypair generation
connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this, &AccountManager::processGeneratedKeypair); connect(keypairGenerator, &RSAKeypairGenerator::generatedKeypair, this,
connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, &AccountManager::processGeneratedKeypair);
this, &AccountManager::handleKeypairGenerationError); connect(keypairGenerator, &RSAKeypairGenerator::errorGeneratingKeypair, this,
&AccountManager::handleKeypairGenerationError);
connect(keypairGenerator, &QObject::destroyed, generateThread, &QThread::quit);
connect(generateThread, &QThread::finished, generateThread, &QThread::deleteLater);
keypairGenerator->moveToThread(generateThread);
qCDebug(networking) << "Starting worker thread to generate 2048-bit RSA keypair."; 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."; qCDebug(networking) << "Generated 2048-bit RSA keypair. Uploading public key now.";
RSAKeypairGenerator* keypairGenerator = qobject_cast<RSAKeypairGenerator*>(sender()); // hold the private key to later set our metaverse API account info if upload succeeds
_pendingPrivateKey = privateKey;
if (keypairGenerator) { // upload the public key so data-web has an up-to-date key
// hold the private key to later set our metaverse API account info if upload succeeds const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key";
_pendingPrivateKey = keypairGenerator->getPrivateKey(); 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 QString uploadPath;
const QString USER_PUBLIC_KEY_UPDATE_PATH = "api/v1/user/public_key"; const auto& domainID = _accountInfo.getDomainID();
const QString DOMAIN_PUBLIC_KEY_UPDATE_PATH = "api/v1/domains/%1/public_key"; if (domainID.isNull()) {
uploadPath = USER_PUBLIC_KEY_UPDATE_PATH;
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();
} else { } else {
qCWarning(networking) << "Expected processGeneratedKeypair to be called by a live RSAKeypairGenerator" uploadPath = DOMAIN_PUBLIC_KEY_UPDATE_PATH.arg(uuidStringWithoutCurlyBraces(domainID));
<< "but the casted sender is NULL. Will not process generated keypair.";
} }
// 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) { void AccountManager::publicKeyUploadSucceeded(QNetworkReply& reply) {
@ -877,6 +862,4 @@ void AccountManager::handleKeypairGenerationError() {
// reset our waiting state for keypair response // reset our waiting state for keypair response
_isWaitingForKeypairResponse = false; _isWaitingForKeypairResponse = false;
sender()->deleteLater();
} }

View file

@ -128,7 +128,7 @@ signals:
private slots: private slots:
void processReply(); void processReply();
void handleKeypairGenerationError(); void handleKeypairGenerationError();
void processGeneratedKeypair(); void processGeneratedKeypair(QByteArray publicKey, QByteArray privateKey);
void publicKeyUploadSucceeded(QNetworkReply& reply); void publicKeyUploadSucceeded(QNetworkReply& reply);
void publicKeyUploadFailed(QNetworkReply& reply); void publicKeyUploadFailed(QNetworkReply& reply);
void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid()); void generateNewKeypair(bool isUserKeypair = true, const QUuid& domainID = QUuid());

View file

@ -25,7 +25,10 @@
RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) : RSAKeypairGenerator::RSAKeypairGenerator(QObject* parent) :
QObject(parent) QObject(parent)
{ {
}
void RSAKeypairGenerator::run() {
generateKeypair();
} }
void RSAKeypairGenerator::generateKeypair() { void RSAKeypairGenerator::generateKeypair() {
@ -92,5 +95,5 @@ void RSAKeypairGenerator::generateKeypair() {
OPENSSL_free(publicKeyDER); OPENSSL_free(publicKeyDER);
OPENSSL_free(privateKeyDER); OPENSSL_free(privateKeyDER);
emit generatedKeypair(); emit generatedKeypair(_publicKey, _privateKey);
} }

View file

@ -13,25 +13,20 @@
#define hifi_RSAKeypairGenerator_h #define hifi_RSAKeypairGenerator_h
#include <QtCore/QObject> #include <QtCore/QObject>
#include <QtCore/QRunnable>
#include <QtCore/QUuid> #include <QtCore/QUuid>
class RSAKeypairGenerator : public QObject { class RSAKeypairGenerator : public QObject, public QRunnable {
Q_OBJECT Q_OBJECT
public: public:
RSAKeypairGenerator(QObject* parent = 0); RSAKeypairGenerator(QObject* parent = nullptr);
void setDomainID(const QUuid& domainID) { _domainID = domainID; } virtual void run() override;
const QUuid& getDomainID() const { return _domainID; }
const QByteArray& getPublicKey() const { return _publicKey; }
const QByteArray& getPrivateKey() const { return _privateKey; }
public slots:
void generateKeypair(); void generateKeypair();
signals: signals:
void errorGeneratingKeypair(); void errorGeneratingKeypair();
void generatedKeypair(); void generatedKeypair(QByteArray publicKey, QByteArray privateKey);
private: private:
QUuid _domainID; QUuid _domainID;

View file

@ -159,6 +159,13 @@ void ObjectDynamic::removeFromSimulation(EntitySimulationPointer simulation) con
simulation->removeDynamic(myID); simulation->removeDynamic(myID);
} }
void ObjectDynamic::setOwnerEntity(const EntityItemPointer ownerEntity) {
if (!ownerEntity) {
activateBody();
}
_ownerEntity = ownerEntity;
}
EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const { EntityItemPointer ObjectDynamic::getEntityByID(EntityItemID entityID) const {
EntityItemPointer ownerEntity; EntityItemPointer ownerEntity;
withReadLock([&]{ withReadLock([&]{

View file

@ -33,7 +33,7 @@ public:
virtual void removeFromSimulation(EntitySimulationPointer simulation) const override; virtual void removeFromSimulation(EntitySimulationPointer simulation) const override;
virtual EntityItemWeakPointer getOwnerEntity() const override { return _ownerEntity; } 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() {}; virtual void invalidate() {};

View file

@ -215,10 +215,7 @@ void CauterizedModel::updateRenderItems() {
modelTransform.setRotation(self->getRotation()); modelTransform.setRotation(self->getRotation());
bool isWireframe = self->isWireframe(); bool isWireframe = self->isWireframe();
bool isVisible = self->isVisible(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool canCastShadow = self->canCastShadow();
bool isLayeredInFront = self->isLayeredInFront();
bool isLayeredInHUD = self->isLayeredInHUD();
bool enableCauterization = self->getEnableCauterization(); bool enableCauterization = self->getEnableCauterization();
render::Transaction transaction; render::Transaction transaction;
@ -234,7 +231,7 @@ void CauterizedModel::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey, transaction.updateItem<CauterizedMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, cauterizedMeshState, invalidatePayloadShapeKey,
isWireframe, isVisible, isLayeredInFront, isLayeredInHUD, canCastShadow, enableCauterization](CauterizedMeshPartPayload& data) { isWireframe, renderItemKeyGlobalFlags, enableCauterization](CauterizedMeshPartPayload& data) {
if (useDualQuaternionSkinning) { if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions, data.updateClusterBuffer(meshState.clusterDualQuaternions,
cauterizedMeshState.clusterDualQuaternions); cauterizedMeshState.clusterDualQuaternions);
@ -276,8 +273,7 @@ void CauterizedModel::updateRenderItems() {
data.updateTransformForCauterizedMesh(renderTransform); data.updateTransformForCauterizedMesh(renderTransform);
data.setEnableCauterization(enableCauterization); data.setEnableCauterization(enableCauterization);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, render::ItemKey::TAG_BITS_ALL); data.updateKey(renderItemKeyGlobalFlags);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
}); });
} }

View file

@ -79,28 +79,10 @@ void MeshPartPayload::removeMaterial(graphics::MaterialPointer material) {
_drawMaterials.remove(material); _drawMaterials.remove(material);
} }
void MeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCastShadow, uint8_t tagBits, bool isGroupCulled) { void MeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder; ItemKey::Builder builder(key);
builder.withTypeShape(); builder.withTypeShape();
if (!isVisible) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
if (canCastShadow) {
builder.withShadowCaster();
}
if (isGroupCulled) {
builder.withSubMetaCulled();
}
if (topMaterialExists()) { if (topMaterialExists()) {
auto matKey = _drawMaterials.top().material->getKey(); auto matKey = _drawMaterials.top().material->getKey();
if (matKey.isTranslucent()) { if (matKey.isTranslucent()) {
@ -200,12 +182,6 @@ template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointe
} }
return Item::Bound(); 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) { template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
if (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 // 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) { void ModelMeshPartPayload::updateKey(const render::ItemKey& key) {
ItemKey::Builder builder; ItemKey::Builder builder(key);
builder.withTypeShape(); builder.withTypeShape();
if (!isVisible) {
builder.withInvisible();
}
builder.withTagBits(tagBits);
if (isLayered) {
builder.withLayered();
}
if (canCastShadow) {
builder.withShadowCaster();
}
if (isGroupCulled) {
builder.withSubMetaCulled();
}
if (_isBlendShaped || _isSkinned) { if (_isBlendShaped || _isSkinned) {
builder.withDeformed(); builder.withDeformed();
} }
@ -368,20 +326,6 @@ void ModelMeshPartPayload::updateKey(bool isVisible, bool isLayered, bool canCas
_itemKey = builder.build(); _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) { void ModelMeshPartPayload::setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning) {
if (invalidateShapeKey) { if (invalidateShapeKey) {
_shapeKey = ShapeKey::Builder::invalid(); _shapeKey = ShapeKey::Builder::invalid();

View file

@ -32,7 +32,7 @@ public:
typedef render::Payload<MeshPartPayload> Payload; typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer; 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<const graphics::Mesh>& drawMesh, int partIndex); virtual void updateMeshPart(const std::shared_ptr<const graphics::Mesh>& drawMesh, int partIndex);
@ -95,7 +95,7 @@ public:
void notifyLocationChanged() override; 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 // matrix palette skinning
void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices); void updateClusterBuffer(const std::vector<glm::mat4>& clusterMatrices);
@ -105,11 +105,9 @@ public:
void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform); void updateTransformForSkinnedMesh(const Transform& renderTransform, const Transform& boundTransform);
// Render Item interface // Render Item interface
int getLayer() const;
render::ShapeKey getShapeKey() const override; // shape interface render::ShapeKey getShapeKey() const override; // shape interface
void render(RenderArgs* args) override; void render(RenderArgs* args) override;
void setLayer(bool isLayeredInFront, bool isLayeredInHUD);
void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning); void setShapeKey(bool invalidateShapeKey, bool isWireframe, bool useDualQuaternionSkinning);
// ModelMeshPartPayload functions to perform render // ModelMeshPartPayload functions to perform render
@ -139,13 +137,11 @@ private:
gpu::BufferPointer _blendedVertexBuffer; gpu::BufferPointer _blendedVertexBuffer;
render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() }; render::ShapeKey _shapeKey { render::ShapeKey::Builder::invalid() };
int _layer { render::Item::LAYER_3D };
}; };
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload); template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(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 <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args); template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
} }

View file

@ -103,11 +103,10 @@ Model::Model(QObject* parent, SpatiallyNestable* spatiallyNestableOverride) :
_snapModelToRegistrationPoint(false), _snapModelToRegistrationPoint(false),
_snappedToRegistrationPoint(false), _snappedToRegistrationPoint(false),
_url(HTTP_INVALID_COM), _url(HTTP_INVALID_COM),
_isVisible(true),
_canCastShadow(false),
_blendNumber(0), _blendNumber(0),
_appliedBlendNumber(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 // we may have been created in the network thread, but we live in the main thread
if (_viewState) { if (_viewState) {
@ -268,12 +267,7 @@ void Model::updateRenderItems() {
modelTransform.setScale(glm::vec3(1.0f)); modelTransform.setScale(glm::vec3(1.0f));
bool isWireframe = self->isWireframe(); bool isWireframe = self->isWireframe();
bool isVisible = self->isVisible(); auto renderItemKeyGlobalFlags = self->getRenderItemKeyGlobalFlags();
bool canCastShadow = self->canCastShadow();
uint8_t viewTagBits = self->getViewTagBits();
bool isLayeredInFront = self->isLayeredInFront();
bool isLayeredInHUD = self->isLayeredInHUD();
bool isGroupCulled = self->isGroupCulled();
render::Transaction transaction; render::Transaction transaction;
for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) { for (int i = 0; i < (int) self->_modelMeshRenderItemIDs.size(); i++) {
@ -287,9 +281,7 @@ void Model::updateRenderItems() {
bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning(); bool useDualQuaternionSkinning = self->getUseDualQuaternionSkinning();
transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning, transaction.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, meshState, useDualQuaternionSkinning,
invalidatePayloadShapeKey, isWireframe, isVisible, invalidatePayloadShapeKey, isWireframe, renderItemKeyGlobalFlags](ModelMeshPartPayload& data) {
canCastShadow, viewTagBits, isLayeredInFront,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
if (useDualQuaternionSkinning) { if (useDualQuaternionSkinning) {
data.updateClusterBuffer(meshState.clusterDualQuaternions); data.updateClusterBuffer(meshState.clusterDualQuaternions);
} else { } else {
@ -313,8 +305,7 @@ void Model::updateRenderItems() {
} }
data.updateTransformForSkinnedMesh(renderTransform, modelTransform); data.updateTransformForSkinnedMesh(renderTransform, modelTransform);
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled); data.updateKey(renderItemKeyGlobalFlags);
data.setLayer(isLayeredInFront, isLayeredInHUD);
data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning); data.setShapeKey(invalidatePayloadShapeKey, isWireframe, useDualQuaternionSkinning);
}); });
} }
@ -322,8 +313,9 @@ void Model::updateRenderItems() {
Transform collisionMeshOffset; Transform collisionMeshOffset;
collisionMeshOffset.setIdentity(); collisionMeshOffset.setIdentity();
foreach(auto itemID, self->_collisionRenderItemsMap.keys()) { foreach(auto itemID, self->_collisionRenderItemsMap.keys()) {
transaction.updateItem<MeshPartPayload>(itemID, [modelTransform, collisionMeshOffset](MeshPartPayload& data) { transaction.updateItem<MeshPartPayload>(itemID, [renderItemKeyGlobalFlags, modelTransform, collisionMeshOffset](MeshPartPayload& data) {
// update the model transform for this render item. // update the model transform for this render item.
data.updateKey(renderItemKeyGlobalFlags);
data.updateTransform(modelTransform, collisionMeshOffset); 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) { void Model::updateRenderItemsKey(const render::ScenePointer& scene) {
if (_isVisible != isVisible || _viewTagBits != viewTagBits || _isGroupCulled != isGroupCulled) { if (!scene) {
_isVisible = isVisible; _needsFixupInScene = true;
_viewTagBits = viewTagBits; return;
_isGroupCulled = isGroupCulled; }
auto renderItemsKey = _renderItemKeyGlobalFlags;
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
data.updateKey(renderItemsKey);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [renderItemsKey](ModelMeshPartPayload& data) {
data.updateKey(renderItemsKey);
});
}
scene->enqueueTransaction(transaction);
}
bool isLayeredInFront = _isLayeredInFront; void Model::setVisibleInScene(bool visible, const render::ScenePointer& scene) {
bool isLayeredInHUD = _isLayeredInHUD; if (Model::isVisible() != visible) {
bool canCastShadow = _canCastShadow; auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
render::Transaction transaction; _renderItemKeyGlobalFlags = (visible ? keyBuilder.withVisible() : keyBuilder.withInvisible());
foreach (auto item, _modelMeshRenderItemsMap.keys()) { updateRenderItemsKey(scene);
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
});
}
foreach(auto item, _collisionRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
});
}
scene->enqueueTransaction(transaction);
} }
} }
void Model::setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled) { bool Model::isVisible() const {
if (_canCastShadow != canCastShadow) { return _renderItemKeyGlobalFlags.isVisible();
_canCastShadow = canCastShadow; }
bool isVisible = _isVisible; void Model::setCanCastShadow(bool castShadow, const render::ScenePointer& scene) {
bool isLayeredInFront = _isLayeredInFront; if (Model::canCastShadow() != castShadow) {
bool isLayeredInHUD = _isLayeredInHUD; auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
_renderItemKeyGlobalFlags = (castShadow ? keyBuilder.withShadowCaster() : keyBuilder.withoutShadowCaster());
render::Transaction transaction; updateRenderItemsKey(scene);
foreach (auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(item,
[isVisible, viewTagBits, canCastShadow, isLayeredInFront, isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, viewTagBits, canCastShadow, isLayeredInFront || isLayeredInHUD, isGroupCulled);
});
}
scene->enqueueTransaction(transaction);
} }
} }
void Model::setLayeredInFront(bool isLayeredInFront, const render::ScenePointer& scene) { bool Model::canCastShadow() const {
if (_isLayeredInFront != isLayeredInFront) { return _renderItemKeyGlobalFlags.isShadowCaster();
_isLayeredInFront = isLayeredInFront; }
bool isVisible = _isVisible; void Model::setLayeredInFront(bool layeredInFront, const render::ScenePointer& scene) {
bool canCastShadow = _canCastShadow; if (Model::isLayeredInFront() != layeredInFront) {
uint8_t viewTagBits = _viewTagBits; auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
bool isLayeredInHUD = _isLayeredInHUD; _renderItemKeyGlobalFlags = (layeredInFront ? keyBuilder.withLayer(render::hifi::LAYER_3D_FRONT) : keyBuilder.withoutLayer());
bool isGroupCulled = _isGroupCulled; updateRenderItemsKey(scene);
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(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<ModelMeshPartPayload>(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 isLayeredInHUD, const render::ScenePointer& scene) { bool Model::isLayeredInFront() const {
if (_isLayeredInHUD != isLayeredInHUD) { return _renderItemKeyGlobalFlags.isLayer(render::hifi::LAYER_3D_FRONT);
_isLayeredInHUD = isLayeredInHUD; }
bool isVisible = _isVisible; void Model::setLayeredInHUD(bool layeredInHUD, const render::ScenePointer& scene) {
bool canCastShadow = _canCastShadow; if (Model::isLayeredInHUD() != layeredInHUD) {
uint8_t viewTagBits = _viewTagBits; auto keyBuilder = render::ItemKey::Builder(_renderItemKeyGlobalFlags);
bool isLayeredInFront = _isLayeredInFront; _renderItemKeyGlobalFlags = (layeredInHUD ? keyBuilder.withLayer(render::hifi::LAYER_3D_HUD) : keyBuilder.withoutLayer());
bool isGroupCulled = _isGroupCulled; updateRenderItemsKey(scene);
render::Transaction transaction;
foreach(auto item, _modelMeshRenderItemsMap.keys()) {
transaction.updateItem<ModelMeshPartPayload>(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<ModelMeshPartPayload>(item, [isVisible, viewTagBits, isLayeredInFront, canCastShadow,
isLayeredInHUD, isGroupCulled](ModelMeshPartPayload& data) {
data.updateKey(isVisible, isLayeredInFront || isLayeredInHUD, canCastShadow, viewTagBits, isGroupCulled);
data.setLayer(isLayeredInFront, isLayeredInHUD);
});
}
scene->enqueueTransaction(transaction);
} }
} }
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, bool Model::addToScene(const render::ScenePointer& scene,
render::Transaction& transaction, render::Transaction& transaction,
render::Item::Status::Getters& statusGetters) { render::Item::Status::Getters& statusGetters) {
@ -1676,20 +1658,16 @@ void Model::addMaterial(graphics::MaterialLayer material, const std::string& par
for (auto shapeID : shapeIDs) { for (auto shapeID : shapeIDs) {
if (shapeID < _modelMeshRenderItemIDs.size()) { if (shapeID < _modelMeshRenderItemIDs.size()) {
auto itemID = _modelMeshRenderItemIDs[shapeID]; auto itemID = _modelMeshRenderItemIDs[shapeID];
bool visible = isVisible(); auto renderItemsKey = _renderItemKeyGlobalFlags;
uint8_t viewTagBits = getViewTagBits();
bool layeredInFront = isLayeredInFront();
bool layeredInHUD = isLayeredInHUD();
bool canCastShadow = _canCastShadow;
bool wireframe = isWireframe(); bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning; bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, transaction.updateItem<ModelMeshPartPayload>(itemID, [material, renderItemsKey,
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.addMaterial(material); data.addMaterial(material);
// if the material changed, we might need to update our item key or shape key // 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); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
}); });
} }
@ -1704,19 +1682,16 @@ void Model::removeMaterial(graphics::MaterialPointer material, const std::string
if (shapeID < _modelMeshRenderItemIDs.size()) { if (shapeID < _modelMeshRenderItemIDs.size()) {
auto itemID = _modelMeshRenderItemIDs[shapeID]; auto itemID = _modelMeshRenderItemIDs[shapeID];
bool visible = isVisible(); bool visible = isVisible();
uint8_t viewTagBits = getViewTagBits(); auto renderItemsKey = _renderItemKeyGlobalFlags;
bool layeredInFront = isLayeredInFront();
bool layeredInHUD = isLayeredInHUD();
bool canCastShadow = _canCastShadow;
bool wireframe = isWireframe(); bool wireframe = isWireframe();
auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex; auto meshIndex = _modelMeshRenderItemShapes[shapeID].meshIndex;
bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex); bool invalidatePayloadShapeKey = shouldInvalidatePayloadShapeKey(meshIndex);
bool useDualQuaternionSkinning = _useDualQuaternionSkinning; bool useDualQuaternionSkinning = _useDualQuaternionSkinning;
transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, layeredInFront, layeredInHUD, viewTagBits, canCastShadow, transaction.updateItem<ModelMeshPartPayload>(itemID, [material, visible, renderItemsKey,
invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) { invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning](ModelMeshPartPayload& data) {
data.removeMaterial(material); data.removeMaterial(material);
// if the material changed, we might need to update our item key or shape key // 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); data.setShapeKey(invalidatePayloadShapeKey, wireframe, useDualQuaternionSkinning);
}); });
} }

View file

@ -33,6 +33,7 @@
#include <TriangleSet.h> #include <TriangleSet.h>
#include <DualQuaternion.h> #include <DualQuaternion.h>
#include "RenderHifi.h"
#include "GeometryCache.h" #include "GeometryCache.h"
#include "TextureCache.h" #include "TextureCache.h"
#include "Rig.h" #include "Rig.h"
@ -87,13 +88,27 @@ public:
const QUrl& getURL() const { return _url; } const QUrl& getURL() const { return _url; }
// new Scene/Engine rendering support // 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; } render::hifi::Tag getTagMask() const;
void setCanCastShadow(bool canCastShadow, const render::ScenePointer& scene, uint8_t viewTagBits, bool isGroupCulled); 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 needsFixupInScene() const;
bool needsReload() const { return _needsReload; } bool needsReload() const { return _needsReload; }
@ -108,13 +123,7 @@ public:
void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction); void removeFromScene(const render::ScenePointer& scene, render::Transaction& transaction);
bool isRenderable() const; bool isRenderable() const;
bool isVisible() const { return _isVisible; } void updateRenderItemsKey(const render::ScenePointer& scene);
uint8_t getViewTagBits() const { return _viewTagBits; }
bool isLayeredInFront() const { return _isLayeredInFront; }
bool isLayeredInHUD() const { return _isLayeredInHUD; }
bool isGroupCulled() const { return _isGroupCulled; }
virtual void updateRenderItems(); virtual void updateRenderItems();
void setRenderItemsNeedUpdate(); void setRenderItemsNeedUpdate();
@ -404,10 +413,6 @@ protected:
QVector<float> _blendshapeCoefficients; QVector<float> _blendshapeCoefficients;
QUrl _url; QUrl _url;
bool _isVisible;
uint8_t _viewTagBits{ render::ItemKey::TAG_BITS_ALL };
bool _canCastShadow;
gpu::Buffers _blendedVertexBuffers; gpu::Buffers _blendedVertexBuffers;
@ -471,10 +476,16 @@ protected:
int _renderInfoDrawCalls { 0 }; int _renderInfoDrawCalls { 0 };
int _renderInfoHasTransparent { false }; int _renderInfoHasTransparent { false };
bool _isLayeredInFront { 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.
bool _isLayeredInHUD { false }; // 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).
bool _isGroupCulled{ false }; // - 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); bool shouldInvalidatePayloadShapeKey(int meshIndex);

View file

@ -27,6 +27,7 @@
#include <render/DrawSceneOctree.h> #include <render/DrawSceneOctree.h>
#include <render/BlurTask.h> #include <render/BlurTask.h>
#include "RenderHifi.h"
#include "RenderCommonTask.h" #include "RenderCommonTask.h"
#include "LightingModel.h" #include "LightingModel.h"
#include "StencilMaskPass.h" #include "StencilMaskPass.h"
@ -200,8 +201,8 @@ void RenderDeferredTask::build(JobModel& task, const render::Varying& input, ren
const auto overlaysInFrontRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOverlaysInFrontRangeTimer", "BeginOverlaysInFrontRangeTimer"); const auto overlaysInFrontRangeTimer = task.addJob<BeginGPURangeTimer>("BeginOverlaysInFrontRangeTimer", "BeginOverlaysInFrontRangeTimer");
// Layered Overlays // Layered Overlays
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT); const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT); const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0); const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0); const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);

View file

@ -23,6 +23,7 @@
#include <render/FilterTask.h> #include <render/FilterTask.h>
#include "RenderHifi.h"
#include "StencilMaskPass.h" #include "StencilMaskPass.h"
#include "ZoneRenderer.h" #include "ZoneRenderer.h"
#include "FadeEffect.h" #include "FadeEffect.h"
@ -79,8 +80,8 @@ void RenderForwardTask::build(JobModel& task, const render::Varying& input, rend
task.addJob<PrepareStencil>("PrepareStencil", framebuffer); task.addJob<PrepareStencil>("PrepareStencil", framebuffer);
// Layered Overlays // Layered Overlays
const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, Item::LAYER_3D_FRONT); const auto filteredOverlaysOpaque = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredOpaque", overlayOpaques, render::hifi::LAYER_3D_FRONT);
const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, Item::LAYER_3D_FRONT); const auto filteredOverlaysTransparent = task.addJob<FilterLayeredItems>("FilterOverlaysLayeredTransparent", overlayTransparents, render::hifi::LAYER_3D_FRONT);
const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0); const auto overlaysInFrontOpaque = filteredOverlaysOpaque.getN<FilterLayeredItems::Outputs>(0);
const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0); const auto overlaysInFrontTransparent = filteredOverlaysTransparent.getN<FilterLayeredItems::Outputs>(0);

View file

@ -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 <render/Item.h>
// 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

View file

@ -368,9 +368,9 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
RenderArgs* args = renderContext->args; RenderArgs* args = renderContext->args;
const auto& inShapes = inputs.get0(); const auto& inShapes = inputs.get0();
const auto& cullFilter = inputs.get1(); const auto& cullFilter = inputs.get1();
const auto& boundsFilter = inputs.get2(); const auto& boundsFilter = inputs.get2();
const auto& antiFrustum = inputs.get3(); const auto& antiFrustum = inputs.get3();
auto& outShapes = outputs.edit0(); auto& outShapes = outputs.edit0();
auto& outBounds = outputs.edit1(); auto& outBounds = outputs.edit1();
@ -380,7 +380,7 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) { if (!cullFilter.selectsNothing() || !boundsFilter.selectsNothing()) {
auto& details = args->_details.edit(_detailType); auto& details = args->_details.edit(_detailType);
Test test(_cullFunctor, args, details, antiFrustum); Test test(_cullFunctor, args, details, antiFrustum);
auto scene = args->_scene; auto scene = args->_scene;
for (auto& inItems : inShapes) { for (auto& inItems : inShapes) {
auto key = inItems.first; auto key = inItems.first;
@ -395,26 +395,26 @@ void CullShapeBounds::run(const RenderContextPointer& renderContext, const Input
if (antiFrustum == nullptr) { if (antiFrustum == nullptr) {
for (auto& item : inItems.second) { for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound)) {
const auto shapeKey = scene->getItem(item.id).getKey(); const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) { if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item); outItems->second.emplace_back(item);
} }
if (boundsFilter.test(shapeKey)) { if (boundsFilter.test(shapeKey)) {
outBounds += item.bound; outBounds += item.bound;
} }
} }
} }
} else { } else {
for (auto& item : inItems.second) { for (auto& item : inItems.second) {
if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) { if (test.solidAngleTest(item.bound) && test.frustumTest(item.bound) && test.antiFrustumTest(item.bound)) {
const auto shapeKey = scene->getItem(item.id).getKey(); const auto shapeKey = scene->getItem(item.id).getKey();
if (cullFilter.test(shapeKey)) { if (cullFilter.test(shapeKey)) {
outItems->second.emplace_back(item); outItems->second.emplace_back(item);
} }
if (boundsFilter.test(shapeKey)) { if (boundsFilter.test(shapeKey)) {
outBounds += item.bound; outBounds += item.bound;
} }
} }
} }
} }
details._rendered += (int)outItems->second.size(); details._rendered += (int)outItems->second.size();
@ -487,6 +487,7 @@ void FetchSpatialSelection::run(const RenderContextPointer& renderContext,
if (filter.test(item.getKey())) { if (filter.test(item.getKey())) {
ItemBound itemBound(id, item.getBound()); ItemBound itemBound(id, item.getBound());
outItems.emplace_back(itemBound); outItems.emplace_back(itemBound);
} }
} }
} }

View file

@ -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::BLUE = 240.0f;
const float Item::Status::Value::MAGENTA = 300.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_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) { void Item::Status::Value::setScale(float scale) {
_scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f)); _scale = (std::numeric_limits<unsigned short>::max() -1) * 0.5f * (1.0f + std::max(std::min(scale, 1.0f), 0.0f));

View file

@ -52,23 +52,45 @@ public:
TAG_6, TAG_6,
TAG_7, 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 { enum FlagBit : uint32_t {
TYPE_SHAPE = 0, // Item is a Shape 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 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 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... TRANSLUCENT, // Transparent and not opaque, for some odd reason TRANSPARENCY doesn't work...
@ -77,13 +99,15 @@ public:
DEFORMED, // Deformed within bound, not solid DEFORMED, // Deformed within bound, not solid
INVISIBLE, // Visible or not in the scene? INVISIBLE, // Visible or not in the scene?
SHADOW_CASTER, // Item cast shadows 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 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 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 FIRST_TAG_BIT, // 8 Tags available to organize the items and filter them against
LAST_TAG_BIT = FIRST_TAG_BIT + NUM_TAGS, 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) __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 NUM_FLAGS, // Not a valid flag
@ -96,6 +120,12 @@ public:
return (keyBits & ~KEY_TAG_BITS_MASK) | (((uint32_t)tagBits) << FIRST_TAG_BIT); 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 // The key is the Flags
Flags _flags; Flags _flags;
@ -124,19 +154,24 @@ public:
Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); } Builder& withInvisible() { _flags.set(INVISIBLE); return (*this); }
Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); } Builder& withVisible() { _flags.reset(INVISIBLE); return (*this); }
Builder& withShadowCaster() { _flags.set(SHADOW_CASTER); 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& 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& 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); } Builder& withTag(Tag tag) { _flags.set(FIRST_TAG_BIT + tag); return (*this); }
// Set ALL the tags in one call using the Tag bits // 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& 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 // Convenient standard keys that we will keep on using all over the place
static Builder opaqueShape() { return Builder().withTypeShape(); } static Builder opaqueShape() { return Builder().withTypeShape(); }
static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); } static Builder transparentShape() { return Builder().withTypeShape().withTransparent(); }
static Builder light() { return Builder().withTypeLight(); } 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) {} ItemKey(const Builder& builder) : ItemKey(builder._flags) {}
@ -161,9 +196,6 @@ public:
bool isShadowCaster() const { return _flags[SHADOW_CASTER]; } 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]; } bool isMetaCullGroup() const { return _flags[META_CULL_GROUP]; }
void setMetaCullGroup(bool cullGroup) { (cullGroup ? _flags.set(META_CULL_GROUP) : _flags.reset(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]; } 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 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 // Probably not public, flags used by the scene
bool isSmall() const { return _flags[__SMALLER]; } bool isSmall() const { return _flags[__SMALLER]; }
void setSmaller(bool smaller) { (smaller ? _flags.set(__SMALLER) : _flags.reset(__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& 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& 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& 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); } 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 // 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& 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); } Builder& withNothing() { _value.reset(); _mask.reset(); return (*this); }
// Convenient standard keys that we will keep on using all over the place // 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 transparentShape() { return Builder().withTypeShape().withTransparent().withWorldSpace(); }
static Builder light() { return Builder().withTypeLight(); } static Builder light() { return Builder().withTypeLight(); }
static Builder meta() { return Builder().withTypeMeta(); } static Builder meta() { return Builder().withTypeMeta(); }
static Builder background() { return Builder().withViewSpace().withLayered(); } static Builder background() { return Builder().withViewSpace().withLayer(ItemKey::LAYER_BACKGROUND); }
static Builder opaqueShapeLayered() { return Builder().withTypeShape().withOpaque().withWorldSpace().withLayered(); }
static Builder transparentShapeLayered() { return Builder().withTypeShape().withTransparent().withWorldSpace().withLayered(); }
static Builder nothing() { return Builder().withNothing(); } static Builder nothing() { return Builder().withNothing(); }
}; };
@ -377,7 +412,6 @@ public:
public: public:
virtual const ItemKey getKey() const = 0; virtual const ItemKey getKey() const = 0;
virtual const Bound getBound() const = 0; virtual const Bound getBound() const = 0;
virtual int getLayer() const = 0;
virtual void render(RenderArgs* args) = 0; virtual void render(RenderArgs* args) = 0;
virtual const ShapeKey getShapeKey() const = 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()) // 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(); } const Bound getBound() const { return _payload->getBound(); }
// Get the layer where the item belongs. // Get the layer where the item belongs, simply reflecting the key.
int getLayer() const { return _payload->getLayer(); } int getLayer() const { return _key.getLayer(); }
static const int LAYER_2D;
static const int LAYER_3D;
static const int LAYER_3D_FRONT;
static const int LAYER_3D_HUD;
// Render call for the item // Render call for the item
void render(RenderArgs* args) const { _payload->render(args); } 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 // Item shared interface supported by the payload
template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); } template <class T> const ItemKey payloadGetKey(const std::shared_ptr<T>& payloadData) { return ItemKey(); }
template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); } template <class T> const Item::Bound payloadGetBound(const std::shared_ptr<T>& payloadData) { return Item::Bound(); }
template <class T> int payloadGetLayer(const std::shared_ptr<T>& payloadData) { return 0; }
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { } template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
// Shape type interface // Shape type interface
@ -505,7 +533,6 @@ public:
// Payload general interface // Payload general interface
virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); } virtual const ItemKey getKey() const override { return payloadGetKey<T>(_data); }
virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); } virtual const Item::Bound getBound() const override { return payloadGetBound<T>(_data); }
virtual int getLayer() const override { return payloadGetLayer<T>(_data); }
virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); } virtual void render(RenderArgs* args) override { payloadRender<T>(_data, args); }

View file

@ -48,6 +48,6 @@ bool blockingInvokeMethod(
} } } }
#define BLOCKING_INVOKE_METHOD(obj, member, ...) \ #define BLOCKING_INVOKE_METHOD(obj, member, ...) \
hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__) ::hifi::qt::blockingInvokeMethod(__FUNCTION__, obj, member, ##__VA_ARGS__)
#endif #endif

View file

@ -23,6 +23,7 @@ var DEFAULT_SCRIPTS_COMBINED = [
"system/makeUserConnection.js", "system/makeUserConnection.js",
"system/tablet-goto.js", "system/tablet-goto.js",
"system/marketplaces/marketplaces.js", "system/marketplaces/marketplaces.js",
"system/notifications.js",
"system/commerce/wallet.js", "system/commerce/wallet.js",
"system/edit.js", "system/edit.js",
"system/dialTone.js", "system/dialTone.js",

View file

@ -79,11 +79,7 @@
var frame = 0; var frame = 0;
var ctrlIsPressed = false; var ctrlIsPressed = false;
var ready = true; var ready = true;
var MENU_NAME = 'Tools > Notifications';
var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds";
var NOTIFICATION_MENU_ITEM_POST = " Notifications"; 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 NOTIFICATIONS_MESSAGE_CHANNEL = "Hifi-Notifications";
var NotificationType = { var NotificationType = {
@ -401,11 +397,6 @@
alpha: backgroundAlpha alpha: backgroundAlpha
}; };
if (Menu.isOptionChecked(PLAY_NOTIFICATION_SOUNDS_MENU_ITEM) &&
Menu.isOptionChecked(NotificationType.getMenuString(notificationType))) {
randomSounds.playRandom();
}
return notify(noticeProperties, buttonProperties, height, imageProperties); 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 // When our script shuts down, we should clean up all of our overlays
function scriptEnding() { function scriptEnding() {
var notificationIndex; var notificationIndex;
@ -649,27 +616,14 @@
Overlays.deleteOverlay(notifications[notificationIndex]); Overlays.deleteOverlay(notifications[notificationIndex]);
Overlays.deleteOverlay(buttons[notificationIndex]); Overlays.deleteOverlay(buttons[notificationIndex]);
} }
Menu.removeMenu(MENU_NAME);
Messages.unsubscribe(NOTIFICATIONS_MESSAGE_CHANNEL); 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.keyPressEvent.connect(keyPressEvent);
Controller.mousePressEvent.connect(mousePressEvent); Controller.mousePressEvent.connect(mousePressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent); Controller.keyReleaseEvent.connect(keyReleaseEvent);
Script.update.connect(update); Script.update.connect(update);
Script.scriptEnding.connect(scriptEnding); Script.scriptEnding.connect(scriptEnding);
Menu.menuItemEvent.connect(menuItemEvent);
Window.domainConnectionRefused.connect(onDomainConnectionRefused); Window.domainConnectionRefused.connect(onDomainConnectionRefused);
Window.stillSnapshotTaken.connect(onSnapshotTaken); Window.stillSnapshotTaken.connect(onSnapshotTaken);
Window.snapshot360Taken.connect(onSnapshotTaken); Window.snapshot360Taken.connect(onSnapshotTaken);
@ -684,7 +638,4 @@
Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL); Messages.subscribe(NOTIFICATIONS_MESSAGE_CHANNEL);
Messages.messageReceived.connect(onMessageReceived); Messages.messageReceived.connect(onMessageReceived);
setup();
}()); // END LOCAL_SCOPE }()); // END LOCAL_SCOPE

View file

@ -47,7 +47,6 @@ void RotationConstraintTests::testElbowConstraint() {
glm::quat inputRotation = referenceRotation; glm::quat inputRotation = referenceRotation;
glm::quat outputRotation = inputRotation; glm::quat outputRotation = inputRotation;
bool updated = elbow.apply(outputRotation); bool updated = elbow.apply(outputRotation);
QVERIFY(updated == false);
glm::quat expectedRotation = referenceRotation; glm::quat expectedRotation = referenceRotation;
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
} }
@ -62,7 +61,6 @@ void RotationConstraintTests::testElbowConstraint() {
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
glm::quat outputRotation = inputRotation; glm::quat outputRotation = inputRotation;
bool updated = elbow.apply(outputRotation); bool updated = elbow.apply(outputRotation);
QVERIFY(updated == false);
QCOMPARE_WITH_ABS_ERROR(inputRotation, outputRotation, EPSILON); QCOMPARE_WITH_ABS_ERROR(inputRotation, outputRotation, EPSILON);
} }
} }
@ -72,7 +70,6 @@ void RotationConstraintTests::testElbowConstraint() {
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
glm::quat outputRotation = inputRotation; glm::quat outputRotation = inputRotation;
bool updated = elbow.apply(outputRotation); bool updated = elbow.apply(outputRotation);
QVERIFY(updated == true);
glm::quat expectedRotation = glm::angleAxis(minAngle, hingeAxis) * referenceRotation; glm::quat expectedRotation = glm::angleAxis(minAngle, hingeAxis) * referenceRotation;
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
} }
@ -82,7 +79,6 @@ void RotationConstraintTests::testElbowConstraint() {
glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation; glm::quat inputRotation = glm::angleAxis(angle, hingeAxis) * referenceRotation;
glm::quat outputRotation = inputRotation; glm::quat outputRotation = inputRotation;
bool updated = elbow.apply(outputRotation); bool updated = elbow.apply(outputRotation);
QVERIFY(updated == true);
glm::quat expectedRotation = glm::angleAxis(maxAngle, hingeAxis) * referenceRotation; glm::quat expectedRotation = glm::angleAxis(maxAngle, hingeAxis) * referenceRotation;
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
} }
@ -94,7 +90,6 @@ void RotationConstraintTests::testElbowConstraint() {
glm::quat inputRotation = glm::angleAxis(someAngle, twistVector) * referenceRotation; glm::quat inputRotation = glm::angleAxis(someAngle, twistVector) * referenceRotation;
glm::quat outputRotation = inputRotation; glm::quat outputRotation = inputRotation;
bool updated = elbow.apply(outputRotation); bool updated = elbow.apply(outputRotation);
QVERIFY(updated == true);
glm::quat expectedRotation = referenceRotation; glm::quat expectedRotation = referenceRotation;
QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON); QCOMPARE_WITH_ABS_ERROR(expectedRotation, outputRotation, EPSILON);
} }

View file

@ -15,6 +15,12 @@
// Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity // Computes SSIM - see https://en.wikipedia.org/wiki/Structural_similarity
// The value is computed for the luminance component and the average value is returned // The value is computed for the luminance component and the average value is returned
double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) const { 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 int L = 255; // (2^number of bits per pixel) - 1
const double K1 { 0.01 }; const double K1 { 0.01 };
const double K2 { 0.03 }; const double K2 { 0.03 };
@ -54,8 +60,8 @@ double ImageComparer::compareImages(QImage resultImage, QImage expectedImage) co
// Collect pixels into linear arrays // Collect pixels into linear arrays
int i{ 0 }; int i{ 0 };
for (int xx = 0; xx < WIN_SIZE; ++xx) { for (int xx = 0; xx < WIN_SIZE && x + xx < expectedImage.width(); ++xx) {
for (int yy = 0; yy < WIN_SIZE; ++yy) { for (int yy = 0; yy < WIN_SIZE && y + yy < expectedImage.height(); ++yy) {
// Get pixels // Get pixels
QRgb pixelP = expectedImage.pixel(QPoint(x + xx, y + yy)); QRgb pixelP = expectedImage.pixel(QPoint(x + xx, y + yy));
QRgb pixelQ = resultImage.pixel(QPoint(x + xx, y + yy)); QRgb pixelQ = resultImage.pixel(QPoint(x + xx, y + yy));

View file

@ -63,7 +63,7 @@ bool Test::compareImageLists(bool isInteractiveMode, QProgressBar* progressBar)
// Loop over both lists and compare each pair of images // Loop over both lists and compare each pair of images
// Quit loop if user has aborted due to a failed test. // 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 success{ true };
bool keepOn{ true }; bool keepOn{ true };
for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) { for (int i = 0; keepOn && i < expectedImagesFullFilenames.length(); ++i) {
@ -131,7 +131,9 @@ void Test::appendTestResultsToFile(const QString& testResultsFolderPath, TestFai
exit(-1); 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)) { if (!QDir().mkdir(failureFolderPath)) {
QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath); QMessageBox::critical(0, "Internal error: " + QString(__FILE__) + ":" + QString::number(__LINE__), "Failed to create folder " + failureFolderPath);
exit(-1); exit(-1);
@ -395,9 +397,9 @@ void Test::createRecursiveScript(const QString& topLevelDirectory, bool interact
const QString DATE_TIME_FORMAT("MMM d yyyy, h:mm"); 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 << "// 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 << "user = \"" + GIT_HUB_USER + "/\";" << endl;
textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\"" << endl; textStream << "repository = \"" + GIT_HUB_REPOSITORY + "/\";" << endl;
textStream << "branch = \"" + GIT_HUB_BRANCH + "/\"" << endl << endl; textStream << "branch = \"" + GIT_HUB_BRANCH + "/\";" << endl << endl;
textStream << "var autoTester = Script.require(\"https://github.com/" + GIT_HUB_USER + "/hifi_tests/blob/" 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; + GIT_HUB_BRANCH + "/tests/utils/autoTester.js?raw=true\");" << endl << endl;

View file

@ -10,6 +10,11 @@
// //
#include "AutoTester.h" #include "AutoTester.h"
#ifdef Q_OS_WIN
#include <windows.h>
#include <shellapi.h>
#endif
AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) { AutoTester::AutoTester(QWidget *parent) : QMainWindow(parent) {
ui.setupUi(this); ui.setupUi(this);
ui.checkBoxInteractiveMode->setChecked(true); 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.actionClose, &QAction::triggered, this, &AutoTester::on_closeButton_clicked);
connect(ui.actionAbout, &QAction::triggered, this, &AutoTester::about); connect(ui.actionAbout, &QAction::triggered, this, &AutoTester::about);
#ifndef Q_OS_WIN
ui.hideTaskbarButton->setVisible(false);
ui.showTaskbarButton->setVisible(false);
#endif
test = new Test(); test = new Test();
} }
@ -56,6 +66,30 @@ void AutoTester::on_createTestsOutlineButton_clicked() {
test->createTestsOutline(); 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() { void AutoTester::on_closeButton_clicked() {
exit(0); exit(0);
} }
@ -95,7 +129,7 @@ void AutoTester::saveImage(int index) {
pixmap.loadFromData(downloaders[index]->downloadedData()); pixmap.loadFromData(downloaders[index]->downloadedData());
QImage image = pixmap.toImage(); QImage image = pixmap.toImage();
image = image.convertToFormat(QImage::Format_RGB32); image = image.convertToFormat(QImage::Format_ARGB32);
QString fullPathname = _directoryName + "/" + _filenames[index]; QString fullPathname = _directoryName + "/" + _filenames[index];
if (!image.save(fullPathname, 0, 100)) { if (!image.save(fullPathname, 0, 100)) {

View file

@ -36,6 +36,10 @@ private slots:
void on_createMDFileButton_clicked(); void on_createMDFileButton_clicked();
void on_createAllMDFilesButton_clicked(); void on_createAllMDFilesButton_clicked();
void on_createTestsOutlineButton_clicked(); void on_createTestsOutlineButton_clicked();
void on_hideTaskbarButton_clicked();
void on_showTaskbarButton_clicked();
void on_closeButton_clicked(); void on_closeButton_clicked();
void saveImage(int index); void saveImage(int index);

View file

@ -147,6 +147,32 @@
<string>Create Tests Outline</string> <string>Create Tests Outline</string>
</property> </property>
</widget> </widget>
<widget class="QPushButton" name="showTaskbarButton">
<property name="geometry">
<rect>
<x>490</x>
<y>280</y>
<width>91</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Show Taskbar</string>
</property>
</widget>
<widget class="QPushButton" name="hideTaskbarButton">
<property name="geometry">
<rect>
<x>490</x>
<y>230</y>
<width>91</width>
<height>40</height>
</rect>
</property>
<property name="text">
<string>Hide Taskbar</string>
</property>
</widget>
</widget> </widget>
<widget class="QMenuBar" name="menuBar"> <widget class="QMenuBar" name="menuBar">
<property name="geometry"> <property name="geometry">