diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 3a3176b78d..eefb654737 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -295,7 +295,7 @@ void AvatarMixer::broadcastAvatarData() { avatarPacketList.startSegment(); numAvatarDataBytes += avatarPacketList.write(otherNode->getUUID().toRfc4122()); - numAvatarDataBytes += avatarPacketList.write(otherAvatar.toByteArray()); + numAvatarDataBytes += avatarPacketList.write(otherAvatar.toByteArray(false)); avatarPacketList.endSegment(); diff --git a/assignment-client/src/avatars/ScriptableAvatar.cpp b/assignment-client/src/avatars/ScriptableAvatar.cpp index 3d243d78ec..0b7af01c94 100644 --- a/assignment-client/src/avatars/ScriptableAvatar.cpp +++ b/assignment-client/src/avatars/ScriptableAvatar.cpp @@ -77,10 +77,7 @@ void ScriptableAvatar::update(float deltatime) { int mapping = animationJoints.indexOf(modelJoints[i]); if (mapping != -1 && !_maskedJoints.contains(modelJoints[i])) { JointData& data = _jointData[i]; - data.valid = true; data.rotation = safeMix(floorFrame.rotations.at(i), ceilFrame.rotations.at(i), frameFraction); - } else { - _jointData[i].valid = false; } } } else { diff --git a/examples/html/entityList.html b/examples/html/entityList.html index 62bbbd08a6..2e3fdb1874 100644 --- a/examples/html/entityList.html +++ b/examples/html/entityList.html @@ -20,7 +20,9 @@ elRefresh = document.getElementById("refresh"); elDelete = document.getElementById("delete"); elTeleport = document.getElementById("teleport"); + elRadius = document.getElementById("radius"); elNoEntitiesMessage = document.getElementById("no-entities"); + elNoEntitiesRadius = document.getElementById("no-entities-radius"); document.getElementById("entity-name").onclick = function() { setSortColumn('name'); @@ -186,6 +188,13 @@ } }, false); + elRadius.onchange = function () { + elRadius.value = Math.max(elRadius.value, 0); + EventBridge.emitWebEvent(JSON.stringify({ type: 'radius', radius: elRadius.value })); + refreshEntities(); + elNoEntitiesRadius.firstChild.nodeValue = elRadius.value; + } + if (window.EventBridge !== undefined) { EventBridge.scriptEventReceived.connect(function(data) { data = JSON.parse(data); @@ -218,14 +227,15 @@
- - - + + +
+  m
@@ -246,7 +256,7 @@
- No entities found within 50 meter radius. Try moving to a different location and refreshing. + No entities found within a 100 meter radius. Try moving to a different location and refreshing.
diff --git a/examples/html/style.css b/examples/html/style.css index e63b6338fc..3614ea821b 100644 --- a/examples/html/style.css +++ b/examples/html/style.css @@ -102,13 +102,23 @@ input[type=button] { } #search-area { - width: 100%; padding: 0.5em; box-sizing: border-box; + padding-right: 6em; } -#search-area input { - width: 100%; +#filter { + width: 99%; +} + +#radius-and-unit { + width: 6em; + float: right; + margin-right: -6em; +} + +#radius { + width: 4em; } textarea, input { diff --git a/examples/libraries/entityList.js b/examples/libraries/entityList.js index 0fd1cd5a06..66dc9f336f 100644 --- a/examples/libraries/entityList.js +++ b/examples/libraries/entityList.js @@ -4,6 +4,8 @@ EntityListTool = function(opts) { var url = Script.resolvePath('html/entityList.html'); var webView = new WebWindow('Entities', url, 200, 280, true); + var searchRadius = 100; + var visible = false; webView.setVisible(visible); @@ -33,7 +35,7 @@ EntityListTool = function(opts) { that.sendUpdate = function() { var entities = []; - var ids = Entities.findEntities(MyAvatar.position, 100); + var ids = Entities.findEntities(MyAvatar.position, searchRadius); for (var i = 0; i < ids.length; i++) { var id = ids[i]; var properties = Entities.getEntityProperties(id); @@ -80,6 +82,9 @@ EntityListTool = function(opts) { } } else if (data.type == "delete") { deleteSelectedEntities(); + } else if (data.type === "radius") { + searchRadius = data.radius; + that.sendUpdate(); } }); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index e7423336b1..55699bccbe 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -200,11 +200,9 @@ void Avatar::simulate(float deltaTime) { if (!_shouldRenderBillboard && inViewFrustum) { { PerformanceTimer perfTimer("skeleton"); - if (_hasNewJointRotations) { - for (int i = 0; i < _jointData.size(); i++) { - const JointData& data = _jointData.at(i); - _skeletonModel.setJointState(i, data.valid, data.rotation); - } + for (int i = 0; i < _jointData.size(); i++) { + const JointData& data = _jointData.at(i); + _skeletonModel.setJointState(i, true, data.rotation); } _skeletonModel.simulate(deltaTime, _hasNewJointRotations); simulateAttachments(deltaTime); @@ -784,8 +782,10 @@ Transform Avatar::calculateDisplayNameTransform(const ViewFrustum& frustum, floa void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, const glm::ivec4& viewport) const { bool shouldShowReceiveStats = DependencyManager::get()->shouldShowReceiveStats() && !isMyAvatar(); - // If we have nothing to draw, or it's tottaly transparent, return - if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f) { + // If we have nothing to draw, or it's totally transparent, or it's too close or behind the camera, return + const float CLIP_DISTANCE = 0.2f; + if ((_displayName.isEmpty() && !shouldShowReceiveStats) || _displayNameAlpha == 0.0f + || (glm::dot(frustum.getDirection(), getDisplayNamePosition() - frustum.getPosition()) <= CLIP_DISTANCE)) { return; } auto renderer = textRenderer(DISPLAYNAME); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 39d2637b9e..6939720f32 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -123,18 +123,18 @@ MyAvatar::~MyAvatar() { _lookAtTargetAvatar.reset(); } -QByteArray MyAvatar::toByteArray() { +QByteArray MyAvatar::toByteArray(bool cullSmallChanges) { CameraMode mode = Application::getInstance()->getCamera()->getMode(); if (mode == CAMERA_MODE_THIRD_PERSON || mode == CAMERA_MODE_INDEPENDENT) { // fake the avatar position that is sent up to the AvatarMixer glm::vec3 oldPosition = _position; _position = getSkeletonPosition(); - QByteArray array = AvatarData::toByteArray(); + QByteArray array = AvatarData::toByteArray(cullSmallChanges); // copy the correct position back _position = oldPosition; return array; } - return AvatarData::toByteArray(); + return AvatarData::toByteArray(cullSmallChanges); } void MyAvatar::reset() { @@ -220,7 +220,7 @@ void MyAvatar::simulate(float deltaTime) { _jointData.resize(_rig->getJointStateCount()); for (int i = 0; i < _jointData.size(); i++) { JointData& data = _jointData[i]; - data.valid = _rig->getJointStateRotation(i, data.rotation); + _rig->getJointStateRotation(i, data.rotation); } } diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 9e7ab11aa6..89f3b236f4 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -200,7 +200,7 @@ private: glm::vec3 getWorldBodyPosition() const; glm::quat getWorldBodyOrientation() const; - QByteArray toByteArray(); + QByteArray toByteArray(bool cullSmallChanges); void simulate(float deltaTime); void updateFromTrackers(float deltaTime); virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 9ef1f94c55..123c9707ba 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -31,6 +31,10 @@ quint64 DEFAULT_FILTERED_LOG_EXPIRY = 2 * USECS_PER_SECOND; +// this controls how large a change in joint-rotation must be before the interface sends it to the avatar mixer +const float MIN_ROTATION_DOT = 0.9999999f; + + using namespace std; const glm::vec3 DEFAULT_LOCAL_AABOX_CORNER(-0.5f); @@ -141,7 +145,7 @@ void AvatarData::setHandPosition(const glm::vec3& handPosition) { _handPosition = glm::inverse(getOrientation()) * (handPosition - _position); } -QByteArray AvatarData::toByteArray() { +QByteArray AvatarData::toByteArray(bool cullSmallChanges) { // TODO: DRY this up to a shared method // that can pack any type given the number of bytes // and return the number of bytes to push the pointer @@ -234,11 +238,19 @@ QByteArray AvatarData::toByteArray() { // joint data *destinationBuffer++ = _jointData.size(); + unsigned char* validityPosition = destinationBuffer; unsigned char validity = 0; int validityBit = 0; - foreach (const JointData& data, _jointData) { - if (data.valid) { - validity |= (1 << validityBit); + + _lastSentJointData.resize(_jointData.size()); + + // foreach (const JointData& data, _jointData) { + for (int i=0; i < _jointData.size(); i++) { + const JointData& data = _jointData.at(i); + if (_lastSentJointData[i].rotation != data.rotation) { + if (!cullSmallChanges || fabsf(glm::dot(data.rotation, _lastSentJointData[i].rotation)) <= MIN_ROTATION_DOT) { + validity |= (1 << validityBit); + } } if (++validityBit == BITS_IN_BYTE) { *destinationBuffer++ = validity; @@ -248,9 +260,18 @@ QByteArray AvatarData::toByteArray() { if (validityBit != 0) { *destinationBuffer++ = validity; } - foreach (const JointData& data, _jointData) { - if (data.valid) { + + validityBit = 0; + validity = *validityPosition++; + for (int i = 0; i < _jointData.size(); i ++) { + const JointData& data = _jointData[ i ]; + if (validity & (1 << validityBit)) { destinationBuffer += packOrientationQuatToBytes(destinationBuffer, data.rotation); + _lastSentJointData[i].rotation = data.rotation; + } + if (++validityBit == BITS_IN_BYTE) { + validityBit = 0; + validity = *validityPosition++; } } @@ -494,6 +515,10 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { } int numValidJoints = 0; _jointData.resize(numJoints); + + QVector valids; + valids.resize(numJoints); + { // validity bits unsigned char validity = 0; int validityBit = 0; @@ -505,7 +530,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { if (valid) { ++numValidJoints; } - _jointData[i].valid = valid; + valids[i] = valid; validityBit = (validityBit + 1) % BITS_IN_BYTE; } } @@ -527,7 +552,7 @@ int AvatarData::parseDataFromBuffer(const QByteArray& buffer) { { // joint data for (int i = 0; i < numJoints; i++) { JointData& data = _jointData[i]; - if (data.valid) { + if (valids[i]) { _hasNewJointRotations = true; sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, data.rotation); } @@ -731,7 +756,6 @@ void AvatarData::setJointData(int index, const glm::quat& rotation) { _jointData.resize(index + 1); } JointData& data = _jointData[index]; - data.valid = true; data.rotation = rotation; } @@ -746,7 +770,6 @@ void AvatarData::clearJointData(int index) { if (_jointData.size() <= index) { _jointData.resize(index + 1); } - _jointData[index].valid = false; } bool AvatarData::isJointDataValid(int index) const { @@ -759,7 +782,7 @@ bool AvatarData::isJointDataValid(int index) const { Q_RETURN_ARG(bool, result), Q_ARG(int, index)); return result; } - return index < _jointData.size() && _jointData.at(index).valid; + return index < _jointData.size(); } glm::quat AvatarData::getJointRotation(int index) const { @@ -1060,7 +1083,7 @@ void AvatarData::setJointMappingsFromNetworkReply() { void AvatarData::sendAvatarDataPacket() { auto nodeList = DependencyManager::get(); - QByteArray avatarByteArray = toByteArray(); + QByteArray avatarByteArray = toByteArray(true); auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size()); avatarPacket->write(avatarByteArray); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 8bb874bc71..278ec2047c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -171,7 +171,7 @@ public: glm::vec3 getHandPosition() const; void setHandPosition(const glm::vec3& handPosition); - virtual QByteArray toByteArray(); + virtual QByteArray toByteArray(bool cullSmallChanges); /// \return true if an error should be logged bool shouldLogError(const quint64& now); @@ -357,6 +357,7 @@ protected: char _handState; QVector _jointData; ///< the state of the skeleton joints + QVector _lastSentJointData; ///< the state of the skeleton joints last time we transmitted // key state KeyState _keyState; @@ -408,7 +409,6 @@ Q_DECLARE_METATYPE(AvatarData*) class JointData { public: - bool valid; glm::quat rotation; }; diff --git a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp index c6cc8a404b..579fddcd63 100644 --- a/libraries/input-plugins/src/input-plugins/SixenseManager.cpp +++ b/libraries/input-plugins/src/input-plugins/SixenseManager.cpp @@ -34,6 +34,8 @@ Q_LOGGING_CATEGORY(inputplugins, "hifi.inputplugins") const unsigned int LEFT_MASK = 0; const unsigned int RIGHT_MASK = 1U << 1; +#ifdef HAVE_SIXENSE + const int CALIBRATION_STATE_IDLE = 0; const int CALIBRATION_STATE_X = 1; const int CALIBRATION_STATE_Y = 2; @@ -47,11 +49,15 @@ const float NECK_Z = 0.3f; // meters const float CONTROLLER_THRESHOLD = 0.35f; +#endif + #ifdef __APPLE__ typedef int (*SixenseBaseFunction)(); typedef int (*SixenseTakeIntFunction)(int); +#ifdef HAVE_SIXENSE typedef int (*SixenseTakeIntAndSixenseControllerData)(int, sixenseControllerData*); #endif +#endif const QString SixenseManager::NAME = "Sixense"; diff --git a/libraries/networking/src/udt/PacketHeaders.cpp b/libraries/networking/src/udt/PacketHeaders.cpp index 737e827c90..e9eca409e6 100644 --- a/libraries/networking/src/udt/PacketHeaders.cpp +++ b/libraries/networking/src/udt/PacketHeaders.cpp @@ -69,7 +69,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) { case EntityData: return VERSION_ENTITIES_POLYVOX_NEIGHBORS; case AvatarData: - return 12; + return 13; default: return 11; } diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index b42daa710a..aa395b1b06 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -599,7 +599,7 @@ void ScriptEngine::run() { / (1000 * 1000)) + 0.5); const int SCRIPT_AUDIO_BUFFER_BYTES = SCRIPT_AUDIO_BUFFER_SAMPLES * sizeof(int16_t); - QByteArray avatarByteArray = _avatarData->toByteArray(); + QByteArray avatarByteArray = _avatarData->toByteArray(true); auto avatarPacket = NLPacket::create(PacketType::AvatarData, avatarByteArray.size()); avatarPacket->write(avatarByteArray);