From c9868640c115c69ed8e5d1343c1daed298768d12 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Wed, 10 May 2017 18:14:50 -0700 Subject: [PATCH 1/9] force data in MemoryStorage to be word aligned to avoid crash in glTextureSubImage2D --- .../src/avatars-renderer/OtherAvatar.h | 2 +- libraries/shared/src/SimpleMovingAverage.h | 2 +- libraries/shared/src/shared/Storage.cpp | 5 +++-- libraries/shared/src/shared/Storage.h | 13 ++++++++----- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h b/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h index 2f6c9a38aa..22a7e1863a 100644 --- a/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h +++ b/libraries/avatars-renderer/src/avatars-renderer/OtherAvatar.h @@ -14,7 +14,7 @@ class OtherAvatar : public Avatar { public: explicit OtherAvatar(QThread* thread, RigPointer rig = nullptr); - void instantiableAvatar() {}; + virtual void instantiableAvatar() override {}; }; #endif // hifi_OtherAvatar_h diff --git a/libraries/shared/src/SimpleMovingAverage.h b/libraries/shared/src/SimpleMovingAverage.h index 0404ab9646..3855375f4c 100644 --- a/libraries/shared/src/SimpleMovingAverage.h +++ b/libraries/shared/src/SimpleMovingAverage.h @@ -71,7 +71,7 @@ public: void addSample(T sample) { if (numSamples > 0) { - average = (sample * WEIGHTING) + (average * ONE_MINUS_WEIGHTING); + average = (sample * (T)WEIGHTING) + (average * (T)ONE_MINUS_WEIGHTING); } else { average = sample; } diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index aae1f8455f..46c631c72a 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -38,8 +38,9 @@ StoragePointer Storage::toFileStorage(const QString& filename) const { return FileStorage::create(filename, size(), data()); } -MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) { - _data.resize(size); +MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) : _size(size) { + _data.resize((size + 3) / 4); // alloc smallest number of 4-byte chunks that will cover size bytes + if (data) { memcpy(_data.data(), data, size); } diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index da5b773d52..e0519c98f6 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -41,13 +41,16 @@ namespace storage { class MemoryStorage : public Storage { public: MemoryStorage(size_t size, const uint8_t* data = nullptr); - const uint8_t* data() const override { return _data.data(); } - uint8_t* data() { return _data.data(); } - uint8_t* mutableData() override { return _data.data(); } - size_t size() const override { return _data.size(); } + const uint8_t* data() const override { return reinterpret_cast(_data.data()); } + uint8_t* data() { return reinterpret_cast(_data.data()); } + uint8_t* mutableData() override { return reinterpret_cast(_data.data()); } + + size_t _size { 0 }; + size_t size() const override { return _size; } operator bool() const override { return true; } private: - std::vector _data; + // the vector is of uint32_t rather than uint8_t to force alignment + std::vector _data; }; class FileStorage : public Storage { From dfb9fecf17181f4245b1d5cced535a846445600b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 11 May 2017 07:11:40 -0700 Subject: [PATCH 2/9] pad MemoryStorage size to multiple of 4 rather than using a vector of uint32_t -- this gets the same alignment without needs casts --- libraries/shared/src/shared/Storage.cpp | 5 +++-- libraries/shared/src/shared/Storage.h | 9 ++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index 46c631c72a..ec29a8d7f8 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -39,8 +39,9 @@ StoragePointer Storage::toFileStorage(const QString& filename) const { } MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) : _size(size) { - _data.resize((size + 3) / 4); // alloc smallest number of 4-byte chunks that will cover size bytes - + // alloc smallest number of 4-byte chunks that will cover size bytes. The buffer is padded out to a multiple + // of 4 to force an alignment that glTextureSubImage2D can later use. + _data.resize((size + 3) & ~0x3); if (data) { memcpy(_data.data(), data, size); } diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index e0519c98f6..f51d95a95a 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -41,16 +41,15 @@ namespace storage { class MemoryStorage : public Storage { public: MemoryStorage(size_t size, const uint8_t* data = nullptr); - const uint8_t* data() const override { return reinterpret_cast(_data.data()); } - uint8_t* data() { return reinterpret_cast(_data.data()); } - uint8_t* mutableData() override { return reinterpret_cast(_data.data()); } + const uint8_t* data() const override { return _data.data(); } + uint8_t* data() { return _data.data(); } + uint8_t* mutableData() override { return _data.data(); } size_t _size { 0 }; size_t size() const override { return _size; } operator bool() const override { return true; } private: - // the vector is of uint32_t rather than uint8_t to force alignment - std::vector _data; + std::vector _data; }; class FileStorage : public Storage { From a26f9c788744d621d7f4f3d1d8df156bd5f8892b Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 11 May 2017 13:36:05 -0700 Subject: [PATCH 3/9] make _size const --- libraries/shared/src/shared/Storage.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index f51d95a95a..ed1c1dd0f3 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -45,7 +45,7 @@ namespace storage { uint8_t* data() { return _data.data(); } uint8_t* mutableData() override { return _data.data(); } - size_t _size { 0 }; + const size_t _size; size_t size() const override { return _size; } operator bool() const override { return true; } private: From ac2bc39a27ca30ff9b95b549b78fa5d3193b9487 Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 11 May 2017 14:10:03 -0700 Subject: [PATCH 4/9] try, try again --- libraries/shared/src/shared/Storage.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index ec29a8d7f8..6a6393ff73 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -39,9 +39,11 @@ StoragePointer Storage::toFileStorage(const QString& filename) const { } MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) : _size(size) { - // alloc smallest number of 4-byte chunks that will cover size bytes. The buffer is padded out to a multiple - // of 4 to force an alignment that glTextureSubImage2D can later use. - _data.resize((size + 3) & ~0x3); + // we end up calling glCompressedTextureSubImage2D with this, and the rows of the image are expected + // to be word aligned. This is fine in all cases except for 1x1 images and 2x2 images. For 1x1, + // there is only one row, so the problem is avoided. For 2x2, we add 2 extra bytes so there's + // room for the second row. + _data.resize(size == 4 ? 6 : size); if (data) { memcpy(_data.data(), data, size); } From 52c288bfed215e817081542302a3b4766a2f0da2 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 11 May 2017 14:20:42 -0700 Subject: [PATCH 5/9] Desktop users of different height can shake hands --- scripts/system/makeUserConnection.js | 36 ++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/scripts/system/makeUserConnection.js b/scripts/system/makeUserConnection.js index a8afad2e1c..37a334bd70 100644 --- a/scripts/system/makeUserConnection.js +++ b/scripts/system/makeUserConnection.js @@ -198,7 +198,7 @@ } var animationData = {}; - function updateAnimationData() { + function updateAnimationData(verticalOffset) { // all we are doing here is moving the right hand to a spot // that is in front of and a bit above the hips. Basing how // far in front as scaling with the avatar's height (say hips @@ -209,6 +209,9 @@ offset = 0.8 * MyAvatar.getAbsoluteJointTranslationInObjectFrame(headIndex).y; } animationData.rightHandPosition = Vec3.multiply(offset, {x: -0.25, y: 0.8, z: 1.3}); + if (verticalOffset) { + animationData.rightHandPosition.y += verticalOffset; + } animationData.rightHandRotation = Quat.fromPitchYawRollDegrees(90, 0, 90); } function shakeHandsAnimation() { @@ -347,7 +350,32 @@ } return false; } - + function findNearestAvatar() { + // We only look some max distance away (much larger than the handshake distance, but still...) + var minDistance = MAX_AVATAR_DISTANCE * 20; + var closestAvatar; + AvatarList.getAvatarIdentifiers().forEach(function (id) { + var avatar = AvatarList.getAvatar(id); + if (avatar && avatar.sessionUUID != MyAvatar.sessionUUID) { + var currentDistance = Vec3.distance(avatar.position, MyAvatar.position); + if (minDistance > currentDistance) { + minDistance = currentDistance; + closestAvatar = avatar; + } + } + }); + return closestAvatar; + } + function adjustAnimationHeight() { + var avatar = findNearestAvatar(); + if (avatar) { + var myHeadIndex = MyAvatar.getJointIndex("Head"); + var otherHeadIndex = avatar.getJointIndex("Head"); + var diff = (avatar.getJointPosition(otherHeadIndex).y - MyAvatar.getJointPosition(myHeadIndex).y) / 2; + print("head height difference: " + diff); + updateAnimationData(diff); + } + } function findNearestWaitingAvatar() { var handPosition = getHandPosition(MyAvatar, currentHandJointIndex); var minDistance = MAX_AVATAR_DISTANCE; @@ -436,6 +464,10 @@ handStringMessageSend({ key: "waiting", }); + // potentially adjust height of handshake + if (fromKeyboard) { + adjustAnimationHeight(); + } lookForWaitingAvatar(); } } From 539aaf8c598d1ffde91fe402a5b9acfc314b90c5 Mon Sep 17 00:00:00 2001 From: Dante Ruiz Date: Thu, 11 May 2017 23:00:41 +0100 Subject: [PATCH 6/9] add debug statment and fixed sorting order --- plugins/openvr/src/ViveControllerManager.cpp | 19 +++++++++++++------ plugins/openvr/src/ViveControllerManager.h | 2 +- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/plugins/openvr/src/ViveControllerManager.cpp b/plugins/openvr/src/ViveControllerManager.cpp index e5cd7ffecc..8c357103c9 100644 --- a/plugins/openvr/src/ViveControllerManager.cpp +++ b/plugins/openvr/src/ViveControllerManager.cpp @@ -66,7 +66,7 @@ static glm::mat4 computeOffset(glm::mat4 defaultToReferenceMat, glm::mat4 defaul } static bool sortPucksYPosition(std::pair firstPuck, std::pair secondPuck) { - return (firstPuck.second.translation.y < firstPuck.second.translation.y); + return (firstPuck.second.translation.y < secondPuck.second.translation.y); } bool ViveControllerManager::isSupported() const { @@ -245,6 +245,7 @@ void ViveControllerManager::InputDevice::calibrateOrUncalibrate(const controller } void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibrationData& inputCalibration) { + qDebug() << "Puck Calibration: Starting..."; // convert the hmd head from sensor space to avatar space glm::mat4 hmdSensorFlippedMat = inputCalibration.hmdSensorMat * Matrices::Y_180; glm::mat4 sensorToAvatarMat = glm::inverse(inputCalibration.avatarMat) * inputCalibration.sensorToWorldMat; @@ -264,18 +265,24 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr glm::mat4 defaultToReferenceMat = currentHead * glm::inverse(inputCalibration.defaultHeadMat); int puckCount = (int)_validTrackedObjects.size(); + qDebug() << "Puck Calibration: " << puckCount << " pucks found for calibration"; _config = _preferedConfig; if (_config != Config::Auto && puckCount < MIN_PUCK_COUNT) { + qDebug() << "Puck Calibration: Failed: Could not meet the minimal # of pucks"; uncalibrate(); return; } else if (_config == Config::Auto){ if (puckCount == MIN_PUCK_COUNT) { _config = Config::Feet; + qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; } else if (puckCount == MIN_FEET_AND_HIPS) { _config = Config::FeetAndHips; + qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; } else if (puckCount >= MIN_FEET_HIPS_CHEST) { _config = Config::FeetHipsAndChest; + qDebug() << "Puck Calibration: Auto Config: " << configToString(_config) << " configuration"; } else { + qDebug() << "Puck Calibration: Auto Config Failed: Could not meet the minimal # of pucks"; uncalibrate(); return; } @@ -283,8 +290,6 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition); - - auto& firstFoot = _validTrackedObjects[FIRST_FOOT]; auto& secondFoot = _validTrackedObjects[SECOND_FOOT]; controller::Pose& firstFootPose = firstFoot.second; @@ -314,10 +319,12 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr _jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first; _pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second); } else { + qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks"; uncalibrate(); return; } _calibrated = true; + qDebug() << "PuckCalibration: " << configToString(_config) << " Configuration Successful"; } void ViveControllerManager::InputDevice::uncalibrate() { @@ -575,9 +582,9 @@ void ViveControllerManager::InputDevice::saveSettings() const { settings.endGroup(); } -QString ViveControllerManager::InputDevice::configToString() { +QString ViveControllerManager::InputDevice::configToString(Config config) { QString currentConfig; - switch (_preferedConfig) { + switch (config) { case Config::Auto: currentConfig = "Auto"; break; @@ -615,7 +622,7 @@ void ViveControllerManager::InputDevice::createPreferences() { static const QString VIVE_PUCKS_CONFIG = "Vive Pucks Configuration"; { - auto getter = [this]()->QString { return configToString(); }; + auto getter = [this]()->QString { return configToString(_preferedConfig); }; auto setter = [this](const QString& value) { setConfigFromString(value); saveSettings(); }; auto preference = new ComboBoxPreference(VIVE_PUCKS_CONFIG, "Configuration", getter, setter); QStringList list = (QStringList() << "Auto" << "Feet" << "FeetAndHips" << "FeetHipsAndChest"); diff --git a/plugins/openvr/src/ViveControllerManager.h b/plugins/openvr/src/ViveControllerManager.h index 9920fb003a..c2ebdc6144 100644 --- a/plugins/openvr/src/ViveControllerManager.h +++ b/plugins/openvr/src/ViveControllerManager.h @@ -126,7 +126,7 @@ private: bool _timeTilCalibrationSet { false }; mutable std::recursive_mutex _lock; - QString configToString(); + QString configToString(Config config); void setConfigFromString(const QString& value); void loadSettings(); void saveSettings() const; From ae5f9e4fb15e274aa9a143dfa101a5e6b1186730 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 11 May 2017 15:10:19 -0700 Subject: [PATCH 7/9] animate scroll of partially visible cards --- interface/resources/qml/hifi/Feed.qml | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index fc108f47e3..3fd28aadb8 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -238,8 +238,24 @@ Column { stackShadowNarrowing: root.stackShadowNarrowing; shadowHeight: root.stackedCardShadowHeight; - hoverThunk: function () { scroll.currentIndex = index; } - unhoverThunk: function () { scroll.currentIndex = -1; } + hoverThunk: function () { scrollToIndex(index); } + unhoverThunk: function () { scrollToIndex(-1); } } } + NumberAnimation { + id: anim; + target: scroll; + property: "contentX"; + duration: 500; + } + function scrollToIndex(index) { + anim.running = false; + var pos = scroll.contentX; + var destPos; + scroll.positionViewAtIndex(index, ListView.Contain); + destPos = scroll.contentX; + anim.from = pos; + anim.to = destPos; + anim.running = true; + } } From 4aa683363c56673c3bc7709b7fc1dcc58f0e59ba Mon Sep 17 00:00:00 2001 From: Seth Alves Date: Thu, 11 May 2017 16:22:12 -0700 Subject: [PATCH 8/9] back out previous changes, do compressionOptions.setPitchAlignment(4) instead --- libraries/image/src/image/Image.cpp | 6 ++++++ libraries/shared/src/shared/Storage.cpp | 8 ++------ libraries/shared/src/shared/Storage.h | 4 +--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/libraries/image/src/image/Image.cpp b/libraries/image/src/image/Image.cpp index 68add428c1..32184dfe79 100644 --- a/libraries/image/src/image/Image.cpp +++ b/libraries/image/src/image/Image.cpp @@ -383,6 +383,7 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { } else if (mipFormat == gpu::Element::COLOR_RGBA_32) { compressionOptions.setFormat(nvtt::Format_RGBA); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(32, 0x000000FF, 0x0000FF00, @@ -393,6 +394,7 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { } else if (mipFormat == gpu::Element::COLOR_BGRA_32) { compressionOptions.setFormat(nvtt::Format_RGBA); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(32, 0x00FF0000, 0x0000FF00, @@ -403,6 +405,7 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { } else if (mipFormat == gpu::Element::COLOR_SRGBA_32) { compressionOptions.setFormat(nvtt::Format_RGBA); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(32, 0x000000FF, 0x0000FF00, @@ -411,6 +414,7 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { } else if (mipFormat == gpu::Element::COLOR_SBGRA_32) { compressionOptions.setFormat(nvtt::Format_RGBA); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(32, 0x00FF0000, 0x0000FF00, @@ -419,11 +423,13 @@ void generateMips(gpu::Texture* texture, QImage& image, int face = -1) { } else if (mipFormat == gpu::Element::COLOR_R_8) { compressionOptions.setFormat(nvtt::Format_RGB); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(8, 0, 0, 0); } else if (mipFormat == gpu::Element::VEC2NU8_XY) { inputOptions.setNormalMap(true); compressionOptions.setFormat(nvtt::Format_RGBA); compressionOptions.setPixelType(nvtt::PixelType_UnsignedNorm); + compressionOptions.setPitchAlignment(4); compressionOptions.setPixelFormat(8, 8, 0, 0); } else { qCWarning(imagelogging) << "Unknown mip format"; diff --git a/libraries/shared/src/shared/Storage.cpp b/libraries/shared/src/shared/Storage.cpp index 6a6393ff73..aae1f8455f 100644 --- a/libraries/shared/src/shared/Storage.cpp +++ b/libraries/shared/src/shared/Storage.cpp @@ -38,12 +38,8 @@ StoragePointer Storage::toFileStorage(const QString& filename) const { return FileStorage::create(filename, size(), data()); } -MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) : _size(size) { - // we end up calling glCompressedTextureSubImage2D with this, and the rows of the image are expected - // to be word aligned. This is fine in all cases except for 1x1 images and 2x2 images. For 1x1, - // there is only one row, so the problem is avoided. For 2x2, we add 2 extra bytes so there's - // room for the second row. - _data.resize(size == 4 ? 6 : size); +MemoryStorage::MemoryStorage(size_t size, const uint8_t* data) { + _data.resize(size); if (data) { memcpy(_data.data(), data, size); } diff --git a/libraries/shared/src/shared/Storage.h b/libraries/shared/src/shared/Storage.h index ed1c1dd0f3..da5b773d52 100644 --- a/libraries/shared/src/shared/Storage.h +++ b/libraries/shared/src/shared/Storage.h @@ -44,9 +44,7 @@ namespace storage { const uint8_t* data() const override { return _data.data(); } uint8_t* data() { return _data.data(); } uint8_t* mutableData() override { return _data.data(); } - - const size_t _size; - size_t size() const override { return _size; } + size_t size() const override { return _data.size(); } operator bool() const override { return true; } private: std::vector _data; From a9716313be317edfa72cdf10495e94a556cd9419 Mon Sep 17 00:00:00 2001 From: David Kelly Date: Thu, 11 May 2017 17:02:37 -0700 Subject: [PATCH 9/9] cr feedback -- really good feedback in fact --- interface/resources/qml/hifi/Feed.qml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/resources/qml/hifi/Feed.qml b/interface/resources/qml/hifi/Feed.qml index 3fd28aadb8..c1bd35f49d 100644 --- a/interface/resources/qml/hifi/Feed.qml +++ b/interface/resources/qml/hifi/Feed.qml @@ -246,7 +246,7 @@ Column { id: anim; target: scroll; property: "contentX"; - duration: 500; + duration: 250; } function scrollToIndex(index) { anim.running = false; @@ -256,6 +256,7 @@ Column { destPos = scroll.contentX; anim.from = pos; anim.to = destPos; + scroll.currentIndex = index; anim.running = true; } }