From 225b330d416a70e6ed1b8f1b8cc82d22d6400622 Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 Mar 2016 12:47:33 -0700 Subject: [PATCH 01/39] Trying to better load aand detect the case for transparent textures oor opacity mask --- .../src/model-networking/ModelCache.cpp | 17 ++++++- .../src/model-networking/ModelCache.h | 1 + libraries/model/src/model/Material.cpp | 43 +++++++++++++++-- libraries/model/src/model/Material.h | 48 ++++++++++--------- libraries/model/src/model/TextureMap.h | 5 ++ .../render-utils/src/MeshPartPayload.cpp | 8 ++-- 6 files changed, 88 insertions(+), 34 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index c9ff8e681b..855a5965ad 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -147,11 +147,12 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } - if (material->albedoTexture && material->albedoTexture->getGPUTexture()) { + if (material->useAlbedoMapOpacity && material->albedoTexture && material->albedoTexture->getGPUTexture()) { + material->_material->setTextureMap(model::MaterialKey::ALBEDO_MAP, material->_material->getTextureMap(model::MaterialKey::ALBEDO_MAP)); // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); - material->_material->setTransparentTexture(isTransparentTexture); + // material->_material->setTransparentTexture(isTransparentTexture); // FIXME: Materials with *some* transparent textures seem to give all *other* textures alphas of 0. _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; } @@ -376,9 +377,21 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB auto albedoMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.albedoTexture, DEFAULT_TEXTURE, networkMaterial->albedoTexture, networkMaterial->albedoTextureName); albedoMap->setTextureTransform(material.albedoTexture.transform); + + if (!material.opacityTexture.filename.isEmpty()) { + if (material.albedoTexture.filename == material.opacityTexture.filename) { + // Best case scenario, just indicating that the albedo map contains transparency + networkMaterial->useAlbedoMapOpacity; + albedoMap->setUseAlphaChannel(true); + } else { + // Opacity Map is different from the Abledo map, not supported + } + } + material._material->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); } + if (!material.normalTexture.filename.isEmpty()) { auto normalMap = setupNetworkTextureMap(geometry, textureBaseUrl, material.normalTexture, (material.normalTexture.isBumpmap ? BUMP_TEXTURE : NORMAL_TEXTURE), diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index 7f01bdafaa..b172bb70b4 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -199,6 +199,7 @@ public: QSharedPointer occlusionTexture; QString lightmapTextureName; QSharedPointer lightmapTexture; + bool useAlbedoMapOpacity{ false }; }; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 306867c204..21fdab59a3 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -51,7 +51,7 @@ void Material::setEmissive(const Color& emissive, bool isSRGB) { } void Material::setOpacity(float opacity) { - _key.setTransparent((opacity < 1.0f)); + _key.setTransparentFactor((opacity < 1.0f)); _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._opacity = opacity; } @@ -80,19 +80,52 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = metallic; } -void Material::setTransparentTexture(bool isTransparent) { - _key.setTransparentTexture(isTransparent); - _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); -} void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { _key.setMapChannel(channel, (true)); + + if (channel == MaterialKey::ALBEDO_MAP) { + if (textureMap->useAlphaChannel()) { + if (textureMap->isDefined()) { + if (textureMap->getTextureView().isValid()) { + auto usage = textureMap->getTextureView()._texture->getUsage(); + if (usage.isAlpha()) { + // Texture has alpha, is nut just a mask or a true transparent channel + if (!usage.isAlphaMask()) { + _key.setOpacityMaskMap(true); + _key.setTransparentMap(false); + } else { + _key.setOpacityMaskMap(false); + _key.setTransparentMap(true); + } + } + } + } + } + } + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps[channel] = textureMap; } else { _key.setMapChannel(channel, (false)); + + if (channel == MaterialKey::ALBEDO_MAP) { + _key.setOpacityMaskMap(false); + _key.setTransparentMap(false); + } + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps.erase(channel); } } + + +const TextureMapPointer Material::getTextureMap(MapChannel channel) const { + auto result = _textureMaps.find(channel); + if (result != _textureMaps.end()) { + return (result->second); + } else { + return TextureMapPointer(); + } +} \ No newline at end of file diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 078fc6499a..0cef46f788 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -31,14 +31,14 @@ public: ALBEDO_VAL_BIT, METALLIC_VAL_BIT, GLOSSY_VAL_BIT, - TRANSPARENT_VAL_BIT, - TRANSPARENT_TEX_VAL_BIT, + OPACITY_VAL_BIT, EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, + OPACITY_MASK_MAP_BIT, // OPacity Map and Opacity MASK map are mutually exclusive + OPACITY_TRANSPARENT_MAP_BIT, METALLIC_MAP_BIT, ROUGHNESS_MAP_BIT, - TRANSPARENT_MAP_BIT, NORMAL_MAP_BIT, OCCLUSION_MAP_BIT, LIGHTMAP_MAP_BIT, @@ -52,7 +52,6 @@ public: ALBEDO_MAP, METALLIC_MAP, ROUGHNESS_MAP, - TRANSPARENT_MAP, NORMAL_MAP, OCCLUSION_MAP, LIGHTMAP_MAP, @@ -77,13 +76,15 @@ public: Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT); return (*this); } Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); } Builder& withGlossy() { _flags.set(GLOSSY_VAL_BIT); return (*this); } - Builder& withTransparent() { _flags.set(TRANSPARENT_VAL_BIT); return (*this); } + Builder& withOpacity() { _flags.set(OPACITY_VAL_BIT); return (*this); } Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT); return (*this); } Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } Builder& withRoughnessMap() { _flags.set(ROUGHNESS_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _flags.set(TRANSPARENT_MAP_BIT); return (*this); } + + Builder& withTransparentMap() { _flags.set(OPACITY_TRANSPARENT_MAP_BIT); return (*this); } + Builder& withMaskMap() { _flags.set(OPACITY_MASK_MAP_BIT); return (*this); } Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } Builder& withOcclusionMap() { _flags.set(OCCLUSION_MAP_BIT); return (*this); } @@ -102,9 +103,6 @@ public: void setAlbedo(bool value) { _flags.set(ALBEDO_VAL_BIT, value); } bool isAlbedo() const { return _flags[ALBEDO_VAL_BIT]; } - void setTransparentTexture(bool value) { _flags.set(TRANSPARENT_TEX_VAL_BIT, value); } - bool isTransparentTexture() const { return _flags[TRANSPARENT_TEX_VAL_BIT]; } - void setAlbedoMap(bool value) { _flags.set(ALBEDO_MAP_BIT, value); } bool isAlbedoMap() const { return _flags[ALBEDO_MAP_BIT]; } @@ -121,13 +119,16 @@ public: void setRoughnessMap(bool value) { _flags.set(ROUGHNESS_MAP_BIT, value); } bool isRoughnessMap() const { return _flags[ROUGHNESS_MAP_BIT]; } - void setTransparent(bool value) { _flags.set(TRANSPARENT_VAL_BIT, value); } - bool isTransparent() const { return _flags[TRANSPARENT_VAL_BIT]; } - bool isOpaque() const { return !_flags[TRANSPARENT_VAL_BIT]; } + void setTransparentFactor(bool value) { _flags.set(OPACITY_VAL_BIT, value); } + bool isTransparentFactor() const { return _flags[OPACITY_VAL_BIT]; } + bool isOpaqueFactor() const { return !_flags[OPACITY_VAL_BIT]; } - void setTransparentMap(bool value) { _flags.set(TRANSPARENT_MAP_BIT, value); } - bool isTransparentMap() const { return _flags[TRANSPARENT_MAP_BIT]; } + void setTransparentMap(bool value) { _flags.set(OPACITY_TRANSPARENT_MAP_BIT, value); } + bool isTransparentMap() const { return _flags[OPACITY_TRANSPARENT_MAP_BIT]; } + void setOpacityMaskMap(bool value) { _flags.set(OPACITY_MASK_MAP_BIT, value); } + bool isOpacityMaskMap() const { return _flags[OPACITY_MASK_MAP_BIT]; } + void setNormalMap(bool value) { _flags.set(NORMAL_MAP_BIT, value); } bool isNormalMap() const { return _flags[NORMAL_MAP_BIT]; } @@ -168,9 +169,6 @@ public: Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); } - Builder& withoutTransparentTexture() { _value.reset(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } - Builder& withTransparentTexture() { _value.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_TEX_VAL_BIT); return (*this); } - Builder& withoutAlbedoMap() { _value.reset(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _value.set(MaterialKey::ALBEDO_MAP_BIT); _mask.set(MaterialKey::ALBEDO_MAP_BIT); return (*this); } @@ -186,11 +184,15 @@ public: Builder& withoutRoughnessMap() { _value.reset(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } Builder& withRoughnessMap() { _value.set(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } - Builder& withoutTransparent() { _value.reset(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } - Builder& withTransparent() { _value.set(MaterialKey::TRANSPARENT_VAL_BIT); _mask.set(MaterialKey::TRANSPARENT_VAL_BIT); return (*this); } + Builder& withoutTransparentFactor() { _value.reset(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } + Builder& withTransparentFactor() { _value.set(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } + Builder& withOpaqueFactor() { return withoutTransparentFactor(); } - Builder& withoutTransparentMap() { _value.reset(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _value.set(MaterialKey::TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::TRANSPARENT_MAP_BIT); return (*this); } + Builder& withoutTransparentMap() { _value.reset(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); return (*this); } + Builder& withTransparentMap() { _value.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); return (*this); } + + Builder& withoutMaskMap() { _value.reset(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } + Builder& withMaskMap() { _value.set(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } Builder& withoutNormalMap() { _value.reset(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } Builder& withNormalMap() { _value.set(MaterialKey::NORMAL_MAP_BIT); _mask.set(MaterialKey::NORMAL_MAP_BIT); return (*this); } @@ -202,7 +204,7 @@ public: Builder& withLightmapMap() { _value.set(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); } // Convenient standard keys that we will keep on using all over the place - static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withoutTransparent().build(); } + static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withOpaqueFactor().build(); } }; // Item Filter operator testing if a key pass the filter @@ -255,7 +257,6 @@ public: void setRoughness(float roughness); float getRoughness() const { return _schemaBuffer.get()._roughness; } - void setTransparentTexture(bool isTransparent); // Schema to access the attribute values of the material class Schema { @@ -283,6 +284,7 @@ public: // The texture map to channel association void setTextureMap(MapChannel channel, const TextureMapPointer& textureMap); const TextureMaps& getTextureMaps() const { return _textureMaps; } + const TextureMapPointer getTextureMap(MapChannel channel) const; // conversion from legacy material properties to PBR equivalent static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; } diff --git a/libraries/model/src/model/TextureMap.h b/libraries/model/src/model/TextureMap.h index 228adb25e6..e845aebb81 100755 --- a/libraries/model/src/model/TextureMap.h +++ b/libraries/model/src/model/TextureMap.h @@ -56,6 +56,9 @@ public: void setTextureTransform(const Transform& texcoordTransform); const Transform& getTextureTransform() const { return _texcoordTransform; } + void setUseAlphaChannel(bool useAlpha) { _useAlphaChannel = useAlpha; } + bool useAlphaChannel() const { return _useAlphaChannel; } + void setLightmapOffsetScale(float offset, float scale); const glm::vec2& getLightmapOffsetScale() const { return _lightmapOffsetScale; } @@ -64,6 +67,8 @@ protected: Transform _texcoordTransform; glm::vec2 _lightmapOffsetScale{ 0.0f, 1.0f }; + + bool _useAlphaChannel{ false }; }; typedef std::shared_ptr< TextureMap > TextureMapPointer; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 4ae5b4532a..2e66fe43f2 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { + if (matKey.isTransparentFactor() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -100,7 +100,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap()) { + if (drawMaterialKey.isTransparentFactor() || drawMaterialKey.isTransparentMap()) { builder.withTranslucent(); } if (drawMaterialKey.isNormalMap()) { @@ -365,7 +365,7 @@ ItemKey ModelMeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparent() || matKey.isTransparentTexture() || matKey.isTransparentMap()) { + if (matKey.isTransparentFactor() || matKey.isTransparentMap()) { builder.withTransparent(); } } @@ -413,7 +413,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { } bool isTranslucent = - drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentTexture() || drawMaterialKey.isTransparentMap(); + drawMaterialKey.isTransparentFactor() || drawMaterialKey.isTransparentMap(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); From f7847f656163b7c2c9fc54f8a8157d269367b4ef Mon Sep 17 00:00:00 2001 From: samcake Date: Fri, 18 Mar 2016 17:32:00 -0700 Subject: [PATCH 02/39] Trying to fix names --- libraries/model/src/model/Material.h | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 0cef46f788..f590b73b85 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -36,7 +36,7 @@ public: EMISSIVE_MAP_BIT, ALBEDO_MAP_BIT, OPACITY_MASK_MAP_BIT, // OPacity Map and Opacity MASK map are mutually exclusive - OPACITY_TRANSPARENT_MAP_BIT, + OPACITY_TRANSLUCENT_MAP_BIT, METALLIC_MAP_BIT, ROUGHNESS_MAP_BIT, NORMAL_MAP_BIT, @@ -83,7 +83,7 @@ public: Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } Builder& withRoughnessMap() { _flags.set(ROUGHNESS_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _flags.set(OPACITY_TRANSPARENT_MAP_BIT); return (*this); } + Builder& withTransparentMap() { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } Builder& withMaskMap() { _flags.set(OPACITY_MASK_MAP_BIT); return (*this); } Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } @@ -119,12 +119,11 @@ public: void setRoughnessMap(bool value) { _flags.set(ROUGHNESS_MAP_BIT, value); } bool isRoughnessMap() const { return _flags[ROUGHNESS_MAP_BIT]; } - void setTransparentFactor(bool value) { _flags.set(OPACITY_VAL_BIT, value); } - bool isTransparentFactor() const { return _flags[OPACITY_VAL_BIT]; } - bool isOpaqueFactor() const { return !_flags[OPACITY_VAL_BIT]; } + void setTranslucentFactor(bool value) { _flags.set(OPACITY_VAL_BIT, value); } + bool isTranslucentFactor() const { return _flags[OPACITY_VAL_BIT]; } - void setTransparentMap(bool value) { _flags.set(OPACITY_TRANSPARENT_MAP_BIT, value); } - bool isTransparentMap() const { return _flags[OPACITY_TRANSPARENT_MAP_BIT]; } + void setTransparentMap(bool value) { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT, value); } + bool isOpacityMap() const { return _flags[OPACITY_TRANSLUCENT_MAP_BIT]; } void setOpacityMaskMap(bool value) { _flags.set(OPACITY_MASK_MAP_BIT, value); } bool isOpacityMaskMap() const { return _flags[OPACITY_MASK_MAP_BIT]; } @@ -188,8 +187,8 @@ public: Builder& withTransparentFactor() { _value.set(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } Builder& withOpaqueFactor() { return withoutTransparentFactor(); } - Builder& withoutTransparentMap() { _value.reset(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _value.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSPARENT_MAP_BIT); return (*this); } + Builder& withoutTransparentMap() { _value.reset(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } + Builder& withTransparentMap() { _value.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } Builder& withoutMaskMap() { _value.reset(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } Builder& withMaskMap() { _value.set(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } From cdbb7b2ad4294796ae007c0d74f0c07df1d5a4dd Mon Sep 17 00:00:00 2001 From: Menithal Date: Sat, 19 Mar 2016 12:32:32 +0200 Subject: [PATCH 03/39] Set UserAnimPreAndPostRotations true by Default If Blender avatars are animated by Blender animations, they have missing Pre and Post rotations. This step is no longer necessary to have false, and also makes sure all animations from Blender Work on all avatars (from other platforms). This commit make it default to be enabled: --- interface/src/Menu.cpp | 14 +++++++------- libraries/animation/src/AnimClip.cpp | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 35bc2aa696..63c67f6b9f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -107,7 +107,7 @@ Menu::Menu() { auto scriptEngines = DependencyManager::get(); // Edit > Stop All Scripts... [advanced] - addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, + addActionToQMenuAndActionHash(editMenu, MenuOption::StopAllScripts, 0, scriptEngines.data(), SLOT(stopAllScripts()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); @@ -140,7 +140,7 @@ Menu::Menu() { // Edit > Reload All Content [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::ReloadContent, 0, qApp, SLOT(reloadResourceCaches()), QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - + // Edit > Package Model... [advanced] addActionToQMenuAndActionHash(editMenu, MenuOption::PackageModel, 0, @@ -153,7 +153,7 @@ Menu::Menu() { auto audioIO = DependencyManager::get(); // Audio > Mute - addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, + addCheckableActionToQMenuAndActionHash(audioMenu, MenuOption::MuteAudio, Qt::CTRL | Qt::Key_M, false, audioIO.data(), SLOT(toggleMute())); // Audio > Show Level Meter @@ -458,7 +458,7 @@ Menu::Menu() { avatar, SLOT(setEnableMeshVisible(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::DisableEyelidAdjustment, 0, false); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::TurnWithHead, 0, false); - addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::UseAnimPreAndPostRotations, 0, false, + addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::UseAnimPreAndPostRotations, 0, true, avatar, SLOT(setUseAnimPreAndPostRotations(bool))); addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true, avatar, SLOT(setEnableInverseKinematics(bool))); @@ -534,7 +534,7 @@ Menu::Menu() { // Developer > Audio >>> MenuWrapper* audioDebugMenu = developerMenu->addMenu("Audio"); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true, + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioNoiseReduction, 0, true, audioIO.data(), SLOT(toggleAudioNoiseReduction())); addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio, 0, false, audioIO.data(), SLOT(toggleServerEcho())); @@ -617,7 +617,7 @@ Menu::Menu() { QAction::NoRole, UNSPECIFIED_POSITION, "Advanced"); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true, NULL, NULL, UNSPECIFIED_POSITION, "Advanced"); #endif } @@ -651,7 +651,7 @@ void Menu::addMenuItem(const MenuItemProperties& properties) { } else if (properties.isCheckable) { menuItemAction = addCheckableActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, properties.isChecked, - MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), + MenuScriptingInterface::getInstance(), SLOT(menuItemTriggered()), requestedPosition, properties.grouping); } else { menuItemAction = addActionToQMenuAndActionHash(menuObj, properties.menuItemName, properties.shortcutKeySequence, diff --git a/libraries/animation/src/AnimClip.cpp b/libraries/animation/src/AnimClip.cpp index e8f429f22c..a5747e4f96 100644 --- a/libraries/animation/src/AnimClip.cpp +++ b/libraries/animation/src/AnimClip.cpp @@ -13,7 +13,7 @@ #include "AnimationLogging.h" #include "AnimUtil.h" -bool AnimClip::usePreAndPostPoseFromAnim = false; +bool AnimClip::usePreAndPostPoseFromAnim = true; AnimClip::AnimClip(const QString& id, const QString& url, float startFrame, float endFrame, float timeScale, bool loopFlag, bool mirrorFlag) : AnimNode(AnimNode::Type::Clip, id), From 227ddb12a6f0af743fa29263625e0fdb22a8e098 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Mar 2016 12:14:59 -0700 Subject: [PATCH 04/39] Trying to clen up the way the opacity final value comes to the fragment shader --- libraries/model/src/model/Material.cpp | 8 +++--- libraries/model/src/model/Material.h | 25 +++++++++++-------- libraries/model/src/model/Material.slh | 20 +++++++-------- .../render-utils/src/MaterialTextures.slh | 19 +++++++++++++- .../render-utils/src/MeshPartPayload.cpp | 9 +++---- libraries/render-utils/src/model.slf | 6 ++++- .../render-utils/src/model_normal_map.slf | 6 ++++- .../src/model_normal_specular_map.slf | 6 ++++- .../render-utils/src/model_specular_map.slf | 6 ++++- .../render-utils/src/model_translucent.slf | 8 +++--- 10 files changed, 76 insertions(+), 37 deletions(-) diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 21fdab59a3..5f5c93eb61 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -51,7 +51,7 @@ void Material::setEmissive(const Color& emissive, bool isSRGB) { } void Material::setOpacity(float opacity) { - _key.setTransparentFactor((opacity < 1.0f)); + _key.setTranslucentFactor((opacity < 1.0f)); _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit()._opacity = opacity; } @@ -94,10 +94,10 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur // Texture has alpha, is nut just a mask or a true transparent channel if (!usage.isAlphaMask()) { _key.setOpacityMaskMap(true); - _key.setTransparentMap(false); + _key.setTranslucentMap(false); } else { _key.setOpacityMaskMap(false); - _key.setTransparentMap(true); + _key.setTranslucentMap(true); } } } @@ -112,7 +112,7 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur if (channel == MaterialKey::ALBEDO_MAP) { _key.setOpacityMaskMap(false); - _key.setTransparentMap(false); + _key.setTranslucentMap(false); } _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index f590b73b85..2527c8e1e1 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -76,14 +76,14 @@ public: Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT); return (*this); } Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); } Builder& withGlossy() { _flags.set(GLOSSY_VAL_BIT); return (*this); } - Builder& withOpacity() { _flags.set(OPACITY_VAL_BIT); return (*this); } + Builder& withTranslucentFactor() { _flags.set(OPACITY_VAL_BIT); return (*this); } Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); } Builder& withAlbedoMap() { _flags.set(ALBEDO_MAP_BIT); return (*this); } Builder& withMetallicMap() { _flags.set(METALLIC_MAP_BIT); return (*this); } Builder& withRoughnessMap() { _flags.set(ROUGHNESS_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } + Builder& withTranslucentMap() { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } Builder& withMaskMap() { _flags.set(OPACITY_MASK_MAP_BIT); return (*this); } Builder& withNormalMap() { _flags.set(NORMAL_MAP_BIT); return (*this); } @@ -122,8 +122,8 @@ public: void setTranslucentFactor(bool value) { _flags.set(OPACITY_VAL_BIT, value); } bool isTranslucentFactor() const { return _flags[OPACITY_VAL_BIT]; } - void setTransparentMap(bool value) { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT, value); } - bool isOpacityMap() const { return _flags[OPACITY_TRANSLUCENT_MAP_BIT]; } + void setTranslucentMap(bool value) { _flags.set(OPACITY_TRANSLUCENT_MAP_BIT, value); } + bool isTranslucentMap() const { return _flags[OPACITY_TRANSLUCENT_MAP_BIT]; } void setOpacityMaskMap(bool value) { _flags.set(OPACITY_MASK_MAP_BIT, value); } bool isOpacityMaskMap() const { return _flags[OPACITY_MASK_MAP_BIT]; } @@ -140,6 +140,12 @@ public: void setMapChannel(MapChannel channel, bool value) { _flags.set(EMISSIVE_MAP_BIT + channel, value); } bool isMapChannel(MapChannel channel) const { return _flags[EMISSIVE_MAP_BIT + channel]; } + + // Translucency and Opacity Heuristics are combining several flags: + bool isTranslucent() const { return isTranslucentFactor() || isTranslucentMap(); } + bool isOpaque() const { return !isTranslucent(); } + bool isSurfaceOpaque() const { return isOpaque() && !isOpacityMaskMap(); } + bool isTexelOpaque() const { return isOpaque() && isOpacityMaskMap(); } }; @@ -183,12 +189,11 @@ public: Builder& withoutRoughnessMap() { _value.reset(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } Builder& withRoughnessMap() { _value.set(MaterialKey::ROUGHNESS_MAP_BIT); _mask.set(MaterialKey::ROUGHNESS_MAP_BIT); return (*this); } - Builder& withoutTransparentFactor() { _value.reset(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } - Builder& withTransparentFactor() { _value.set(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } - Builder& withOpaqueFactor() { return withoutTransparentFactor(); } + Builder& withoutTranslucentFactor() { _value.reset(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } + Builder& withTranslucentFactor() { _value.set(MaterialKey::OPACITY_VAL_BIT); _mask.set(MaterialKey::OPACITY_VAL_BIT); return (*this); } - Builder& withoutTransparentMap() { _value.reset(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } - Builder& withTransparentMap() { _value.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } + Builder& withoutTranslucentMap() { _value.reset(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } + Builder& withTranslucentMap() { _value.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); _mask.set(MaterialKey::OPACITY_TRANSLUCENT_MAP_BIT); return (*this); } Builder& withoutMaskMap() { _value.reset(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } Builder& withMaskMap() { _value.set(MaterialKey::OPACITY_MASK_MAP_BIT); _mask.set(MaterialKey::OPACITY_MASK_MAP_BIT); return (*this); } @@ -203,7 +208,7 @@ public: Builder& withLightmapMap() { _value.set(MaterialKey::LIGHTMAP_MAP_BIT); _mask.set(MaterialKey::LIGHTMAP_MAP_BIT); return (*this); } // Convenient standard keys that we will keep on using all over the place - static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withOpaqueFactor().build(); } + static MaterialFilter opaqueAlbedo() { return Builder().withAlbedo().withoutTranslucentFactor().build(); } }; // Item Filter operator testing if a key pass the filter diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index da185ddf0b..e8c9d3d6bc 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -43,17 +43,17 @@ const int EMISSIVE_VAL_BIT = 0x00000001; const int ALBEDO_VAL_BIT = 0x00000002; const int METALLIC_VAL_BIT = 0x00000004; const int GLOSSY_VAL_BIT = 0x00000008; -const int TRANSPARENT_VAL_BIT = 0x00000010; -const int TRANSPARENT_TEX_VAL_BIT = 0x00000020; +const int OPACITY_VAL_BIT = 0x00000010; -const int EMISSIVE_MAP_BIT = 0x00000040; -const int ALBEDO_MAP_BIT = 0x00000080; -const int METALLIC_MAP_BIT = 0x00000100; -const int ROUGHNESS_MAP_BIT = 0x00000200; -const int TRANSPARENT_MAP_BIT = 0x00000400; -const int NORMAL_MAP_BIT = 0x00000800; -const int OCCLUSION_MAP_BIT = 0x00001000; +const int EMISSIVE_MAP_BIT = 0x00000020; +const int ALBEDO_MAP_BIT = 0x00000040; +const int OPACITY_MASK_MAP_BIT = 0x00000080; +const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000100; +const int METALLIC_MAP_BIT = 0x00000200; +const int ROUGHNESS_MAP_BIT = 0x00000400; +const int NORMAL_MAP_BIT = 0x00001000; +const int OCCLUSION_MAP_BIT = 0x00002000; +const int LIGHTMAP_MAP_BIT = 0x00004000; -const int LIGHTMAP_MAP_BIT = 0x00002000; <@endif@> diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index 8904ae34b2..ef8c30a97f 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -59,7 +59,7 @@ float fetchOcclusionMap(vec2 uv) { <@func fetchMaterialTextures(matKey, texcoord0, albedo, roughness, normal, metallic, emissive, occlusion)@> <@if albedo@> - vec4 <$albedo$> = (((<$matKey$> & ALBEDO_MAP_BIT) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0)); + vec4 <$albedo$> = (((<$matKey$> & (ALBEDO_MAP_BIT | OPACITY_MASK_MAP_BIT | OPACITY_TRANSLUCENT_MAP_BIT)) != 0) ? fetchAlbedoMap(<$texcoord0$>) : vec4(1.0)); <@endif@> <@if roughness@> float <$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? fetchRoughnessMap(<$texcoord0$>) : 1.0); @@ -112,6 +112,23 @@ vec3 fetchLightmapMap(vec2 uv) { } <@endfunc@> +<@func evalMaterialOpacity(fetchedOpacity, materialOpacity, matKey, opacity)@> +{ + const float OPACITY_MASK_THRESHOLD = 0.5; + <$opacity$> = (((<$matKey$> & (OPACITY_TRANSLUCENCY_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0) ? + (((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(OPACITY_MASK_THRESHOLD, <$fetchedOpacity$>) : <$fetchedOpacity$>) : + 1.0) * <$materialOpacity$>; +} +<@endfunc@> + +<@func $discardTransparent(opacity)@> +{ + if (<$opacity$> < 1.0) { + discard; + } +} +<@endfunc@> + <@func evalMaterialRoughness(fetchedRoughness, materialRoughness, matKey, roughness)@> { <$roughness$> = (((<$matKey$> & ROUGHNESS_MAP_BIT) != 0) ? <$fetchedRoughness$> : <$materialRoughness$>); diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index 2e66fe43f2..aca9774221 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparentFactor() || matKey.isTransparentMap()) { + if (matKey.isTranslucentFactor() || matKey.isTranslucentMap()) { builder.withTransparent(); } } @@ -100,7 +100,7 @@ ShapeKey MeshPartPayload::getShapeKey() const { } ShapeKey::Builder builder; - if (drawMaterialKey.isTransparentFactor() || drawMaterialKey.isTransparentMap()) { + if (drawMaterialKey.isTranslucent()) { builder.withTranslucent(); } if (drawMaterialKey.isNormalMap()) { @@ -365,7 +365,7 @@ ItemKey ModelMeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTransparentFactor() || matKey.isTransparentMap()) { + if (matKey.isTranslucent()) { builder.withTransparent(); } } @@ -412,8 +412,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const { drawMaterialKey = _drawMaterial->getKey(); } - bool isTranslucent = - drawMaterialKey.isTransparentFactor() || drawMaterialKey.isTransparentMap(); + bool isTranslucent = drawMaterialKey.isTranslucent(); bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty(); bool hasSpecular = drawMaterialKey.isMetallicMap(); bool hasLightmap = drawMaterialKey.isLightmapMap(); diff --git a/libraries/render-utils/src/model.slf b/libraries/render-utils/src/model.slf index c9ca6d9eb7..ddfd83d1d4 100755 --- a/libraries/render-utils/src/model.slf +++ b/libraries/render-utils/src/model.slf @@ -29,6 +29,10 @@ void main(void) { int matKey = getMaterialKey(mat); <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; @@ -41,7 +45,7 @@ void main(void) { packDeferredFragment( normalize(_normal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + opacity, albedo, roughness, getMaterialMetallic(mat), diff --git a/libraries/render-utils/src/model_normal_map.slf b/libraries/render-utils/src/model_normal_map.slf index a584427005..10ae6ee880 100755 --- a/libraries/render-utils/src/model_normal_map.slf +++ b/libraries/render-utils/src/model_normal_map.slf @@ -30,6 +30,10 @@ void main(void) { int matKey = getMaterialKey(mat); <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; @@ -45,7 +49,7 @@ void main(void) { packDeferredFragment( viewNormal, - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + opacity, albedo, roughness, getMaterialMetallic(mat), diff --git a/libraries/render-utils/src/model_normal_specular_map.slf b/libraries/render-utils/src/model_normal_specular_map.slf index cf461db7ef..2529596818 100755 --- a/libraries/render-utils/src/model_normal_specular_map.slf +++ b/libraries/render-utils/src/model_normal_specular_map.slf @@ -30,6 +30,10 @@ void main(void) { int matKey = getMaterialKey(mat); <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, metallicTex, emissiveTex, occlusionTex)$> + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; @@ -49,7 +53,7 @@ void main(void) { packDeferredFragment( normalize(viewNormal.xyz), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + opacity, albedo, roughness, metallic, diff --git a/libraries/render-utils/src/model_specular_map.slf b/libraries/render-utils/src/model_specular_map.slf index 32e5823430..9b2f4ae640 100755 --- a/libraries/render-utils/src/model_specular_map.slf +++ b/libraries/render-utils/src/model_specular_map.slf @@ -30,6 +30,10 @@ void main(void) { int matKey = getMaterialKey(mat); <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex, occlusionTex)$> + float opacity = 1.0; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; @@ -45,7 +49,7 @@ void main(void) { packDeferredFragment( normalize(_normal), - evalOpaqueFinalAlpha(getMaterialOpacity(mat), albedoTex.a), + opacity, albedo, roughness, metallic, diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index b99b5c8a2a..12a7b9299f 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -36,6 +36,10 @@ void main(void) { int matKey = getMaterialKey(mat); <$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$> + float opacity = getMaterialOpacity(mat) * _alpha; + <$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>; + <$discardTransparent(opacity)$>; + vec3 albedo = getMaterialAlbedo(mat); <$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>; albedo *= _color; @@ -52,8 +56,6 @@ void main(void) { vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - float fragOpacity = getMaterialOpacity(mat) * albedoTex.a * _alpha; - TransformCamera cam = getTransformCamera(); _fragColor = vec4(evalAmbientSphereGlobalColor( @@ -66,5 +68,5 @@ void main(void) { metallic, emissive, roughness), - fragOpacity); + opacity); } From d189dc4af2f42da7d2f1b6226a8897d162542c13 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Mar 2016 13:30:08 -0700 Subject: [PATCH 05/39] Problem not fixed yet, need to merge with upstream --- libraries/render-utils/src/MaterialTextures.slh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index ef8c30a97f..b25876af63 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -114,9 +114,9 @@ vec3 fetchLightmapMap(vec2 uv) { <@func evalMaterialOpacity(fetchedOpacity, materialOpacity, matKey, opacity)@> { - const float OPACITY_MASK_THRESHOLD = 0.5; - <$opacity$> = (((<$matKey$> & (OPACITY_TRANSLUCENCY_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0) ? - (((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(OPACITY_MASK_THRESHOLD, <$fetchedOpacity$>) : <$fetchedOpacity$>) : + const float OPACITY_MASK_THRESHOLD = 0.95; + <$opacity$> = (((<$matKey$> & (OPACITY_TRANSLUCENT_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0) ? + (((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(<$fetchedOpacity$>, OPACITY_MASK_THRESHOLD) : <$fetchedOpacity$>) : 1.0) * <$materialOpacity$>; } <@endfunc@> From 695e558851adbb7a12bae26a5ecc614e9cac1446 Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Mar 2016 16:36:47 -0700 Subject: [PATCH 06/39] Trying to clena up the problem? --- .../src/model-networking/ModelCache.cpp | 2 +- libraries/model/src/model/Material.cpp | 18 +++++++++++- libraries/model/src/model/Material.slh | 28 +++++++++---------- .../render-utils/src/MaterialTextures.slh | 4 +-- 4 files changed, 34 insertions(+), 18 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 7d5c6964e8..9c2725a919 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -151,7 +151,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } - if (material->useAlbedoMapOpacity && material->albedoTexture && material->albedoTexture->getGPUTexture()) { + if (/*material->useAlbedoMapOpacity && */ material->albedoTexture && material->albedoTexture->getGPUTexture()) { material->_material->setTextureMap(model::MaterialKey::ALBEDO_MAP, material->_material->getTextureMap(model::MaterialKey::ALBEDO_MAP)); // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 5f5c93eb61..eaabda8f07 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -92,7 +92,23 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur auto usage = textureMap->getTextureView()._texture->getUsage(); if (usage.isAlpha()) { // Texture has alpha, is nut just a mask or a true transparent channel - if (!usage.isAlphaMask()) { + if (usage.isAlphaMask()) { + _key.setOpacityMaskMap(true); + _key.setTranslucentMap(false); + } else { + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(true); + } + } + } + } + } else { + if (textureMap->isDefined()) { + if (textureMap->getTextureView().isValid()) { + auto usage = textureMap->getTextureView()._texture->getUsage(); + if (usage.isAlpha()) { + // Texture has alpha, is nut just a mask or a true transparent channel + if (usage.isAlphaMask()) { _key.setOpacityMaskMap(true); _key.setTranslucentMap(false); } else { diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index e8c9d3d6bc..a5b58e2aa0 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -39,21 +39,21 @@ float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); } int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); } -const int EMISSIVE_VAL_BIT = 0x00000001; -const int ALBEDO_VAL_BIT = 0x00000002; -const int METALLIC_VAL_BIT = 0x00000004; -const int GLOSSY_VAL_BIT = 0x00000008; -const int OPACITY_VAL_BIT = 0x00000010; +const int EMISSIVE_VAL_BIT = 0x00000001; +const int ALBEDO_VAL_BIT = 0x00000002; +const int METALLIC_VAL_BIT = 0x00000004; +const int GLOSSY_VAL_BIT = 0x00000008; +const int OPACITY_VAL_BIT = 0x00000010; -const int EMISSIVE_MAP_BIT = 0x00000020; -const int ALBEDO_MAP_BIT = 0x00000040; -const int OPACITY_MASK_MAP_BIT = 0x00000080; -const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000100; -const int METALLIC_MAP_BIT = 0x00000200; -const int ROUGHNESS_MAP_BIT = 0x00000400; -const int NORMAL_MAP_BIT = 0x00001000; -const int OCCLUSION_MAP_BIT = 0x00002000; -const int LIGHTMAP_MAP_BIT = 0x00004000; +const int EMISSIVE_MAP_BIT = 0x00000020; +const int ALBEDO_MAP_BIT = 0x00000040; +const int OPACITY_MASK_MAP_BIT = 0x00000080; +const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000100; +const int METALLIC_MAP_BIT = 0x00000200; +const int ROUGHNESS_MAP_BIT = 0x00000400; +const int NORMAL_MAP_BIT = 0x00000800; +const int OCCLUSION_MAP_BIT = 0x00001000; +const int LIGHTMAP_MAP_BIT = 0x00002000; <@endif@> diff --git a/libraries/render-utils/src/MaterialTextures.slh b/libraries/render-utils/src/MaterialTextures.slh index b25876af63..34bb7c429b 100644 --- a/libraries/render-utils/src/MaterialTextures.slh +++ b/libraries/render-utils/src/MaterialTextures.slh @@ -114,9 +114,9 @@ vec3 fetchLightmapMap(vec2 uv) { <@func evalMaterialOpacity(fetchedOpacity, materialOpacity, matKey, opacity)@> { - const float OPACITY_MASK_THRESHOLD = 0.95; + const float OPACITY_MASK_THRESHOLD = 0.5; <$opacity$> = (((<$matKey$> & (OPACITY_TRANSLUCENT_MAP_BIT | OPACITY_MASK_MAP_BIT)) != 0) ? - (((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(<$fetchedOpacity$>, OPACITY_MASK_THRESHOLD) : <$fetchedOpacity$>) : + (((<$matKey$> & OPACITY_MASK_MAP_BIT) != 0) ? step(OPACITY_MASK_THRESHOLD, <$fetchedOpacity$>) : <$fetchedOpacity$>) : 1.0) * <$materialOpacity$>; } <@endfunc@> From de374c0cacf6b342227e2b8e40a0ac096eeb4f1a Mon Sep 17 00:00:00 2001 From: samcake Date: Mon, 21 Mar 2016 17:51:57 -0700 Subject: [PATCH 07/39] Switching emissive and lightmap somewhere but not big issue --- .../model-networking/src/model-networking/ModelCache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 9c2725a919..2b142d95d5 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -213,10 +213,10 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u networkMaterial->setTextureMap(model::MaterialKey::EMISSIVE_MAP, emissiveMap); } else if (material->lightmapTextureName == name) { - material->emissiveTexture = textureCache->getTexture(url, LIGHTMAP_TEXTURE); + material->lightmapTexture = textureCache->getTexture(url, LIGHTMAP_TEXTURE); auto lightmapMap = model::TextureMapPointer(new model::TextureMap()); - lightmapMap->setTextureSource(material->emissiveTexture->_textureSource); + lightmapMap->setTextureSource(material->lightmapTexture->_textureSource); lightmapMap->setTextureTransform( oldTextureMaps[model::MaterialKey::LIGHTMAP_MAP]->getTextureTransform()); glm::vec2 oldOffsetScale = From d47e8eb9991091799da66281baab2c5f300892ec Mon Sep 17 00:00:00 2001 From: Thijs Wenker Date: Tue, 22 Mar 2016 17:39:57 +0100 Subject: [PATCH 08/39] Fix setting colors in ParticleExplorer without having the particle entity disappear. Handles Hex strings as well as color arrays. --- examples/particle_explorer/particleExplorer.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/particle_explorer/particleExplorer.js b/examples/particle_explorer/particleExplorer.js index 307e361ff1..4fd0978a84 100644 --- a/examples/particle_explorer/particleExplorer.js +++ b/examples/particle_explorer/particleExplorer.js @@ -198,6 +198,16 @@ function createColorPicker(key) { settings[key] = colorArray; var controller = gui.addColor(settings, key); controller.onChange(function(value) { + // Handle hex colors + if(_.isString(value) && value[0] === '#') { + const BASE_HEX = 16; + var colorRegExResult = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(value); + value = [ + parseInt(colorRegExResult[1], BASE_HEX), + parseInt(colorRegExResult[2], BASE_HEX), + parseInt(colorRegExResult[3], BASE_HEX) + ]; + } var obj = {}; obj[key] = convertColorArrayToObject(value); writeVec3ToInterface(obj); From 3c075532f8cd3670eb51766f49e1a690ed813e2c Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Mar 2016 15:14:01 -0700 Subject: [PATCH 09/39] Good to go for merge --- .../src/model-networking/ModelCache.cpp | 7 ++----- .../src/model-networking/ModelCache.h | 2 -- libraries/model/src/model/Material.cpp | 18 +----------------- libraries/model/src/model/Material.h | 7 ++++--- libraries/model/src/model/Material.slh | 8 ++++---- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 2b142d95d5..5eb961ef98 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -151,13 +151,11 @@ bool NetworkGeometry::isLoadedWithTextures() const { (material->lightmapTexture && !material->lightmapTexture->isLoaded())) { return false; } - if (/*material->useAlbedoMapOpacity && */ material->albedoTexture && material->albedoTexture->getGPUTexture()) { + if (material->albedoTexture && material->albedoTexture->getGPUTexture()) { + // Reassign the texture to make sure that itsalbedo alpha channel material key is detected correctly material->_material->setTextureMap(model::MaterialKey::ALBEDO_MAP, material->_material->getTextureMap(model::MaterialKey::ALBEDO_MAP)); - // Reset the materialKey transparentTexture key only, as it is albedoTexture-dependent const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); - // material->_material->setTransparentTexture(isTransparentTexture); - // FIXME: Materials with *some* transparent textures seem to give all *other* textures alphas of 0. _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; } } @@ -385,7 +383,6 @@ static NetworkMaterial* buildNetworkMaterial(NetworkGeometry* geometry, const FB if (!material.opacityTexture.filename.isEmpty()) { if (material.albedoTexture.filename == material.opacityTexture.filename) { // Best case scenario, just indicating that the albedo map contains transparency - networkMaterial->useAlbedoMapOpacity; albedoMap->setUseAlphaChannel(true); } else { // Opacity Map is different from the Abledo map, not supported diff --git a/libraries/model-networking/src/model-networking/ModelCache.h b/libraries/model-networking/src/model-networking/ModelCache.h index b172bb70b4..1c76a0b878 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.h +++ b/libraries/model-networking/src/model-networking/ModelCache.h @@ -199,8 +199,6 @@ public: QSharedPointer occlusionTexture; QString lightmapTextureName; QSharedPointer lightmapTexture; - bool useAlbedoMapOpacity{ false }; - }; diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index eaabda8f07..f1e6b8c2ef 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -91,23 +91,7 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur if (textureMap->getTextureView().isValid()) { auto usage = textureMap->getTextureView()._texture->getUsage(); if (usage.isAlpha()) { - // Texture has alpha, is nut just a mask or a true transparent channel - if (usage.isAlphaMask()) { - _key.setOpacityMaskMap(true); - _key.setTranslucentMap(false); - } else { - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(true); - } - } - } - } - } else { - if (textureMap->isDefined()) { - if (textureMap->getTextureView().isValid()) { - auto usage = textureMap->getTextureView()._texture->getUsage(); - if (usage.isAlpha()) { - // Texture has alpha, is nut just a mask or a true transparent channel + // Texture has alpha, is not just a mask or a true transparent channel if (usage.isAlphaMask()) { _key.setOpacityMaskMap(true); _key.setTranslucentMap(false); diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 2527c8e1e1..5a7b919994 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -32,11 +32,12 @@ public: METALLIC_VAL_BIT, GLOSSY_VAL_BIT, OPACITY_VAL_BIT, - - EMISSIVE_MAP_BIT, - ALBEDO_MAP_BIT, OPACITY_MASK_MAP_BIT, // OPacity Map and Opacity MASK map are mutually exclusive OPACITY_TRANSLUCENT_MAP_BIT, + + // THe map bits must be in the smae sequence as the enum names for the map channels + EMISSIVE_MAP_BIT, + ALBEDO_MAP_BIT, METALLIC_MAP_BIT, ROUGHNESS_MAP_BIT, NORMAL_MAP_BIT, diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index a5b58e2aa0..28f9769a8b 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -44,11 +44,11 @@ const int ALBEDO_VAL_BIT = 0x00000002; const int METALLIC_VAL_BIT = 0x00000004; const int GLOSSY_VAL_BIT = 0x00000008; const int OPACITY_VAL_BIT = 0x00000010; +const int OPACITY_MASK_MAP_BIT = 0x00000020; +const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000040; -const int EMISSIVE_MAP_BIT = 0x00000020; -const int ALBEDO_MAP_BIT = 0x00000040; -const int OPACITY_MASK_MAP_BIT = 0x00000080; -const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000100; +const int EMISSIVE_MAP_BIT = 0x00000080; +const int ALBEDO_MAP_BIT = 0x00000100; const int METALLIC_MAP_BIT = 0x00000200; const int ROUGHNESS_MAP_BIT = 0x00000400; const int NORMAL_MAP_BIT = 0x00000800; From 3274df9923a4c70b96262778cbfb8178c18ee138 Mon Sep 17 00:00:00 2001 From: samcake Date: Tue, 22 Mar 2016 16:18:51 -0700 Subject: [PATCH 10/39] Fixing the missing field for blender translucent map --- libraries/fbx/src/FBXReader.cpp | 5 +++-- libraries/fbx/src/FBXReader_Material.cpp | 8 ++++++-- libraries/model/src/model/Material.cpp | 6 +++++- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index b2ede33e01..c3364f90f8 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1098,8 +1098,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("tex_color_map")) { diffuseTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); - } else if (type.contains("transparentcolor")) { // it should be TransparentColor... - // THis is how Maya assign a texture that affect diffuse color AND transparency ? + } else if (type.contains("transparentcolor")) { // Maya way of passing TransparentMap + transparentTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); + } else if (type.contains("transparencyfactor")) { // Blender way of passing TransparentMap transparentTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); } else if (type.contains("bump")) { bumpTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1)); diff --git a/libraries/fbx/src/FBXReader_Material.cpp b/libraries/fbx/src/FBXReader_Material.cpp index fb272a1af9..11c6dad2f2 100644 --- a/libraries/fbx/src/FBXReader_Material.cpp +++ b/libraries/fbx/src/FBXReader_Material.cpp @@ -102,16 +102,20 @@ void FBXReader::consolidateFBXMaterials() { detectDifferentUVs = (diffuseTexture.texcoordSet != 0) || (!diffuseTexture.transform.isIdentity()); } - FBXTexture transparentTexture; QString transparentTextureID = transparentTextures.value(material.materialID); + // If PBS Material, systematically bind the albedo texture as transparency texture and check for the alpha channel + if (material.isPBSMaterial) { + transparentTextureID = diffuseTextureID; + } if (!transparentTextureID.isNull()) { transparentTexture = getTexture(transparentTextureID); - material.opacityTexture = transparentTexture; detectDifferentUVs |= (transparentTexture.texcoordSet != 0) || (!transparentTexture.transform.isIdentity()); } + + FBXTexture normalTexture; QString bumpTextureID = bumpTextures.value(material.materialID); QString normalTextureID = normalTextures.value(material.materialID); diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index f1e6b8c2ef..81bc9b40a6 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -84,8 +84,12 @@ void Material::setMetallic(float metallic) { void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { _key.setMapChannel(channel, (true)); - + if (channel == MaterialKey::ALBEDO_MAP) { + // clear the previous flags whatever they were: + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(false); + if (textureMap->useAlphaChannel()) { if (textureMap->isDefined()) { if (textureMap->getTextureView().isValid()) { From df187499ff1e0601fd9b82c8454527b2f0fe73f5 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Tue, 22 Mar 2016 19:19:52 -0700 Subject: [PATCH 11/39] MyAvatar: fix jitter in hands when moving Store hand controller positions within the avatar in sensor space, not world space. Before IK the sensorToWorld matrix is updated to reflect the world space motion of the character controller during physics. This ensures the IK hand targets move properly with the character. --- interface/src/Application.cpp | 10 ++++++---- interface/src/avatar/MyAvatar.cpp | 28 ++++++++++++++++++---------- interface/src/avatar/MyAvatar.h | 10 ++++++---- 3 files changed, 30 insertions(+), 18 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e88ea28dc..47d008aa69 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3228,7 +3228,9 @@ void Application::update(float deltaTime) { controller::Pose leftHandPose = userInputMapper->getPoseState(controller::Action::LEFT_HAND); controller::Pose rightHandPose = userInputMapper->getPoseState(controller::Action::RIGHT_HAND); auto myAvatarMatrix = createMatFromQuatAndPos(myAvatar->getOrientation(), myAvatar->getPosition()); - myAvatar->setHandControllerPosesInWorldFrame(leftHandPose.transform(myAvatarMatrix), rightHandPose.transform(myAvatarMatrix)); + auto worldToSensorMatrix = glm::inverse(myAvatar->getSensorToWorldMatrix()); + auto avatarToSensorMatrix = worldToSensorMatrix * myAvatarMatrix; + myAvatar->setHandControllerPosesInSensorFrame(leftHandPose.transform(avatarToSensorMatrix), rightHandPose.transform(avatarToSensorMatrix)); updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... updateDialogs(deltaTime); // update various stats dialogs if present @@ -3315,6 +3317,9 @@ void Application::update(float deltaTime) { qApp->updateMyAvatarLookAtPosition(); + // update sensorToWorldMatrix for camera and hand controllers + myAvatar->updateSensorToWorldMatrix(); + avatarManager->updateMyAvatar(deltaTime); } @@ -3374,9 +3379,6 @@ void Application::update(float deltaTime) { QMetaObject::invokeMethod(DependencyManager::get().data(), "sendDownstreamAudioStatsPacket", Qt::QueuedConnection); } } - - // update sensorToWorldMatrix for rendering camera. - myAvatar->updateSensorToWorldMatrix(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4405204b47..8f11c635e9 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -418,7 +418,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) { _hmdSensorFacing = getFacingDir2D(_hmdSensorOrientation); } -// best called at end of main loop, just before rendering. +// best called at end of main loop, after physics. // update sensor to world matrix from current body position and hmd sensor. // This is so the correct camera can be used for rendering. void MyAvatar::updateSensorToWorldMatrix() { @@ -1087,24 +1087,32 @@ static controller::Pose applyLowVelocityFilter(const controller::Pose& oldPose, return finalPose; } -void MyAvatar::setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right) { +void MyAvatar::setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) { if (controller::InputDevice::getLowVelocityFilter()) { - auto oldLeftPose = getLeftHandControllerPoseInWorldFrame(); - auto oldRightPose = getRightHandControllerPoseInWorldFrame(); - _leftHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldLeftPose, left)); - _rightHandControllerPoseInWorldFrameCache.set(applyLowVelocityFilter(oldRightPose, right)); + auto oldLeftPose = getLeftHandControllerPoseInSensorFrame(); + auto oldRightPose = getRightHandControllerPoseInSensorFrame(); + _leftHandControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldLeftPose, left)); + _rightHandControllerPoseInSensorFrameCache.set(applyLowVelocityFilter(oldRightPose, right)); } else { - _leftHandControllerPoseInWorldFrameCache.set(left); - _rightHandControllerPoseInWorldFrameCache.set(right); + _leftHandControllerPoseInSensorFrameCache.set(left); + _rightHandControllerPoseInSensorFrameCache.set(right); } } +controller::Pose MyAvatar::getLeftHandControllerPoseInSensorFrame() const { + return _leftHandControllerPoseInSensorFrameCache.get(); +} + +controller::Pose MyAvatar::getRightHandControllerPoseInSensorFrame() const { + return _rightHandControllerPoseInSensorFrameCache.get(); +} + controller::Pose MyAvatar::getLeftHandControllerPoseInWorldFrame() const { - return _leftHandControllerPoseInWorldFrameCache.get(); + return _leftHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix()); } controller::Pose MyAvatar::getRightHandControllerPoseInWorldFrame() const { - return _rightHandControllerPoseInWorldFrameCache.get(); + return _rightHandControllerPoseInSensorFrameCache.get().transform(getSensorToWorldMatrix()); } controller::Pose MyAvatar::getLeftHandControllerPoseInAvatarFrame() const { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 3554d9b8bc..92bf9e7614 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -247,7 +247,9 @@ public: virtual void rebuildCollisionShape() override; - void setHandControllerPosesInWorldFrame(const controller::Pose& left, const controller::Pose& right); + void setHandControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right); + controller::Pose getLeftHandControllerPoseInSensorFrame() const; + controller::Pose getRightHandControllerPoseInSensorFrame() const; controller::Pose getLeftHandControllerPoseInWorldFrame() const; controller::Pose getRightHandControllerPoseInWorldFrame() const; controller::Pose getLeftHandControllerPoseInAvatarFrame() const; @@ -451,9 +453,9 @@ private: bool _hoverReferenceCameraFacingIsCaptured { false }; glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space - // These are stored in WORLD frame - ThreadSafeValueCache _leftHandControllerPoseInWorldFrameCache { controller::Pose() }; - ThreadSafeValueCache _rightHandControllerPoseInWorldFrameCache { controller::Pose() }; + // These are stored in SENSOR frame + ThreadSafeValueCache _leftHandControllerPoseInSensorFrameCache { controller::Pose() }; + ThreadSafeValueCache _rightHandControllerPoseInSensorFrameCache { controller::Pose() }; float AVATAR_MOVEMENT_ENERGY_CONSTANT { 0.001f }; float AUDIO_ENERGY_CONSTANT { 0.000001f }; From 472dd076252b32b86a6385a250439f815b7bfdd9 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Tue, 22 Mar 2016 22:39:22 -0700 Subject: [PATCH 12/39] airship from hack project --- examples/airship/airship.js | 303 ++++++++++++++++++++++++++++++++ examples/airship/makeAirship.js | 60 +++++++ 2 files changed, 363 insertions(+) create mode 100644 examples/airship/airship.js create mode 100644 examples/airship/makeAirship.js diff --git a/examples/airship/airship.js b/examples/airship/airship.js new file mode 100644 index 0000000000..9b6ae45093 --- /dev/null +++ b/examples/airship/airship.js @@ -0,0 +1,303 @@ +// +// airship.js +// +// Animates a pirate airship that chases people and shoots cannonballs at them +// +// Created by Philip Rosedale on March 7, 2016 +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function () { + var entityID, + minimumDelay = 100, // milliseconds + distanceScale = 2.0, // distance at which 100% chance of hopping + timeScale = 300.0, // crash + hopStrength = 0.4, // meters / second + spotlight = null, + wantDebug = false, + timeoutID = undefined, + bullet = null, + particles = null, + nearbyAvatars = 0, + nearbyAvatarsInRange = 0, + averageAvatarLocation = { x: 0, y: 0, z: 0 }, + properties, + lightTimer = 0, + lightTimeoutID = undefined, + audioInjector = null + + var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; + var cannonSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "philip/cannonShot.wav"); + var explosionSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "philip/explosion.wav"); + + var NO_SHOOT_COLOR = { red: 100, green: 100, blue: 100 }; + + var MAX_TARGET_RANGE = 200; + + function printDebug(message) { + if (wantDebug) { + print(message); + } + } + + var LIGHT_UPDATE_INTERVAL = 50; + var LIGHT_LIFETIME = 700; + + function randomVector(size) { + return { x: (Math.random() - 0.5) * size, + y: (Math.random() - 0.5) * size, + z: (Math.random() - 0.5) * size }; + } + + function makeLight(parent, position, colorDivisor) { + // Create a flickering light somewhere for a while + if (spotlight !== null) { + // light still exists, do nothing + printDebug("light still there"); + return; + } + printDebug("making light"); + + var colorIndex = 180 + Math.random() * 50; + + spotlight = Entities.addEntity({ + type: "Light", + name: "Test Light", + intensity: 50.0, + falloffRadius: 20.0, + dimensions: { + x: 150, + y: 150, + z: 150 + }, + position: position, + parentID: parent, + color: { + red: colorIndex, + green: colorIndex / colorDivisor, + blue: 0 + }, + lifetime: LIGHT_LIFETIME * 2 + }); + + lightTimer = 0; + lightTimeoutID = Script.setTimeout(updateLight, LIGHT_UPDATE_INTERVAL); + + }; + + function updateLight() { + lightTimer += LIGHT_UPDATE_INTERVAL; + if ((spotlight !== null) && (lightTimer > LIGHT_LIFETIME)) { + printDebug("deleting light!"); + Entities.deleteEntity(spotlight); + spotlight = null; + } else { + Entities.editEntity(spotlight, { + intensity: 5 + Math.random() * 50, + falloffRadius: 5 + Math.random() * 10 + }); + lightTimeoutID = Script.setTimeout(updateLight, LIGHT_UPDATE_INTERVAL); + } + } + + function move() { + + var HOVER_DISTANCE = 30.0; + var RUN_TOWARD_STRENGTH = 0.002; + var VELOCITY_FOLLOW_RATE = 0.01; + + var range = Vec3.distance(properties.position, averageAvatarLocation); + var impulse = { x: 0, y: 0, z: 0 }; + + // move in the XZ plane + var away = Vec3.subtract(properties.position, averageAvatarLocation); + away.y = 0.0; + + if (range > HOVER_DISTANCE) { + impulse = Vec3.multiply(-RUN_TOWARD_STRENGTH, Vec3.normalize(away)); + } + + var rotation = Quat.rotationBetween(Vec3.UNIT_NEG_Z, properties.velocity); + Entities.editEntity(entityID, {velocity: Vec3.sum(properties.velocity, impulse), rotation: Quat.mix(properties.rotation, rotation, VELOCITY_FOLLOW_RATE)}); + } + + + function countAvatars() { + var workQueue = AvatarList.getAvatarIdentifiers(); + var averageLocation = {x: 0, y: 0, z: 0}; + var summed = 0; + var inRange = 0; + for (var i = 0; i < workQueue.length; i++) { + var avatar = AvatarList.getAvatar(workQueue[i]), avatarPosition = avatar && avatar.position; + if (avatarPosition) { + averageLocation = Vec3.sum(averageLocation, avatarPosition); + summed++; + if (Vec3.distance(avatarPosition, properties.position) < MAX_TARGET_RANGE) { + inRange++; + } + } + } + if (summed > 0) { + averageLocation = Vec3.multiply(1 / summed, averageLocation); + } + nearbyAvatars = summed; + nearbyAvatarsInRange = inRange; + averageAvatarLocation = averageLocation; + + //printDebug(" Avatars: " + summed + "in range: " + nearbyAvatarsInRange); + //Vec3.print(" location: ", averageAvatarLocation); + + return; + } + + function shoot() { + if (bullet !== null) { + return; + } + if (Vec3.distance(MyAvatar.position, properties.position) > MAX_TARGET_RANGE) { + return; + } + + var SPEED = 7.5; + var GRAVITY = -2.0; + var DIAMETER = 0.5; + var direction = Vec3.subtract(MyAvatar.position, properties.position); + var range = Vec3.distance(MyAvatar.position, properties.position); + var timeOfFlight = range / SPEED; + + var fall = 0.5 * -GRAVITY * (timeOfFlight * timeOfFlight); + + var velocity = Vec3.multiply(SPEED, Vec3.normalize(direction)); + velocity.y += 0.5 * fall / timeOfFlight * 2.0; + + var DISTANCE_TO_DECK = 3; + var bulletStart = properties.position; + bulletStart.y -= DISTANCE_TO_DECK; + + makeLight(entityID, Vec3.sum(properties.position, randomVector(10.0)), 2); + + bullet = Entities.addEntity({ + type: "Sphere", + name: "cannonball", + position: properties.position, + dimensions: { x: DIAMETER, y: DIAMETER, z: DIAMETER }, + color: { red: 10, green: 10, blue: 10 }, + velocity: velocity, + damping: 0.01, + dynamic: true, + ignoreForCollisions: true, + gravity: { x: 0, y: GRAVITY, z: 0 }, + lifetime: timeOfFlight * 2 + }); + + Audio.playSound(cannonSound, { + position: Vec3.sum(MyAvatar.position, velocity), + volume: 1.0 + }); + makeParticles(properties.position, bullet, timeOfFlight * 2); + Script.setTimeout(explode, timeOfFlight * 1000); + + + } + + function explode() { + var properties = Entities.getEntityProperties(bullet); + var direction = Vec3.normalize(Vec3.subtract(MyAvatar.position, properties.position)); + makeLight(null, properties.position, 10); + Audio.playSound(explosionSound, { position: Vec3.sum(MyAvatar.position, direction), volume: 1.0 }); + bullet = null; + } + + + function maybe() { // every user checks their distance and tries to claim if close enough. + var PROBABILITY_OF_SHOOT = 0.015; + properties = Entities.getEntityProperties(entityID); + countAvatars(); + + if (nearbyAvatars && (Math.random() < 1 / nearbyAvatars)) { + move(); + } + + if (nearbyAvatarsInRange && (Math.random() < PROBABILITY_OF_SHOOT / nearbyAvatarsInRange)) { + shoot(); + } + + var timeToNextCheck = 33; + timeoutID = Script.setTimeout(maybe, timeToNextCheck); + } + + this.preload = function (givenEntityID) { + printDebug("preload airship v1..."); + + entityID = givenEntityID; + properties = Entities.getEntityProperties(entityID); + timeoutID = Script.setTimeout(maybe, minimumDelay); + }; + + this.unload = function () { + printDebug("unload airship..."); + if (timeoutID !== undefined) { + Script.clearTimeout(timeoutID); + } + if (lightTimeoutID !== undefined) { + Script.clearTimeout(lightTimeoutID); + } + if (spotlight !== null) { + Entities.deleteEntity(spotlight); + } + }; + + function makeParticles(position, parent, lifespan) { + particles = Entities.addEntity({ + type: 'ParticleEffect', + position: position, + parentID: parent, + color: { + red: 70, + green: 70, + blue: 70 + }, + isEmitting: 1, + maxParticles: 1000, + lifetime: lifespan, + lifespan: lifespan / 3, + emitRate: 80, + emitSpeed: 0, + speedSpread: 1.0, + emitRadiusStart: 1, + polarStart: -Math.PI/8, + polarFinish: Math.PI/8, + azimuthStart: -Math.PI/4, + azimuthFinish: Math.PI/4, + emitAcceleration: { x: 0, y: 0, z: 0 }, + particleRadius: 0.25, + radiusSpread: 0.1, + radiusStart: 0.3, + radiusFinish: 0.15, + colorSpread: { + red: 100, + green: 100, + blue: 0 + }, + colorStart: { + red: 125, + green: 125, + blue: 125 + }, + colorFinish: { + red: 10, + green: 10, + blue: 10 + }, + alpha: 0.5, + alphaSpread: 0, + alphaStart: 1, + alphaFinish: 0, + emitterShouldTrail: true, + textures: 'https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png' + }); + } +}) diff --git a/examples/airship/makeAirship.js b/examples/airship/makeAirship.js new file mode 100644 index 0000000000..92fff090ee --- /dev/null +++ b/examples/airship/makeAirship.js @@ -0,0 +1,60 @@ +// makeAirship.js +// +// // Created by Philip Rosedale on March 7, 2016 +// Copyright 2016 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 +// +// A firefly which is animated by passerbys. It's physical, no gravity, periodic forces applied. +// If a firefly is found to + +var SIZE = 0.2; +var TYPE = "Model"; // Right now this can be "Box" or "Model" or "Sphere" + +var MODEL_URL = "https://s3.amazonaws.com/hifi-public/philip/airship_compact.fbx" + +var MODEL_DIMENSION = { x: 19.257, y: 24.094, z: 40.3122 }; +//var ENTITY_URL = "https://s3.amazonaws.com/hifi-public/scripts/airship/airship.js?"+Math.random(); +var ENTITY_URL = "file:///c:/users/dev/philip/examples/airship/airship.js?"+Math.random(); + +var LIFETIME = 3600 * 48; + +var GRAVITY = { x: 0, y: 0, z: 0 }; +var DAMPING = 0.05; +var ANGULAR_DAMPING = 0.01; + +var collidable = true; +var gravity = true; + +var HOW_FAR_IN_FRONT_OF_ME = 30; +var HOW_FAR_ABOVE_ME = 15; + +var leaveBehind = true; + +var shipLocation = Vec3.sum(MyAvatar.position, Vec3.multiply(HOW_FAR_IN_FRONT_OF_ME, Quat.getFront(Camera.orientation))); +shipLocation.y += HOW_FAR_ABOVE_ME; + + +var airship = Entities.addEntity({ + type: TYPE, + modelURL: MODEL_URL, + name: "airship", + position: shipLocation, + dimensions: (TYPE == "Model") ? MODEL_DIMENSION : { x: SIZE, y: SIZE, z: SIZE }, + damping: DAMPING, + angularDamping: ANGULAR_DAMPING, + gravity: (gravity ? GRAVITY : { x: 0, y: 0, z: 0}), + dynamic: collidable, + lifetime: LIFETIME, + animation: {url: MODEL_URL, running: true, currentFrame: 0, loop: true}, + script: ENTITY_URL + }); + +function scriptEnding() { + if (!leaveBehind) { + Entities.deleteEntity(airship); + } +} + +Script.scriptEnding.connect(scriptEnding); \ No newline at end of file From 7e658896e63a1b7e8728a719d41e5890a46a2397 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Tue, 22 Mar 2016 22:39:55 -0700 Subject: [PATCH 13/39] update header --- examples/airship/makeAirship.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/airship/makeAirship.js b/examples/airship/makeAirship.js index 92fff090ee..9c6a3348b1 100644 --- a/examples/airship/makeAirship.js +++ b/examples/airship/makeAirship.js @@ -6,8 +6,7 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -// A firefly which is animated by passerbys. It's physical, no gravity, periodic forces applied. -// If a firefly is found to + var SIZE = 0.2; var TYPE = "Model"; // Right now this can be "Box" or "Model" or "Sphere" From 84dc15aff62408bff63543f132282dbcc6426e51 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Wed, 23 Mar 2016 12:06:52 -0700 Subject: [PATCH 14/39] Fix potential deadlock in QML --- libraries/gl/src/gl/OffscreenQmlSurface.cpp | 34 +++++++++++++++------ libraries/shared/src/Finally.h | 4 +++ 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/libraries/gl/src/gl/OffscreenQmlSurface.cpp b/libraries/gl/src/gl/OffscreenQmlSurface.cpp index d3699b54e6..e224adad07 100644 --- a/libraries/gl/src/gl/OffscreenQmlSurface.cpp +++ b/libraries/gl/src/gl/OffscreenQmlSurface.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include "OffscreenGLCanvas.h" #include "GLEscrow.h" @@ -84,6 +85,7 @@ protected: Queue _queue; QMutex _mutex; QWaitCondition _waitCondition; + std::atomic _rendering { false }; private: // Event-driven methods @@ -271,15 +273,25 @@ void OffscreenQmlRenderThread::resize() { } void OffscreenQmlRenderThread::render() { - if (_surface->_paused) { + // Ensure we always release the main thread + Finally releaseMainThread([this] { _waitCondition.wakeOne(); + }); + + if (_surface->_paused) { return; } - QMutexLocker locker(&_mutex); - _renderControl->sync(); - _waitCondition.wakeOne(); - locker.unlock(); + _rendering = true; + Finally unmarkRenderingFlag([this] { + _rendering = false; + }); + + { + QMutexLocker locker(&_mutex); + _renderControl->sync(); + releaseMainThread.trigger(); + } using namespace oglplus; @@ -292,6 +304,7 @@ void OffscreenQmlRenderThread::render() { _fbo->AttachTexture(Framebuffer::Target::Draw, FramebufferAttachment::Color, *texture, 0); _fbo->Complete(Framebuffer::Target::Draw); { + PROFILE_RANGE("qml_render->rendercontrol") _renderControl->render(); // FIXME The web browsers seem to be leaving GL in an error state. // Need a debug context with sync logging to figure out why. @@ -380,8 +393,6 @@ void OffscreenQmlSurface::resize(const QSize& newSize_) { std::max(static_cast(scale * newSize.height()), 10)); } - - QSize currentSize = _renderer->_quickWindow->geometry().size(); if (newSize == currentSize) { return; @@ -492,7 +503,12 @@ QObject* OffscreenQmlSurface::finishQmlLoad(std::functionallowNewFrame(_maxFps)) { + // If we're + // a) not set up + // b) already rendering a frame + // c) rendering too fast + // then skip this + if (!_renderer || _renderer->_rendering || !_renderer->allowNewFrame(_maxFps)) { return; } @@ -502,11 +518,11 @@ void OffscreenQmlSurface::updateQuick() { } if (_render) { + PROFILE_RANGE(__FUNCTION__); // Lock the GUI size while syncing QMutexLocker locker(&(_renderer->_mutex)); _renderer->_queue.add(RENDER); _renderer->_waitCondition.wait(&(_renderer->_mutex)); - _render = false; } diff --git a/libraries/shared/src/Finally.h b/libraries/shared/src/Finally.h index 59e8be0228..9070d49647 100644 --- a/libraries/shared/src/Finally.h +++ b/libraries/shared/src/Finally.h @@ -20,6 +20,10 @@ public: template Finally(F f) : _f(f) {} ~Finally() { _f(); } + void trigger() { + _f(); + _f = [] {}; + } private: std::function _f; }; From 17aa2845a8d8f365002ddb7c419cce7bd2739df6 Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 15 Mar 2016 18:44:38 -0700 Subject: [PATCH 15/39] Add finished signal to Resource loading --- libraries/networking/src/ResourceCache.cpp | 1 + libraries/networking/src/ResourceCache.h | 3 +++ 2 files changed, 4 insertions(+) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 295af8c5ee..77ced1619c 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -380,6 +380,7 @@ void Resource::finishedLoading(bool success) { _failedToLoad = true; } _loadPriorities.clear(); + emit finished(success); } void Resource::reinsert() { diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ed938f6cf4..b24f5bc0b4 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -201,6 +201,9 @@ signals: /// This can be used instead of downloadFinished to access data before it is processed. void loaded(const QByteArray& request); + /// Fired when the resource has finished loading. + void finished(bool success); + /// Fired when the resource failed to load. void failed(QNetworkReply::NetworkError error); From 8b1a78bac0cfb2f3ae6d63f86b9a3d7844e740bd Mon Sep 17 00:00:00 2001 From: Zach Pomerantz Date: Tue, 15 Mar 2016 12:49:19 -0700 Subject: [PATCH 16/39] Restrict Resource reinsertion --- libraries/networking/src/ResourceCache.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index ed938f6cf4..2589819102 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -224,9 +224,6 @@ protected: /// This should be called by subclasses that override downloadFinished to mark the end of processing. Q_INVOKABLE void finishedLoading(bool success); - /// Reinserts this resource into the cache. - virtual void reinsert(); - QUrl _url; QUrl _activeUrl; bool _startedLoading = false; @@ -246,6 +243,7 @@ private: void makeRequest(); void retry(); + void reinsert(); friend class ResourceCache; From fdd7bb9f58a6cb5165e57799d084428f4cabda2a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Mar 2016 13:18:46 -0700 Subject: [PATCH 17/39] Update readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a2eb058ae6..48e0de03af 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ like to get paid for your work, make sure you report the bug via a job on [Worklist.net](https://worklist.net). We're hiring! We're looking for skilled developers; -send your resume to hiring@highfidelity.io +send your resume to hiring@highfidelity.com ##### Chat with us Come chat with us in [our Gitter](http://gitter.im/highfidelity/hifi) if you have any questions or just want to say hi! Documentation ========= -Documentation is available at [docs.highfidelity.io](http://docs.highfidelity.io), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). +Documentation is available at [docs.highfidelity.com](http://docs.highfidelity.com), if something is missing, please suggest it via a new job on Worklist (add to the hifi-docs project). Build Instructions ========= From 34fb06a7bd43ba12aba32ef65470cb6b47ea0087 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Mar 2016 13:52:47 -0700 Subject: [PATCH 18/39] changes to attachments dialog from contractor --- .../resources/qml/controls-uit/ComboBox.qml | 24 +++++ .../resources/qml/controls-uit/SpinBox.qml | 23 ++++ .../qml/hifi/dialogs/AttachmentsDialog.qml | 20 ++-- .../hifi/dialogs/attachments/Attachment.qml | 100 +++++++++--------- 4 files changed, 109 insertions(+), 58 deletions(-) mode change 100644 => 100755 interface/resources/qml/controls-uit/ComboBox.qml mode change 100644 => 100755 interface/resources/qml/controls-uit/SpinBox.qml mode change 100644 => 100755 interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml mode change 100644 => 100755 interface/resources/qml/hifi/dialogs/attachments/Attachment.qml diff --git a/interface/resources/qml/controls-uit/ComboBox.qml b/interface/resources/qml/controls-uit/ComboBox.qml old mode 100644 new mode 100755 index 888e8ccbc1..d25a8c5940 --- a/interface/resources/qml/controls-uit/ComboBox.qml +++ b/interface/resources/qml/controls-uit/ComboBox.qml @@ -162,6 +162,30 @@ FocusScope { height: 480 width: root.width + 4 + style: ScrollViewStyle { + decrementControl: Item { + visible: false + } + incrementControl: Item { + visible: false + } + scrollBarBackground: Rectangle{ + implicitWidth: 14 + color: hifi.colors.baseGray + } + + handle: + Rectangle { + implicitWidth: 8 + anchors.left: parent.left + anchors.leftMargin: 3 + anchors.top: parent.top + anchors.bottom: parent.bottom + radius: 3 + color: hifi.colors.lightGrayText + } + } + ListView { id: listView height: textField.height * count * 1.4 diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml old mode 100644 new mode 100755 index 5dac1710f0..be6dcdc7ee --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -91,4 +91,27 @@ SpinBox { color: spinBox.colorLabelInside visible: spinBox.labelInside != "" } + + MouseArea { + anchors.fill: parent + propagateComposedEvents: true + onWheel: { + if(spinBox.focus) + wheel.accepted = false + else + wheel.accepted = true + } + onPressed: { + mouse.accepted = false + } + onReleased: { + mouse.accepted = false + } + onClicked: { + mouse.accepted = false + } + onDoubleClicked: { + mouse.accepted = false + } + } } diff --git a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml old mode 100644 new mode 100755 index f82ef8d86c..8e5b377521 --- a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml @@ -4,13 +4,9 @@ import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 import QtQuick.Controls.Styles 1.4 -//import "../../windows" - - import "../../styles-uit" import "../../controls-uit" as HifiControls import "../../windows-uit" - import "attachments" Window { @@ -43,6 +39,7 @@ Window { listView.model.append({}); } } + Column { width: pane.contentWidth @@ -55,7 +52,7 @@ Window { Rectangle { id: attachmentsBackground anchors { left: parent.left; right: parent.right; top: parent.top; bottom: newAttachmentButton.top; margins: 8 } - color: hifi.colors.lightGrayText + color: hifi.colors.baseGrayShadow radius: 4 ScrollView{ @@ -72,8 +69,10 @@ Window { scrollBarBackground: Rectangle{ implicitWidth: 14 color: hifi.colors.baseGray + anchors.left: attachmentDelegate.right + anchors.leftMargin: 5 + radius: 3 } - handle: Rectangle { implicitWidth: 8 @@ -90,8 +89,9 @@ Window { id: listView model: ListModel {} delegate: Item { + id: attachmentDelegate implicitHeight: attachmentView.height + 8; - implicitWidth: attachmentView.width; + implicitWidth: attachmentView.width Attachment { id: attachmentView width: scrollView.width @@ -113,7 +113,7 @@ Window { anchors { left: parent.left; right: parent.right; bottom: buttonRow.top; margins: 8 } text: "New Attachment" color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark + colorScheme: hifi.colorSchemes.dark onClicked: { var template = { modelUrl: "", @@ -136,12 +136,12 @@ Window { HifiControls.Button { action: cancelAction color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark + colorScheme: hifi.colorSchemes.dark } HifiControls.Button { action: okAction color: hifi.buttons.black - colorScheme: hifi.colorSchemes.dark + colorScheme: hifi.colorSchemes.dark } } diff --git a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml old mode 100644 new mode 100755 index c88e991ed3..0db6bb4875 --- a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml @@ -4,11 +4,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.2 as OriginalDialogs import Qt.labs.settings 1.0 -//import "../../../windows" -//import "../../../controls" as VrControls import "." import ".." - import "../../../styles-uit" import "../../../controls-uit" as HifiControls import "../../../windows-uit" @@ -33,13 +30,13 @@ Item { Column { y: 8 id: column - anchors { left: parent.left; right: parent.right; margins: 8 } + anchors { left: parent.left; right: parent.right; margins: 20 } spacing: 8 Item { - height: modelChooserButton.height + urlLabel.height + height: modelChooserButton.height + urlLabel.height + 4 anchors { left: parent.left; right: parent.right;} - Text { id: urlLabel; color: hifi.colors.lightGrayText; text: "Model URL:"; width: 80; anchors.top: parent.top;} + HifiControls.Label { id: urlLabel; color: hifi.colors.lightGrayText; text: "Model URL:"; anchors.top: parent.top;} HifiControls.TextField { id: modelUrl; height: jointChooser.height; @@ -74,11 +71,10 @@ Item { } Item { - height: jointChooser.height + jointLabel.height + height: jointChooser.height + jointLabel.height + 4 anchors { left: parent.left; right: parent.right; } - Text { + HifiControls.Label { id: jointLabel; - width: 80; text: "Joint:"; color: hifi.colors.lightGrayText; anchors.top: parent.top @@ -99,9 +95,9 @@ Item { } Item { - height: translation.height + translationLabel.height + height: translation.height + translationLabel.height + 4 anchors { left: parent.left; right: parent.right; } - Text { id: translationLabel; width: 80; color: hifi.colors.lightGrayText; text: "Translation:"; anchors.top: parent.top; } + HifiControls.Label { id: translationLabel; color: hifi.colors.lightGrayText; text: "Translation:"; anchors.top: parent.top; } Translation { id: translation; anchors { left: parent.left; right: parent.right; bottom: parent.bottom} @@ -116,9 +112,9 @@ Item { } Item { - height: rotation.height + rotationLabel.height + height: rotation.height + rotationLabel.height + 4 anchors { left: parent.left; right: parent.right; } - Text { id: rotationLabel; width: 80; color: hifi.colors.lightGrayText; text: "Rotation:"; anchors.top: parent.top; } + HifiControls.Label { id: rotationLabel; color: hifi.colors.lightGrayText; text: "Rotation:"; anchors.top: parent.top; } Rotation { id: rotation; anchors { left: parent.left; right: parent.right; bottom: parent.bottom; } @@ -133,45 +129,53 @@ Item { } Item { - height: scaleSpinner.height + scaleLabel.height - anchors { left: parent.left; right: parent.right; } - Text { id: scaleLabel; width: 80; color: hifi.colors.lightGrayText; text: "Scale:"; anchors.top: parent.top; } - HifiControls.SpinBox { - id: scaleSpinner; - anchors { left: parent.left; right: parent.right; bottom: parent.bottom; } - decimals: 1; - minimumValue: 0.1 - maximumValue: 10 - stepSize: 0.1; - value: attachment ? attachment.scale : 1.0 - colorScheme: hifi.colorSchemes.dark - onValueChanged: { - if (completed && attachment && attachment.scale !== value) { - attachment.scale = value; - updateAttachment(); + height: scaleItem.height + anchors {left: parent.left; right: parent.right;} + + Item { + id: scaleItem + height: scaleSpinner.height + scaleLabel.height + 4 + width: parent.width - isSoftItem.width + anchors { left: isSoftItem.right; right: parent.right; } + HifiControls.Label { id: scaleLabel; color: hifi.colors.lightGrayText; text: "Scale:"; anchors.top: parent.top; } + HifiControls.SpinBox { + id: scaleSpinner; + anchors { left: parent.left; right: parent.right; bottom: parent.bottom; } + decimals: 1; + minimumValue: 0.1 + maximumValue: 10 + stepSize: 0.1; + value: attachment ? attachment.scale : 1.0 + colorScheme: hifi.colorSchemes.dark + onValueChanged: { + if (completed && attachment && attachment.scale !== value) { + attachment.scale = value; + updateAttachment(); + } + } + } + } + + Item { + id: isSoftItem + height: soft.height + width: parent.width * 0.2 + anchors { left: parent.left; bottom: parent.bottom } + HifiControls.Label { id: softLabel; color: hifi.colors.lightGrayText; text: "Is soft"; anchors.left: soft.right; anchors.leftMargin: 8; } + HifiControls.CheckBox { + id: soft; + anchors { left: parent.left; bottom: parent.bottom;} + checked: attachment ? attachment.soft : false + colorScheme: hifi.colorSchemes.dark + onCheckedChanged: { + if (completed && attachment && attachment.soft !== checked) { + attachment.soft = checked; + updateAttachment(); + } } } } } - - Item { - height: soft.height - anchors { left: parent.left; right: parent.right; } - Text { id: softLabel; width: 80; color: hifi.colors.lightGrayText; text: "Is soft"; anchors.left: soft.right; anchors.leftMargin: 8; } - HifiControls.CheckBox { - id: soft; - anchors { left: parent.left; bottom: parent.bottom;} - checked: attachment ? attachment.soft : false - colorScheme: hifi.colorSchemes.dark - onCheckedChanged: { - if (completed && attachment && attachment.soft !== checked) { - attachment.soft = checked; - updateAttachment(); - } - } - } - } - HifiControls.Button { color: hifi.buttons.black colorScheme: hifi.colorSchemes.dark From a52ac3cc506ead268e372f5bdd3f29c9bfe40bc4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Mar 2016 11:41:32 -0700 Subject: [PATCH 19/39] remove excess whitespace --- libraries/shared/src/ShapeInfo.h | 2 +- tests/physics/src/MeshMassPropertiesTests.cpp | 20 +++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index a3fbe55f36..79390b6680 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -63,7 +63,7 @@ public: void appendToPoints (const QVector& newPoints) { _points << newPoints; } float computeVolume() const; - + /// Returns whether point is inside the shape /// For compound shapes it will only return whether it is inside the bounding box bool contains(const glm::vec3& point) const; diff --git a/tests/physics/src/MeshMassPropertiesTests.cpp b/tests/physics/src/MeshMassPropertiesTests.cpp index 825721641f..0b22ea1223 100644 --- a/tests/physics/src/MeshMassPropertiesTests.cpp +++ b/tests/physics/src/MeshMassPropertiesTests.cpp @@ -33,7 +33,7 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { // verity we can compute the inertia tensor of a box in two different ways: // (a) as one box // (b) as a combination of two partial boxes. - + btScalar bigBoxX = 7.0f; btScalar bigBoxY = 9.0f; btScalar bigBoxZ = 11.0f; @@ -62,9 +62,9 @@ void MeshMassPropertiesTests::testParallelAxisTheorem() { } void MeshMassPropertiesTests::testTetrahedron(){ - // given the four vertices of a tetrahedron verify the analytic formula for inertia + // given the four vertices of a tetrahedron verify the analytic formula for inertia // agrees with expected results - + // these numbers from the Tonon paper: btVector3 points[4]; points[0] = btVector3(8.33220f, -11.86875f, 0.93355f); @@ -102,14 +102,14 @@ void MeshMassPropertiesTests::testTetrahedron(){ } btMatrix3x3 inertia; computeTetrahedronInertia(volume, points, inertia); - + QCOMPARE_WITH_ABS_ERROR(volume, expectedVolume, acceptableRelativeError * volume); - + QCOMPARE_WITH_RELATIVE_ERROR(inertia, expectedInertia, acceptableRelativeError); } void MeshMassPropertiesTests::testOpenTetrahedonMesh() { - // given the simplest possible mesh (open, with one triangle) + // given the simplest possible mesh (open, with one triangle) // verify MeshMassProperties computes the right nubers // these numbers from the Tonon paper: @@ -155,7 +155,7 @@ void MeshMassPropertiesTests::testOpenTetrahedonMesh() { void MeshMassPropertiesTests::testClosedTetrahedronMesh() { // given a tetrahedron as a closed mesh of four tiangles // verify MeshMassProperties computes the right nubers - + // these numbers from the Tonon paper: VectorOfPoints points; points.push_back(btVector3(8.33220f, -11.86875f, 0.93355f)); @@ -186,7 +186,7 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() { // compute mass properties MeshMassProperties mesh(points, triangles); - + // verify QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); @@ -210,7 +210,7 @@ void MeshMassPropertiesTests::testClosedTetrahedronMesh() { void MeshMassPropertiesTests::testBoxAsMesh() { // verify that a mesh box produces the same mass properties as the analytic box. - + // build a box: // / // y @@ -265,7 +265,7 @@ void MeshMassPropertiesTests::testBoxAsMesh() { MeshMassProperties mesh(points, triangles); // verify - + QCOMPARE_WITH_ABS_ERROR(mesh._volume, expectedVolume, acceptableRelativeError * expectedVolume); QCOMPARE_WITH_ABS_ERROR(mesh._centerOfMass, expectedCenterOfMass, acceptableAbsoluteError); From 119ef24d5def7f688611af1a7ea3bd2240c63110 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 22 Mar 2016 11:41:45 -0700 Subject: [PATCH 20/39] cleanup ShapeManager API and fix bitrot in tests --- libraries/physics/src/ShapeManager.cpp | 8 ++------ libraries/physics/src/ShapeManager.h | 5 ++--- tests/physics/src/BulletTestUtils.h | 2 ++ tests/physics/src/ShapeManagerTests.cpp | 8 ++++---- tests/physics/src/ShapeManagerTests.h | 2 +- 5 files changed, 11 insertions(+), 14 deletions(-) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 7a3065dfff..e9430b36db 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -58,7 +58,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { } // private helper method -bool ShapeManager::releaseShape(const DoubleHashKey& key) { +bool ShapeManager::releaseShapeByKey(const DoubleHashKey& key) { ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef) { if (shapeRef->refCount > 0) { @@ -82,16 +82,12 @@ bool ShapeManager::releaseShape(const DoubleHashKey& key) { return false; } -bool ShapeManager::releaseShape(const ShapeInfo& info) { - return releaseShape(info.getHash()); -} - bool ShapeManager::releaseShape(const btCollisionShape* shape) { int numShapes = _shapeMap.size(); for (int i = 0; i < numShapes; ++i) { ShapeReference* shapeRef = _shapeMap.getAtIndex(i); if (shape == shapeRef->shape) { - return releaseShape(shapeRef->key); + return releaseShapeByKey(shapeRef->key); } } return false; diff --git a/libraries/physics/src/ShapeManager.h b/libraries/physics/src/ShapeManager.h index e04fa1280c..0c411f5f62 100644 --- a/libraries/physics/src/ShapeManager.h +++ b/libraries/physics/src/ShapeManager.h @@ -29,7 +29,6 @@ public: btCollisionShape* getShape(const ShapeInfo& info); /// \return true if shape was found and released - bool releaseShape(const ShapeInfo& info); bool releaseShape(const btCollisionShape* shape); /// delete shapes that have zero references @@ -39,10 +38,10 @@ public: int getNumShapes() const { return _shapeMap.size(); } int getNumReferences(const ShapeInfo& info) const; int getNumReferences(const btCollisionShape* shape) const; - bool hasShape(const btCollisionShape* shape) const; + bool hasShape(const btCollisionShape* shape) const; private: - bool releaseShape(const DoubleHashKey& key); + bool releaseShapeByKey(const DoubleHashKey& key); struct ShapeReference { int refCount; diff --git a/tests/physics/src/BulletTestUtils.h b/tests/physics/src/BulletTestUtils.h index 9166f80ba1..c047a2c1ce 100644 --- a/tests/physics/src/BulletTestUtils.h +++ b/tests/physics/src/BulletTestUtils.h @@ -14,6 +14,8 @@ #include +#include + // Implements functionality in QTestExtensions.h for glm types // There are 3 functions in here (which need to be defined for all types that use them): // diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 1ee7cd561e..75ad8b3d3a 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -21,7 +21,7 @@ void ShapeManagerTests::testShapeAccounting() { ShapeManager shapeManager; ShapeInfo info; info.setBox(glm::vec3(1.0f, 1.0f, 1.0f)); - + int numReferences = shapeManager.getNumReferences(info); QCOMPARE(numReferences, 0); @@ -42,10 +42,10 @@ void ShapeManagerTests::testShapeAccounting() { QCOMPARE(numReferences, expectedNumReferences); // release all references - bool released = shapeManager.releaseShape(info); + bool released = shapeManager.releaseShape(shape); numReferences--; while (numReferences > 0) { - released = shapeManager.releaseShape(info) && released; + released = shapeManager.releaseShape(shape) && released; numReferences--; } QCOMPARE(released, true); @@ -69,7 +69,7 @@ void ShapeManagerTests::testShapeAccounting() { QCOMPARE(numReferences, 1); // release reference and verify that it is collected as garbage - released = shapeManager.releaseShape(info); + released = shapeManager.releaseShape(shape); shapeManager.collectGarbage(); QCOMPARE(shapeManager.getNumShapes(), 0); QCOMPARE(shapeManager.hasShape(shape), false); diff --git a/tests/physics/src/ShapeManagerTests.h b/tests/physics/src/ShapeManagerTests.h index a4b7fbecd1..1dac307413 100644 --- a/tests/physics/src/ShapeManagerTests.h +++ b/tests/physics/src/ShapeManagerTests.h @@ -16,7 +16,7 @@ class ShapeManagerTests : public QObject { Q_OBJECT - + private slots: void testShapeAccounting(); void addManyShapes(); From ecfe198e35fad5b07d09eba40ede017b7f1eb65c Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Wed, 23 Mar 2016 14:37:01 -0700 Subject: [PATCH 21/39] patch btCompoundShape memory leak --- libraries/physics/src/ShapeFactory.cpp | 18 ++++++++ libraries/physics/src/ShapeFactory.h | 1 + libraries/physics/src/ShapeManager.cpp | 31 +++++--------- tests/physics/src/ShapeManagerTests.cpp | 55 +++++++++++++++++++++++++ tests/physics/src/ShapeManagerTests.h | 1 + 5 files changed, 86 insertions(+), 20 deletions(-) diff --git a/libraries/physics/src/ShapeFactory.cpp b/libraries/physics/src/ShapeFactory.cpp index f956e562cd..de3e9cc794 100644 --- a/libraries/physics/src/ShapeFactory.cpp +++ b/libraries/physics/src/ShapeFactory.cpp @@ -120,3 +120,21 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) { } return shape; } + +void ShapeFactory::deleteShape(btCollisionShape* shape) { + assert(shape); + if (shape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + btCompoundShape* compoundShape = static_cast(shape); + const int numChildShapes = compoundShape->getNumChildShapes(); + for (int i = 0; i < numChildShapes; i ++) { + btCollisionShape* childShape = compoundShape->getChildShape(i); + if (childShape->getShapeType() == (int)COMPOUND_SHAPE_PROXYTYPE) { + // recurse + ShapeFactory::deleteShape(childShape); + } else { + delete childShape; + } + } + } + delete shape; +} diff --git a/libraries/physics/src/ShapeFactory.h b/libraries/physics/src/ShapeFactory.h index f6a6dfb3e6..1ba2bdb619 100644 --- a/libraries/physics/src/ShapeFactory.h +++ b/libraries/physics/src/ShapeFactory.h @@ -22,6 +22,7 @@ namespace ShapeFactory { btConvexHullShape* createConvexHull(const QVector& points); btCollisionShape* createShapeFromInfo(const ShapeInfo& info); + void deleteShape(btCollisionShape* shape); }; #endif // hifi_ShapeFactory_h diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index e9430b36db..4231d1eb60 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -23,7 +23,7 @@ ShapeManager::~ShapeManager() { int numShapes = _shapeMap.size(); for (int i = 0; i < numShapes; ++i) { ShapeReference* shapeRef = _shapeMap.getAtIndex(i); - delete shapeRef->shape; + ShapeFactory::deleteShape(shapeRef->shape); } _shapeMap.clear(); } @@ -32,13 +32,14 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { if (info.getType() == SHAPE_TYPE_NONE) { return NULL; } - // Very small or large objects are not supported. - float diagonal = 4.0f * glm::length2(info.getHalfExtents()); - const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube - //const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e6f; // 1000 m cube - if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED /* || diagonal > MAX_SHAPE_DIAGONAL_SQUARED*/ ) { - // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; - return NULL; + if (info.getType() != SHAPE_TYPE_COMPOUND) { + // Very small or large non-compound objects are not supported. + float diagonal = 4.0f * glm::length2(info.getHalfExtents()); + const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube + if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED) { + // qCDebug(physics) << "ShapeManager::getShape -- not making shape due to size" << diagonal; + return NULL; + } } DoubleHashKey key = info.getHash(); ShapeReference* shapeRef = _shapeMap.find(key); @@ -65,7 +66,7 @@ bool ShapeManager::releaseShapeByKey(const DoubleHashKey& key) { shapeRef->refCount--; if (shapeRef->refCount == 0) { _pendingGarbage.push_back(key); - const int MAX_GARBAGE_CAPACITY = 127; + const int MAX_GARBAGE_CAPACITY = 255; if (_pendingGarbage.size() > MAX_GARBAGE_CAPACITY) { collectGarbage(); } @@ -99,17 +100,7 @@ void ShapeManager::collectGarbage() { DoubleHashKey& key = _pendingGarbage[i]; ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef && shapeRef->refCount == 0) { - // if the shape we're about to delete is compound, delete the children first. - if (shapeRef->shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) { - const btCompoundShape* compoundShape = static_cast(shapeRef->shape); - const int numChildShapes = compoundShape->getNumChildShapes(); - for (int i = 0; i < numChildShapes; i ++) { - const btCollisionShape* childShape = compoundShape->getChildShape(i); - delete childShape; - } - } - - delete shapeRef->shape; + ShapeFactory::deleteShape(shapeRef->shape); _shapeMap.remove(key); } } diff --git a/tests/physics/src/ShapeManagerTests.cpp b/tests/physics/src/ShapeManagerTests.cpp index 75ad8b3d3a..66ac9d0c4a 100644 --- a/tests/physics/src/ShapeManagerTests.cpp +++ b/tests/physics/src/ShapeManagerTests.cpp @@ -183,3 +183,58 @@ void ShapeManagerTests::addCapsuleShape() { QCOMPARE(shape, otherShape); */ } + +void ShapeManagerTests::addCompoundShape() { + // initialize some points for generating tetrahedral convex hulls + QVector tetrahedron; + tetrahedron.push_back(glm::vec3(1.0f, 1.0f, 1.0f)); + tetrahedron.push_back(glm::vec3(1.0f, -1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, 1.0f, -1.0f)); + tetrahedron.push_back(glm::vec3(-1.0f, -1.0f, 1.0f)); + int numHullPoints = tetrahedron.size(); + + // compute the points of the hulls + QVector< QVector > hulls; + int numHulls = 5; + glm::vec3 offsetNormal(1.0f, 0.0f, 0.0f); + for (int i = 0; i < numHulls; ++i) { + glm::vec3 offset = (float)(i - numHulls/2) * offsetNormal; + QVector hull; + float radius = (float)(i + 1); + for (int j = 0; j < numHullPoints; ++j) { + glm::vec3 point = radius * tetrahedron[j] + offset; + hull.push_back(point); + } + hulls.push_back(hull); + } + + // create the ShapeInfo + ShapeInfo info; + info.setConvexHulls(hulls); + + // create the shape + ShapeManager shapeManager; + btCollisionShape* shape = shapeManager.getShape(info); + QVERIFY(shape != nullptr); + + // verify the shape is correct type + QCOMPARE(shape->getShapeType(), (int)COMPOUND_SHAPE_PROXYTYPE); + + // verify the shape has correct number of children + btCompoundShape* compoundShape = static_cast(shape); + QCOMPARE(compoundShape->getNumChildShapes(), numHulls); + + // verify manager has only one shape + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 1); + + // release the shape + shapeManager.releaseShape(shape); + QCOMPARE(shapeManager.getNumShapes(), 1); + QCOMPARE(shapeManager.getNumReferences(info), 0); + + // collect garbage + shapeManager.collectGarbage(); + QCOMPARE(shapeManager.getNumShapes(), 0); + QCOMPARE(shapeManager.getNumReferences(info), 0); +} diff --git a/tests/physics/src/ShapeManagerTests.h b/tests/physics/src/ShapeManagerTests.h index 1dac307413..cff02dcfa4 100644 --- a/tests/physics/src/ShapeManagerTests.h +++ b/tests/physics/src/ShapeManagerTests.h @@ -24,6 +24,7 @@ private slots: void addSphereShape(); void addCylinderShape(); void addCapsuleShape(); + void addCompoundShape(); }; #endif // hifi_ShapeManagerTests_h From 550738776c0b39a3fed5caad4a6b1ea9efc1d43d Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Mar 2016 15:56:29 -0700 Subject: [PATCH 22/39] Pass whether or not previous session crashed to the UserActivityLogger. --- interface/src/Application.cpp | 8 ++++---- interface/src/Application.h | 2 +- interface/src/CrashHandler.cpp | 4 +++- interface/src/CrashHandler.h | 2 +- libraries/networking/src/UserActivityLogger.cpp | 4 +++- libraries/networking/src/UserActivityLogger.h | 2 +- 6 files changed, 13 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7e88ea28dc..f96dcb0335 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -369,7 +369,7 @@ bool setupEssentials(int& argc, char** argv) { Setting::preInit(); - CrashHandler::checkForAndHandleCrash(); + bool previousSessionCrashed = CrashHandler::checkForAndHandleCrash(); CrashHandler::writeRunningMarkerFiler(); qAddPostRoutine(CrashHandler::deleteRunningMarkerFile); @@ -431,7 +431,7 @@ bool setupEssentials(int& argc, char** argv) { DependencyManager::set(); DependencyManager::set(true, qApp, qApp); DependencyManager::set(); - return true; + return previousSessionCrashed; } // FIXME move to header, or better yet, design some kind of UI manager @@ -455,7 +455,7 @@ Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), _window(new MainWindow(desktop())), - _dependencyManagerIsSetup(setupEssentials(argc, argv)), + _previousSessionCrashed(setupEssentials(argc, argv)), _undoStackScriptingInterface(&_undoStack), _frameCount(0), _fps(60.0f), @@ -642,7 +642,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : accountManager.setIsAgent(true); accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); - UserActivityLogger::getInstance().launch(applicationVersion()); + UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed); // once the event loop has started, check and signal for an access token QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); diff --git a/interface/src/Application.h b/interface/src/Application.h index 4c12164a5f..206a37ce58 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -376,7 +376,7 @@ private: MainWindow* _window; - bool _dependencyManagerIsSetup; + bool _previousSessionCrashed; OffscreenGLCanvas* _offscreenContext { nullptr }; DisplayPluginPointer _displayPlugin; diff --git a/interface/src/CrashHandler.cpp b/interface/src/CrashHandler.cpp index 5a194973b4..50cca15c88 100644 --- a/interface/src/CrashHandler.cpp +++ b/interface/src/CrashHandler.cpp @@ -27,7 +27,7 @@ static const QString RUNNING_MARKER_FILENAME = "Interface.running"; -void CrashHandler::checkForAndHandleCrash() { +bool CrashHandler::checkForAndHandleCrash() { QFile runningMarkerFile(runningMarkerFilePath()); if (runningMarkerFile.exists()) { QSettings::setDefaultFormat(QSettings::IniFormat); @@ -42,7 +42,9 @@ void CrashHandler::checkForAndHandleCrash() { handleCrash(action); } } + return true; } + return false; } CrashHandler::Action CrashHandler::promptUserForAction() { diff --git a/interface/src/CrashHandler.h b/interface/src/CrashHandler.h index 61361b6107..18c935b595 100644 --- a/interface/src/CrashHandler.h +++ b/interface/src/CrashHandler.h @@ -17,7 +17,7 @@ class CrashHandler { public: - static void checkForAndHandleCrash(); + static bool checkForAndHandleCrash(); static void writeRunningMarkerFiler(); static void deleteRunningMarkerFile(); diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index f2019ba9a9..05144d8cb0 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -78,11 +78,13 @@ void UserActivityLogger::requestError(QNetworkReply& errorReply) { qCDebug(networking) << errorReply.error() << "-" << errorReply.errorString(); } -void UserActivityLogger::launch(QString applicationVersion) { +void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed) { const QString ACTION_NAME = "launch"; QJsonObject actionDetails; QString VERSION_KEY = "version"; + QString CRASH_KEY = "previousSessionCrashed"; actionDetails.insert(VERSION_KEY, applicationVersion); + actionDetails.insert(CRASH_KEY, previousSessionCrashed); logAction(ACTION_NAME, actionDetails); } diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h index 2811be86a8..bfb7a42a50 100644 --- a/libraries/networking/src/UserActivityLogger.h +++ b/libraries/networking/src/UserActivityLogger.h @@ -29,7 +29,7 @@ public slots: void disable(bool disable); void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters()); - void launch(QString applicationVersion); + void launch(QString applicationVersion, bool previousSessionCrashed); void changedDisplayName(QString displayName); void changedModel(QString typeOfModel, QString modelURL); From 3fa3b40f433251a1ae4fc758f2b58e492b45f364 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 23 Mar 2016 15:56:31 -0700 Subject: [PATCH 23/39] fix non-animated motor proteins --- libraries/entities-renderer/src/RenderableModelEntityItem.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 03226342da..069b7385b5 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -38,12 +38,6 @@ public: EntityPropertyFlags& propertyFlags, bool overwriteLocalData, bool& somethingChanged) override; - virtual void somethingChangedNotification() override { - // FIX ME: this is overly aggressive. We only really need to simulate() if something about - // the world space transform has changed and/or if some animation is occurring. - _needsInitialSimulation = true; - } - virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr); virtual bool addToScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; virtual void removeFromScene(EntityItemPointer self, std::shared_ptr scene, render::PendingChanges& pendingChanges) override; From 1e46b0803c829f393ea72a5d09d0335280cca964 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 15:59:57 -0700 Subject: [PATCH 24/39] fixing repported issues during review --- .../src/model-networking/ModelCache.cpp | 4 +-- libraries/model/src/model/Material.cpp | 32 ++++++++----------- .../render-utils/src/MeshPartPayload.cpp | 2 +- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 5eb961ef98..198cf9143c 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -139,7 +139,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { } if (!_isLoadedWithTextures) { - _hasTransparentTextures = true; + _hasTransparentTextures = false; for (auto&& material : _materials) { if ((material->albedoTexture && !material->albedoTexture->isLoaded()) || @@ -156,7 +156,7 @@ bool NetworkGeometry::isLoadedWithTextures() const { material->_material->setTextureMap(model::MaterialKey::ALBEDO_MAP, material->_material->getTextureMap(model::MaterialKey::ALBEDO_MAP)); const auto& usage = material->albedoTexture->getGPUTexture()->getUsage(); bool isTransparentTexture = usage.isAlpha() && !usage.isAlphaMask(); - _hasTransparentTextures = isTransparentTexture && _hasTransparentTextures; + _hasTransparentTextures |= isTransparentTexture; } } diff --git a/libraries/model/src/model/Material.cpp b/libraries/model/src/model/Material.cpp index 81bc9b40a6..0a6a4bb695 100755 --- a/libraries/model/src/model/Material.cpp +++ b/libraries/model/src/model/Material.cpp @@ -80,7 +80,6 @@ void Material::setMetallic(float metallic) { _schemaBuffer.edit()._metallic = metallic; } - void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textureMap) { if (textureMap) { _key.setMapChannel(channel, (true)); @@ -90,26 +89,21 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _key.setOpacityMaskMap(false); _key.setTranslucentMap(false); - if (textureMap->useAlphaChannel()) { - if (textureMap->isDefined()) { - if (textureMap->getTextureView().isValid()) { - auto usage = textureMap->getTextureView()._texture->getUsage(); - if (usage.isAlpha()) { - // Texture has alpha, is not just a mask or a true transparent channel - if (usage.isAlphaMask()) { - _key.setOpacityMaskMap(true); - _key.setTranslucentMap(false); - } else { - _key.setOpacityMaskMap(false); - _key.setTranslucentMap(true); - } - } + if (textureMap->useAlphaChannel() && textureMap->isDefined() && textureMap->getTextureView().isValid()) { + auto usage = textureMap->getTextureView()._texture->getUsage(); + if (usage.isAlpha()) { + // Texture has alpha, is not just a mask or a true transparent channel + if (usage.isAlphaMask()) { + _key.setOpacityMaskMap(true); + _key.setTranslucentMap(false); + } else { + _key.setOpacityMaskMap(false); + _key.setTranslucentMap(true); } } } } - _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps[channel] = textureMap; } else { _key.setMapChannel(channel, (false)); @@ -119,9 +113,11 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur _key.setTranslucentMap(false); } - _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); _textureMaps.erase(channel); } + + _schemaBuffer.edit()._key = (uint32)_key._flags.to_ulong(); + } @@ -132,4 +128,4 @@ const TextureMapPointer Material::getTextureMap(MapChannel channel) const { } else { return TextureMapPointer(); } -} \ No newline at end of file +} diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index aca9774221..363def05a1 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -81,7 +81,7 @@ ItemKey MeshPartPayload::getKey() const { if (_drawMaterial) { auto matKey = _drawMaterial->getKey(); - if (matKey.isTranslucentFactor() || matKey.isTranslucentMap()) { + if (matKey.isTranslucent()) { builder.withTransparent(); } } From 22191a2864f9f0eaa5ba8a12e47279912cc04a36 Mon Sep 17 00:00:00 2001 From: samcake Date: Wed, 23 Mar 2016 16:12:43 -0700 Subject: [PATCH 25/39] When an albedo texture is replaced from script,make sure its aloha channel is checked for opacity --- .../model-networking/src/model-networking/ModelCache.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/model-networking/src/model-networking/ModelCache.cpp b/libraries/model-networking/src/model-networking/ModelCache.cpp index 198cf9143c..b0b769d5e9 100644 --- a/libraries/model-networking/src/model-networking/ModelCache.cpp +++ b/libraries/model-networking/src/model-networking/ModelCache.cpp @@ -176,9 +176,9 @@ void NetworkGeometry::setTextureWithNameToURL(const QString& name, const QUrl& u auto albedoMap = model::TextureMapPointer(new model::TextureMap()); albedoMap->setTextureSource(material->albedoTexture->_textureSource); - albedoMap->setTextureTransform( - oldTextureMaps[model::MaterialKey::ALBEDO_MAP]->getTextureTransform()); - + albedoMap->setTextureTransform(oldTextureMaps[model::MaterialKey::ALBEDO_MAP]->getTextureTransform()); + // when reassigning the albedo texture we also check for the alpha channel used as opacity + albedoMap->setUseAlphaChannel(true); networkMaterial->setTextureMap(model::MaterialKey::ALBEDO_MAP, albedoMap); } else if (material->normalTextureName == name) { material->normalTexture = textureCache->getTexture(url); From c435ca212a603e0bb37a67b83464d125ee4cbac6 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Mar 2016 16:59:17 -0700 Subject: [PATCH 26/39] Report previous session time. --- interface/src/Application.cpp | 14 +++++++++----- interface/src/Application.h | 1 + libraries/networking/src/UserActivityLogger.cpp | 4 +++- libraries/networking/src/UserActivityLogger.h | 2 +- 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f96dcb0335..4f13665fef 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,8 +169,6 @@ #include "Util.h" #include "InterfaceParentFinder.h" - - // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) @@ -195,6 +193,7 @@ static const QString FBX_EXTENSION = ".fbx"; static const QString OBJ_EXTENSION = ".obj"; static const QString AVA_JSON_EXTENSION = ".ava.json"; +static const int MSECS_PER_SEC = 1000; static const int MIRROR_VIEW_TOP_PADDING = 5; static const int MIRROR_VIEW_LEFT_PADDING = 10; static const int MIRROR_VIEW_WIDTH = 265; @@ -452,8 +451,11 @@ PluginContainer* _pluginContainer; OffscreenGLCanvas* _chromiumShareContext { nullptr }; Q_GUI_EXPORT void qt_gl_set_global_share_context(QOpenGLContext *context); +Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; + Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), + _sessionRunTimer(startupTimer), _window(new MainWindow(desktop())), _previousSessionCrashed(setupEssentials(argc, argv)), _undoStackScriptingInterface(&_undoStack), @@ -605,7 +607,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(clearDomainOctreeDetails())); // update our location every 5 seconds in the metaverse server, assuming that we are authenticated with one - const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * 1000; + const qint64 DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS = 5 * MSECS_PER_SEC; auto discoverabilityManager = DependencyManager::get(); connect(&locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); @@ -627,7 +629,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : // connect to appropriate slots on AccountManager AccountManager& accountManager = AccountManager::getInstance(); - const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * 1000; + const qint64 BALANCE_UPDATE_INTERVAL_MSECS = 5 * MSECS_PER_SEC; connect(&balanceUpdateTimer, &QTimer::timeout, &accountManager, &AccountManager::updateBalance); balanceUpdateTimer.start(BALANCE_UPDATE_INTERVAL_MSECS); @@ -642,7 +644,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : accountManager.setIsAgent(true); accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); - UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed); + UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get()); // before loadSettings resets sessionRuntTime. // once the event loop has started, check and signal for an access token QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); @@ -2804,6 +2806,7 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa void Application::loadSettings() { + sessionRunTime.set(0); // Just clean living. We're about to saveSettings, which will update value. DependencyManager::get()->loadSettings(); DependencyManager::get()->loadSettings(); @@ -2817,6 +2820,7 @@ void Application::loadSettings() { } void Application::saveSettings() { + sessionRunTime.set(_sessionRunTimer.elapsed() / MSECS_PER_SEC); DependencyManager::get()->saveSettings(); DependencyManager::get()->saveSettings(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 206a37ce58..88c7602b6d 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -375,6 +375,7 @@ private: void maybeToggleMenuVisible(QMouseEvent* event); MainWindow* _window; + QElapsedTimer& _sessionRunTimer; bool _previousSessionCrashed; diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index 05144d8cb0..2e74a5166c 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -78,13 +78,15 @@ void UserActivityLogger::requestError(QNetworkReply& errorReply) { qCDebug(networking) << errorReply.error() << "-" << errorReply.errorString(); } -void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed) { +void UserActivityLogger::launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime) { const QString ACTION_NAME = "launch"; QJsonObject actionDetails; QString VERSION_KEY = "version"; QString CRASH_KEY = "previousSessionCrashed"; + QString RUNTIME_KEY = "previousSessionRuntime"; actionDetails.insert(VERSION_KEY, applicationVersion); actionDetails.insert(CRASH_KEY, previousSessionCrashed); + actionDetails.insert(RUNTIME_KEY, previousSessionRuntime); logAction(ACTION_NAME, actionDetails); } diff --git a/libraries/networking/src/UserActivityLogger.h b/libraries/networking/src/UserActivityLogger.h index bfb7a42a50..8eda086521 100644 --- a/libraries/networking/src/UserActivityLogger.h +++ b/libraries/networking/src/UserActivityLogger.h @@ -29,7 +29,7 @@ public slots: void disable(bool disable); void logAction(QString action, QJsonObject details = QJsonObject(), JSONCallbackParameters params = JSONCallbackParameters()); - void launch(QString applicationVersion, bool previousSessionCrashed); + void launch(QString applicationVersion, bool previousSessionCrashed, int previousSessionRuntime); void changedDisplayName(QString displayName); void changedModel(QString typeOfModel, QString modelURL); From dbdf79f96ffa6598ba3bd7c730f5ee2051b83883 Mon Sep 17 00:00:00 2001 From: howard-stearns Date: Wed, 23 Mar 2016 17:01:50 -0700 Subject: [PATCH 27/39] Restore whitespace so there aren't superfluous diffs. --- interface/src/Application.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4f13665fef..c27dfb63df 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -169,6 +169,8 @@ #include "Util.h" #include "InterfaceParentFinder.h" + + // ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU // FIXME seems to be broken. #if defined(Q_OS_WIN) From fdd0b48ae13aefbf300d76af1b8065bbc3aaeafb Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 23 Mar 2016 17:06:03 -0700 Subject: [PATCH 28/39] reduce log spam --- libraries/entities/src/EntityTreeElement.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 6f9880171b..8cc7c98855 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -956,8 +956,10 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int entityItem->recordCreationTime(); } } else { - qDebug() << "Recieved packet for previously deleted entity [" << + #ifdef WANT_DEBUG + qDebug() << "Recieved packet for previously deleted entity [" << entityItem->getID() << "] ignoring. (inside " << __FUNCTION__ << ")"; + #endif } } } From c09c1438f897b4e9b1aab6483207a8ddb49b9250 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 23 Mar 2016 17:28:54 -0700 Subject: [PATCH 29/39] ivar init order. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index c27dfb63df..5febdb7d76 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -457,8 +457,8 @@ Setting::Handle sessionRunTime{ "sessionRunTime", 0 }; Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : QApplication(argc, argv), - _sessionRunTimer(startupTimer), _window(new MainWindow(desktop())), + _sessionRunTimer(startupTimer), _previousSessionCrashed(setupEssentials(argc, argv)), _undoStackScriptingInterface(&_undoStack), _frameCount(0), From 57da7c2ba71e848dba7b785e970ff3c005c45625 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Mar 2016 17:29:46 -0700 Subject: [PATCH 30/39] add handling for short circuit loss in SendQueue --- .../networking/src/udt/CongestionControl.cpp | 2 +- libraries/networking/src/udt/Connection.cpp | 7 ++ libraries/networking/src/udt/Connection.h | 1 + libraries/networking/src/udt/SendQueue.cpp | 99 +++++++++++-------- libraries/networking/src/udt/SendQueue.h | 7 +- tools/udt-test/src/UDTTest.cpp | 2 +- 6 files changed, 73 insertions(+), 45 deletions(-) diff --git a/libraries/networking/src/udt/CongestionControl.cpp b/libraries/networking/src/udt/CongestionControl.cpp index 1d1a6628fe..d30be2c139 100644 --- a/libraries/networking/src/udt/CongestionControl.cpp +++ b/libraries/networking/src/udt/CongestionControl.cpp @@ -201,7 +201,7 @@ void DefaultCC::onTimeout() { void DefaultCC::stopSlowStart() { _slowStart = false; - + if (_receiveRate > 0) { // Set the sending rate to the receiving rate. setPacketSendPeriod(USECS_PER_SECOND / _receiveRate); diff --git a/libraries/networking/src/udt/Connection.cpp b/libraries/networking/src/udt/Connection.cpp index e5f3508b81..af70295840 100644 --- a/libraries/networking/src/udt/Connection.cpp +++ b/libraries/networking/src/udt/Connection.cpp @@ -103,6 +103,7 @@ SendQueue& Connection::getSendQueue() { QObject::connect(_sendQueue.get(), &SendQueue::packetRetransmitted, this, &Connection::recordRetransmission); QObject::connect(_sendQueue.get(), &SendQueue::queueInactive, this, &Connection::queueInactive); QObject::connect(_sendQueue.get(), &SendQueue::timeout, this, &Connection::queueTimeout); + QObject::connect(_sendQueue.get(), &SendQueue::shortCircuitLoss, this, &Connection::queueShortCircuitLoss); // set defaults on the send queue from our congestion control object and estimatedTimeout() _sendQueue->setPacketSendPeriod(_congestionControl->_packetSendPeriod); @@ -140,6 +141,12 @@ void Connection::queueTimeout() { }); } +void Connection::queueShortCircuitLoss(quint32 sequenceNumber) { + updateCongestionControlAndSendQueue([this, sequenceNumber]{ + _congestionControl->onLoss(SequenceNumber { sequenceNumber }, SequenceNumber { sequenceNumber }); + }); +} + void Connection::sendReliablePacket(std::unique_ptr packet) { Q_ASSERT_X(packet->isReliable(), "Connection::send", "Trying to send an unreliable packet reliably."); getSendQueue().queuePacket(std::move(packet)); diff --git a/libraries/networking/src/udt/Connection.h b/libraries/networking/src/udt/Connection.h index 4f5a8793e7..08a2df9b97 100644 --- a/libraries/networking/src/udt/Connection.h +++ b/libraries/networking/src/udt/Connection.h @@ -87,6 +87,7 @@ private slots: void recordRetransmission(); void queueInactive(); void queueTimeout(); + void queueShortCircuitLoss(quint32 sequenceNumber); private: void sendACK(bool wasCausedBySyncTimeout = true); diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 9701561ec7..2c3303537c 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -128,8 +128,8 @@ void SendQueue::stop() { _emptyCondition.notify_one(); } -void SendQueue::sendPacket(const Packet& packet) { - _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); +int SendQueue::sendPacket(const Packet& packet) { + return _socket->writeDatagram(packet.getData(), packet.getDataSize(), _destination); } void SendQueue::ack(SequenceNumber ack) { @@ -178,7 +178,7 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { // this is a response from the client, re-set our timeout expiry _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); - + { std::lock_guard nakLocker(_naksLock); _naks.clear(); @@ -232,15 +232,16 @@ SequenceNumber SendQueue::getNextSequenceNumber() { return _currentSequenceNumber; } -void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) { +bool SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber) { // write the sequence number and send the packet newPacket->writeSequenceNumber(sequenceNumber); - sendPacket(*newPacket); - + // Save packet/payload size before we move it auto packetSize = newPacket->getDataSize(); auto payloadSize = newPacket->getPayloadSize(); + auto bytesWritten = sendPacket(*newPacket); + { // Insert the packet we have just sent in the sent list QWriteLocker locker(&_sentLock); @@ -249,8 +250,24 @@ void SendQueue::sendNewPacketAndAddToSentList(std::unique_ptr newPacket, entry.second.swap(newPacket); } Q_ASSERT_X(!newPacket, "SendQueue::sendNewPacketAndAddToSentList()", "Overriden packet in sent list"); - + emit packetSent(packetSize, payloadSize); + + if (bytesWritten < 0) { + // this is a short-circuit loss - we failed to put this packet on the wire + // so immediately add it to the loss list + + { + std::lock_guard nakLocker(_naksLock); + _naks.append(sequenceNumber); + } + + emit shortCircuitLoss(quint32(sequenceNumber)); + + return false; + } else { + return true; + } } void SendQueue::run() { @@ -285,12 +302,12 @@ void SendQueue::run() { auto nextPacketTimestamp = p_high_resolution_clock::now(); while (_state == State::Running) { - bool sentAPacket = maybeResendPacket(); + bool attemptedToSendPacket = maybeResendPacket(); // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet - if (!sentAPacket) { - sentAPacket = maybeSendNewPacket(); + if (!attemptedToSendPacket) { + attemptedToSendPacket = maybeSendNewPacket(); } // since we're a while loop, give the thread a chance to process events @@ -300,7 +317,7 @@ void SendQueue::run() { // If the send queue has been innactive, skip the sleep for // Either _isRunning will have been set to false and we'll break // Or something happened and we'll keep going - if (_state != State::Running || isInactive(sentAPacket)) { + if (_state != State::Running || isInactive(attemptedToSendPacket)) { return; } @@ -324,33 +341,34 @@ bool SendQueue::maybeSendNewPacket() { // grab the first packet we will send std::unique_ptr firstPacket = _packets.takePacket(); Q_ASSERT(firstPacket); - - std::unique_ptr secondPacket; - bool shouldSendPairTail = false; - - if (((uint32_t) nextNumber & 0xF) == 0) { - // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets - // pull off a second packet if we can before we unlock - shouldSendPairTail = true; - - secondPacket = _packets.takePacket(); + + + // attempt to send the first packet + if (sendNewPacketAndAddToSentList(move(firstPacket), nextNumber)) { + std::unique_ptr secondPacket; + bool shouldSendPairTail = false; + + if (((uint32_t) nextNumber & 0xF) == 0) { + // the first packet is the first in a probe pair - every 16 (rightmost 16 bits = 0) packets + // pull off a second packet if we can before we unlock + shouldSendPairTail = true; + + secondPacket = _packets.takePacket(); + } + + // do we have a second in a pair to send as well? + if (secondPacket) { + sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber()); + } else if (shouldSendPairTail) { + // we didn't get a second packet to send in the probe pair + // send a control packet of type ProbePairTail so the receiver can still do + // proper bandwidth estimation + static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail); + _socket->writeBasePacket(*pairTailPacket, _destination); + } } - - // definitely send the first packet - sendNewPacketAndAddToSentList(move(firstPacket), nextNumber); - - // do we have a second in a pair to send as well? - if (secondPacket) { - sendNewPacketAndAddToSentList(move(secondPacket), getNextSequenceNumber()); - } else if (shouldSendPairTail) { - // we didn't get a second packet to send in the probe pair - // send a control packet of type ProbePairTail so the receiver can still do - // proper bandwidth estimation - static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail); - _socket->writeBasePacket(*pairTailPacket, _destination); - } - - // We sent our packet(s), return here + + // We attempted to send packet(s), return here return true; } } @@ -375,8 +393,9 @@ bool SendQueue::maybeResendPacket() { // see if we can find the packet to re-send auto it = _sentPackets.find(resendNumber); - + if (it != _sentPackets.end()) { + auto& entry = it->second; // we found the packet - grab it auto& resendPacket = *(entry.second); @@ -437,7 +456,7 @@ bool SendQueue::maybeResendPacket() { return false; } -bool SendQueue::isInactive(bool sentAPacket) { +bool SendQueue::isInactive(bool attemptedToSendPacket) { // check for connection timeout first // that will be the case if we have had 16 timeouts since hearing back from the client, and it has been @@ -462,7 +481,7 @@ bool SendQueue::isInactive(bool sentAPacket) { return true; } - if (!sentAPacket) { + if (!attemptedToSendPacket) { // During our processing above we didn't send any packets // If that is still the case we should use a condition_variable_any to sleep until we have data to handle. diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 9400ae8352..dc151e9f4d 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -79,6 +79,7 @@ signals: void queueInactive(); + void shortCircuitLoss(quint32 sequenceNumber); void timeout(); private slots: @@ -91,13 +92,13 @@ private: void sendHandshake(); - void sendPacket(const Packet& packet); - void sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); + int sendPacket(const Packet& packet); + bool sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); bool maybeSendNewPacket(); // Figures out what packet to send next bool maybeResendPacket(); // Determines whether to resend a packet and which one - bool isInactive(bool sentAPacket); + bool isInactive(bool attemptedToSendPacket); void deactivate(); // makes the queue inactive and cleans it up bool isFlowWindowFull() const; diff --git a/tools/udt-test/src/UDTTest.cpp b/tools/udt-test/src/UDTTest.cpp index 533e6371e9..2b5e306b09 100644 --- a/tools/udt-test/src/UDTTest.cpp +++ b/tools/udt-test/src/UDTTest.cpp @@ -77,7 +77,7 @@ UDTTest::UDTTest(int& argc, char** argv) : // randomize the seed for packet size randomization srand(time(NULL)); - + _socket.bind(QHostAddress::AnyIPv4, _argumentParser.value(PORT_OPTION).toUInt()); qDebug() << "Test socket is listening on" << _socket.localPort(); From a393f36978dfc04083acb8507e424d390b38dc06 Mon Sep 17 00:00:00 2001 From: Howard Stearns Date: Wed, 23 Mar 2016 17:31:21 -0700 Subject: [PATCH 31/39] Forgot important comment. --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5febdb7d76..0b02d0803e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -646,7 +646,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) : accountManager.setIsAgent(true); accountManager.setAuthURL(NetworkingConstants::METAVERSE_SERVER_URL); - UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get()); // before loadSettings resets sessionRuntTime. + // sessionRunTime will be reset soon by loadSettings. Grab it now to get previous session value. + // The value will be 0 if the user blew away settings this session, which is both a feature and a bug. + UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get()); // once the event loop has started, check and signal for an access token QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection); From 62a56ecbfa0436f6dd0b1b13fc5dd2d868356581 Mon Sep 17 00:00:00 2001 From: Brad Hefta-Gaub Date: Wed, 23 Mar 2016 17:45:22 -0700 Subject: [PATCH 32/39] fix typos --- libraries/entities/src/EntityItem.cpp | 2 +- libraries/entities/src/EntityTreeElement.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 21919922b9..bbc94e9910 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -516,7 +516,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef EntityTreePointer tree = getTree(); if (tree && tree->isDeletedEntity(_id)) { #ifdef WANT_DEBUG - qDebug() << "Recieved packet for previously deleted entity [" << _id << "] ignoring. " + qDebug() << "Received packet for previously deleted entity [" << _id << "] ignoring. " "(inside " << __FUNCTION__ << ")"; #endif ignoreServerPacket = true; diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 8cc7c98855..7f87c4e0b1 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -957,7 +957,7 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int } } else { #ifdef WANT_DEBUG - qDebug() << "Recieved packet for previously deleted entity [" << + qDebug() << "Received packet for previously deleted entity [" << entityItem->getID() << "] ignoring. (inside " << __FUNCTION__ << ")"; #endif } From 7b326c9d7bdf8daafb3168ce1fbadc4af14f5999 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Wed, 23 Mar 2016 17:56:02 -0700 Subject: [PATCH 33/39] fixes per review --- examples/airship/airship.js | 102 ++++++++++++++++++------------------ 1 file changed, 50 insertions(+), 52 deletions(-) diff --git a/examples/airship/airship.js b/examples/airship/airship.js index 9b6ae45093..0d6d277498 100644 --- a/examples/airship/airship.js +++ b/examples/airship/airship.js @@ -27,7 +27,7 @@ properties, lightTimer = 0, lightTimeoutID = undefined, - audioInjector = null + audioInjector = null; var HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/"; var cannonSound = SoundCache.getSound(HIFI_PUBLIC_BUCKET + "philip/cannonShot.wav"); @@ -199,8 +199,6 @@ }); makeParticles(properties.position, bullet, timeOfFlight * 2); Script.setTimeout(explode, timeOfFlight * 1000); - - } function explode() { @@ -225,8 +223,8 @@ shoot(); } - var timeToNextCheck = 33; - timeoutID = Script.setTimeout(maybe, timeToNextCheck); + var TIME_TO_NEXT_CHECK = 33; + timeoutID = Script.setTimeout(maybe, TIME_TO_NEXT_CHECK); } this.preload = function (givenEntityID) { @@ -252,52 +250,52 @@ function makeParticles(position, parent, lifespan) { particles = Entities.addEntity({ - type: 'ParticleEffect', - position: position, - parentID: parent, - color: { - red: 70, - green: 70, - blue: 70 - }, - isEmitting: 1, - maxParticles: 1000, - lifetime: lifespan, - lifespan: lifespan / 3, - emitRate: 80, - emitSpeed: 0, - speedSpread: 1.0, - emitRadiusStart: 1, - polarStart: -Math.PI/8, - polarFinish: Math.PI/8, - azimuthStart: -Math.PI/4, - azimuthFinish: Math.PI/4, - emitAcceleration: { x: 0, y: 0, z: 0 }, - particleRadius: 0.25, - radiusSpread: 0.1, - radiusStart: 0.3, - radiusFinish: 0.15, - colorSpread: { - red: 100, - green: 100, - blue: 0 - }, - colorStart: { - red: 125, - green: 125, - blue: 125 - }, - colorFinish: { - red: 10, - green: 10, - blue: 10 - }, - alpha: 0.5, - alphaSpread: 0, - alphaStart: 1, - alphaFinish: 0, - emitterShouldTrail: true, - textures: 'https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png' - }); + type: 'ParticleEffect', + position: position, + parentID: parent, + color: { + red: 70, + green: 70, + blue: 70 + }, + isEmitting: 1, + maxParticles: 1000, + lifetime: lifespan, + lifespan: lifespan / 3, + emitRate: 80, + emitSpeed: 0, + speedSpread: 1.0, + emitRadiusStart: 1, + polarStart: -Math.PI/8, + polarFinish: Math.PI/8, + azimuthStart: -Math.PI/4, + azimuthFinish: Math.PI/4, + emitAcceleration: { x: 0, y: 0, z: 0 }, + particleRadius: 0.25, + radiusSpread: 0.1, + radiusStart: 0.3, + radiusFinish: 0.15, + colorSpread: { + red: 100, + green: 100, + blue: 0 + }, + colorStart: { + red: 125, + green: 125, + blue: 125 + }, + colorFinish: { + red: 10, + green: 10, + blue: 10 + }, + alpha: 0.5, + alphaSpread: 0, + alphaStart: 1, + alphaFinish: 0, + emitterShouldTrail: true, + textures: 'https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png' + }); } }) From 0ef5c458150c4c23cda558c3c4b26a38cf405530 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 23 Mar 2016 17:59:54 -0700 Subject: [PATCH 34/39] DeadlockWatchdogThread: bumped up age from 10 to 15 seconds. This will, hopefully, prevent false positives from people loading content on slow PCs. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2a836e00f7..41654dfe6e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -239,7 +239,7 @@ class DeadlockWatchdogThread : public QThread { public: static const unsigned long HEARTBEAT_CHECK_INTERVAL_SECS = 1; static const unsigned long HEARTBEAT_UPDATE_INTERVAL_SECS = 1; - static const unsigned long MAX_HEARTBEAT_AGE_USECS = 10 * USECS_PER_SECOND; + static const unsigned long MAX_HEARTBEAT_AGE_USECS = 15 * USECS_PER_SECOND; // Set the heartbeat on launch DeadlockWatchdogThread() { From 1b322c8d015fd59a657e71c4aa88b4949c5df0f1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Mar 2016 18:07:28 -0700 Subject: [PATCH 35/39] don't oversend because of packet pairs --- libraries/networking/src/udt/SendQueue.cpp | 21 ++++++++++++++------- libraries/networking/src/udt/SendQueue.h | 2 +- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 2c3303537c..30c9f2f491 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -306,8 +306,10 @@ void SendQueue::run() { // if we didn't find a packet to re-send AND we think we can fit a new packet on the wire // (this is according to the current flow window size) then we send out a new packet + auto newPacketCount = 0; if (!attemptedToSendPacket) { - attemptedToSendPacket = maybeSendNewPacket(); + newPacketCount = maybeSendNewPacket(); + attemptedToSendPacket = (newPacketCount > 0); } // since we're a while loop, give the thread a chance to process events @@ -322,7 +324,8 @@ void SendQueue::run() { } // push the next packet timestamp forwards by the current packet send period - nextPacketTimestamp += std::chrono::microseconds(_packetSendPeriod); + auto nextPacketDelta = (newPacketCount == 2 ? 2 : 1) * _packetSendPeriod; + nextPacketTimestamp += std::chrono::microseconds(nextPacketDelta); // sleep as long as we need until next packet send, if we can const auto timeToSleep = duration_cast(nextPacketTimestamp - p_high_resolution_clock::now()); @@ -331,7 +334,7 @@ void SendQueue::run() { } } -bool SendQueue::maybeSendNewPacket() { +int SendQueue::maybeSendNewPacket() { if (!isFlowWindowFull()) { // we didn't re-send a packet, so time to send a new one @@ -366,14 +369,18 @@ bool SendQueue::maybeSendNewPacket() { static auto pairTailPacket = ControlPacket::create(ControlPacket::ProbeTail); _socket->writeBasePacket(*pairTailPacket, _destination); } - } - // We attempted to send packet(s), return here - return true; + // we attempted to send two packets, return 2 + return 2; + } else { + // we attempted to send a single packet, return 1 + return 1; + } } } + // No packets were sent - return false; + return 0; } bool SendQueue::maybeResendPacket() { diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index dc151e9f4d..77c7f3e85e 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -95,7 +95,7 @@ private: int sendPacket(const Packet& packet); bool sendNewPacketAndAddToSentList(std::unique_ptr newPacket, SequenceNumber sequenceNumber); - bool maybeSendNewPacket(); // Figures out what packet to send next + int maybeSendNewPacket(); // Figures out what packet to send next bool maybeResendPacket(); // Determines whether to resend a packet and which one bool isInactive(bool attemptedToSendPacket); From ef3f5e022177a15687b937b478fb6653c73aef87 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 23 Mar 2016 18:23:30 -0700 Subject: [PATCH 36/39] fix for race in last receiver response --- libraries/networking/src/udt/SendQueue.cpp | 9 +++++---- libraries/networking/src/udt/SendQueue.h | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/networking/src/udt/SendQueue.cpp b/libraries/networking/src/udt/SendQueue.cpp index 30c9f2f491..2ffa42cb82 100644 --- a/libraries/networking/src/udt/SendQueue.cpp +++ b/libraries/networking/src/udt/SendQueue.cpp @@ -134,7 +134,7 @@ int SendQueue::sendPacket(const Packet& packet) { void SendQueue::ack(SequenceNumber ack) { // this is a response from the client, re-set our timeout expiry and our last response time - _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); + _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); if (_lastACKSequenceNumber == (uint32_t) ack) { return; @@ -164,7 +164,7 @@ void SendQueue::ack(SequenceNumber ack) { void SendQueue::nak(SequenceNumber start, SequenceNumber end) { // this is a response from the client, re-set our timeout expiry - _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); + _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); { std::lock_guard nakLocker(_naksLock); @@ -177,7 +177,7 @@ void SendQueue::nak(SequenceNumber start, SequenceNumber end) { void SendQueue::overrideNAKListFromPacket(ControlPacket& packet) { // this is a response from the client, re-set our timeout expiry - _lastReceiverResponse = uint64_t(QDateTime::currentMSecsSinceEpoch()); + _lastReceiverResponse = QDateTime::currentMSecsSinceEpoch(); { std::lock_guard nakLocker(_naksLock); @@ -473,7 +473,8 @@ bool SendQueue::isInactive(bool attemptedToSendPacket) { auto sinceLastResponse = (QDateTime::currentMSecsSinceEpoch() - _lastReceiverResponse); - if (sinceLastResponse >= quint64(NUM_TIMEOUTS_BEFORE_INACTIVE * (_estimatedTimeout / USECS_PER_MSEC)) && + if (sinceLastResponse > 0 && + sinceLastResponse >= int64_t(NUM_TIMEOUTS_BEFORE_INACTIVE * (_estimatedTimeout / USECS_PER_MSEC)) && _lastReceiverResponse > 0 && sinceLastResponse > MIN_MS_BEFORE_INACTIVE) { // If the flow window has been full for over CONSIDER_INACTIVE_AFTER, diff --git a/libraries/networking/src/udt/SendQueue.h b/libraries/networking/src/udt/SendQueue.h index 77c7f3e85e..21f6141c3c 100644 --- a/libraries/networking/src/udt/SendQueue.h +++ b/libraries/networking/src/udt/SendQueue.h @@ -123,7 +123,7 @@ private: std::atomic _estimatedTimeout { 0 }; // Estimated timeout, set from CC std::atomic _syncInterval { udt::DEFAULT_SYN_INTERVAL_USECS }; // Sync interval, set from CC - std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK) + std::atomic _lastReceiverResponse { 0 }; // Timestamp for the last time we got new data from the receiver (ACK/NAK) std::atomic _flowWindowSize { 0 }; // Flow control window size (number of packets that can be on wire) - set from CC From 69c516caafe206fd3ec1a4f05b56b000b4f16701 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Mar 2016 19:05:15 -0700 Subject: [PATCH 37/39] Have ATP respect request limit --- libraries/networking/src/ResourceCache.cpp | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 77ced1619c..3de94ed839 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -216,17 +216,13 @@ Resource* ResourceCacheSharedItems::getHighestPendingRequest() { bool ResourceCache::attemptRequest(Resource* resource) { auto sharedItems = DependencyManager::get(); - // Disable request limiting for ATP - if (resource->getURL().scheme() != URL_SCHEME_ATP) { - if (_requestsActive >= _requestLimit) { - // wait until a slot becomes available - sharedItems->appendPendingRequest(resource); - return false; - } - - ++_requestsActive; + if (_requestsActive >= _requestLimit) { + // wait until a slot becomes available + sharedItems->appendPendingRequest(resource); + return false; } - + + ++_requestsActive; sharedItems->appendActiveRequest(resource); resource->makeRequest(); return true; @@ -235,9 +231,7 @@ bool ResourceCache::attemptRequest(Resource* resource) { void ResourceCache::requestCompleted(Resource* resource) { auto sharedItems = DependencyManager::get(); sharedItems->removeRequest(resource); - if (resource->getURL().scheme() != URL_SCHEME_ATP) { - --_requestsActive; - } + --_requestsActive; attemptHighestPriorityRequest(); } From 8c4ecc64d94f6a5a99994d00638ec89b080ada04 Mon Sep 17 00:00:00 2001 From: PhilipRosedale Date: Wed, 23 Mar 2016 22:49:18 -0700 Subject: [PATCH 38/39] fix entity script location --- examples/airship/airship.js | 2 +- examples/airship/makeAirship.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/airship/airship.js b/examples/airship/airship.js index 0d6d277498..80f37603eb 100644 --- a/examples/airship/airship.js +++ b/examples/airship/airship.js @@ -285,7 +285,7 @@ green: 125, blue: 125 }, - colorFinish: { + colorFinish: { red: 10, green: 10, blue: 10 diff --git a/examples/airship/makeAirship.js b/examples/airship/makeAirship.js index 9c6a3348b1..8a25ac6703 100644 --- a/examples/airship/makeAirship.js +++ b/examples/airship/makeAirship.js @@ -14,8 +14,8 @@ var TYPE = "Model"; // Right now this can be "Box" or "Model" or "S var MODEL_URL = "https://s3.amazonaws.com/hifi-public/philip/airship_compact.fbx" var MODEL_DIMENSION = { x: 19.257, y: 24.094, z: 40.3122 }; -//var ENTITY_URL = "https://s3.amazonaws.com/hifi-public/scripts/airship/airship.js?"+Math.random(); -var ENTITY_URL = "file:///c:/users/dev/philip/examples/airship/airship.js?"+Math.random(); +var ENTITY_URL = "https://s3.amazonaws.com/hifi-public/scripts/airship/airship.js"; + var LIFETIME = 3600 * 48; From 51728d14a725a1df2eba79b57ce682a4ba157c68 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 24 Mar 2016 21:17:36 +1300 Subject: [PATCH 39/39] Miscellaneous improvements to Attachments dialog --- .../resources/qml/controls-uit/SpinBox.qml | 1 - .../qml/hifi/dialogs/AttachmentsDialog.qml | 43 +++++++++++++------ .../hifi/dialogs/attachments/Attachment.qml | 41 ++++++++++-------- .../hifi/dialogs/attachments/Translation.qml | 2 +- 4 files changed, 55 insertions(+), 32 deletions(-) diff --git a/interface/resources/qml/controls-uit/SpinBox.qml b/interface/resources/qml/controls-uit/SpinBox.qml index be6dcdc7ee..ec7821851f 100755 --- a/interface/resources/qml/controls-uit/SpinBox.qml +++ b/interface/resources/qml/controls-uit/SpinBox.qml @@ -35,7 +35,6 @@ SpinBox { style: SpinBoxStyle { id: spinStyle background: Rectangle { - id: backgrondRec color: isLightColorScheme ? (spinBox.focus ? hifi.colors.white : hifi.colors.lightGray) : (spinBox.focus ? hifi.colors.black : hifi.colors.baseGrayShadow) diff --git a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml index 8e5b377521..01be4ddbde 100755 --- a/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml +++ b/interface/resources/qml/hifi/dialogs/AttachmentsDialog.qml @@ -11,7 +11,7 @@ import "attachments" Window { id: root - title: "Attachments Dialog" + title: "Attachments" objectName: "AttachmentsDialog" width: 600 height: 600 @@ -55,11 +55,19 @@ Window { color: hifi.colors.baseGrayShadow radius: 4 - ScrollView{ + ScrollView { id: scrollView anchors.fill: parent anchors.margins: 4 + style: ScrollViewStyle { + + padding { + top: 0 + right: 0 + bottom: 0 + } + decrementControl: Item { visible: false } @@ -69,18 +77,29 @@ Window { scrollBarBackground: Rectangle{ implicitWidth: 14 color: hifi.colors.baseGray - anchors.left: attachmentDelegate.right - anchors.leftMargin: 5 - radius: 3 + radius: 4 + Rectangle { + // Make top left corner of scrollbar appear square + width: 8 + height: 4 + color: hifi.colors.baseGray + anchors.top: parent.top + anchors.horizontalCenter: parent.left + } + } handle: Rectangle { implicitWidth: 8 - anchors.left: parent.left - anchors.leftMargin: 3 - anchors.top: parent.top - anchors.bottom: parent.bottom - radius: 3 + anchors { + left: parent.left + leftMargin: 3 + top: parent.top + topMargin: 3 + bottom: parent.bottom + bottomMargin: 4 + } + radius: 4 color: hifi.colors.lightGrayText } } @@ -134,12 +153,12 @@ Window { spacing: 8 anchors { right: parent.right; bottom: parent.bottom; margins: 8 } HifiControls.Button { - action: cancelAction + action: okAction color: hifi.buttons.black colorScheme: hifi.colorSchemes.dark } HifiControls.Button { - action: okAction + action: cancelAction color: hifi.buttons.black colorScheme: hifi.colorSchemes.dark } diff --git a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml index 0db6bb4875..1277c459ce 100755 --- a/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Attachment.qml @@ -36,7 +36,7 @@ Item { Item { height: modelChooserButton.height + urlLabel.height + 4 anchors { left: parent.left; right: parent.right;} - HifiControls.Label { id: urlLabel; color: hifi.colors.lightGrayText; text: "Model URL:"; anchors.top: parent.top;} + HifiControls.Label { id: urlLabel; color: hifi.colors.lightGrayText; text: "Model URL"; anchors.top: parent.top;} HifiControls.TextField { id: modelUrl; height: jointChooser.height; @@ -57,12 +57,12 @@ Item { colorScheme: hifi.colorSchemes.dark anchors { right: parent.right; verticalCenter: modelUrl.verticalCenter } Component { - id: modelBrowserBuiler; + id: modelBrowserBuilder; ModelBrowserDialog {} } onClicked: { - var browser = modelBrowserBuiler.createObject(desktop); + var browser = modelBrowserBuilder.createObject(desktop); browser.selected.connect(function(newModelUrl){ modelUrl.text = newModelUrl; }) @@ -75,7 +75,7 @@ Item { anchors { left: parent.left; right: parent.right; } HifiControls.Label { id: jointLabel; - text: "Joint:"; + text: "Joint"; color: hifi.colors.lightGrayText; anchors.top: parent.top } @@ -97,7 +97,7 @@ Item { Item { height: translation.height + translationLabel.height + 4 anchors { left: parent.left; right: parent.right; } - HifiControls.Label { id: translationLabel; color: hifi.colors.lightGrayText; text: "Translation:"; anchors.top: parent.top; } + HifiControls.Label { id: translationLabel; color: hifi.colors.lightGrayText; text: "Translation"; anchors.top: parent.top; } Translation { id: translation; anchors { left: parent.left; right: parent.right; bottom: parent.bottom} @@ -114,7 +114,7 @@ Item { Item { height: rotation.height + rotationLabel.height + 4 anchors { left: parent.left; right: parent.right; } - HifiControls.Label { id: rotationLabel; color: hifi.colors.lightGrayText; text: "Rotation:"; anchors.top: parent.top; } + HifiControls.Label { id: rotationLabel; color: hifi.colors.lightGrayText; text: "Rotation"; anchors.top: parent.top; } Rotation { id: rotation; anchors { left: parent.left; right: parent.right; bottom: parent.bottom; } @@ -129,15 +129,15 @@ Item { } Item { - height: scaleItem.height - anchors {left: parent.left; right: parent.right;} + height: scaleItem.height + anchors { left: parent.left; right: parent.right; } Item { - id: scaleItem + id: scaleItem height: scaleSpinner.height + scaleLabel.height + 4 - width: parent.width - isSoftItem.width - anchors { left: isSoftItem.right; right: parent.right; } - HifiControls.Label { id: scaleLabel; color: hifi.colors.lightGrayText; text: "Scale:"; anchors.top: parent.top; } + width: parent.width / 3 - 8 + anchors { right: parent.right; } + HifiControls.Label { id: scaleLabel; color: hifi.colors.lightGrayText; text: "Scale"; anchors.top: parent.top; } HifiControls.SpinBox { id: scaleSpinner; anchors { left: parent.left; right: parent.right; bottom: parent.bottom; } @@ -158,13 +158,18 @@ Item { Item { id: isSoftItem - height: soft.height - width: parent.width * 0.2 - anchors { left: parent.left; bottom: parent.bottom } - HifiControls.Label { id: softLabel; color: hifi.colors.lightGrayText; text: "Is soft"; anchors.left: soft.right; anchors.leftMargin: 8; } + height: scaleSpinner.height + anchors { + left: parent.left + bottom: parent.bottom + } HifiControls.CheckBox { - id: soft; - anchors { left: parent.left; bottom: parent.bottom;} + id: soft + text: "Is soft" + anchors { + left: parent.left + verticalCenter: parent.verticalCenter + } checked: attachment ? attachment.soft : false colorScheme: hifi.colorSchemes.dark onCheckedChanged: { diff --git a/interface/resources/qml/hifi/dialogs/attachments/Translation.qml b/interface/resources/qml/hifi/dialogs/attachments/Translation.qml index f3a90cdf94..39ac6da55a 100644 --- a/interface/resources/qml/hifi/dialogs/attachments/Translation.qml +++ b/interface/resources/qml/hifi/dialogs/attachments/Translation.qml @@ -1,7 +1,7 @@ import "." Vector3 { - decimals: 2; + decimals: 3; stepSize: 0.01; maximumValue: 10 minimumValue: -10