From d811660ed6f0da1574aadb2d114f1649ae84eb81 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 9 Dec 2015 11:07:10 -0800 Subject: [PATCH 01/38] DO NOT MERGE - Testing PR environment --- README.md | 2 ++ cmake/modules/FindOpenSSL.cmake | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index a2eb058ae6..7741445842 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +### TESTING BUILD - DO NOT MERGE ### + High Fidelity (hifi) is an early-stage technology lab experimenting with Virtual Worlds and VR. In this repository you'll find the source to many of the components in our diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 9d9557ad9e..6893948d01 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -256,6 +256,7 @@ if (WIN32) # For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this # but for now resorting to the following interm solution if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) + message(STATUS "*********** Copying SSL DLL from ${OPENSSL_DLL_PATH}/ssleay32.dll") add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/ From 8e7a2ac5362349aab0c0af4a697733b79a6e493e Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Tue, 15 Dec 2015 15:41:36 -0800 Subject: [PATCH 02/38] Exposing emmisive property of the Image3DOverlay --- interface/src/ui/overlays/Image3DOverlay.cpp | 18 ++++++++++++++---- interface/src/ui/overlays/Image3DOverlay.h | 1 + 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 11fb647f01..6e4c274943 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -26,14 +26,16 @@ QString const Image3DOverlay::TYPE = "image3d"; Image3DOverlay::Image3DOverlay() { - _isLoaded = false; + _isLoaded = false; + _emmisive = false; } Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : Billboard3DOverlay(image3DOverlay), _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), - _fromImage(image3DOverlay->_fromImage) + _fromImage(image3DOverlay->_fromImage), + _emmisive(image3DOverlay->_emmisive) { } @@ -93,8 +95,8 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - - DependencyManager::get()->bindSimpleProgram(*batch, true, false, false, true); + + DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emmisive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -144,6 +146,11 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) { setClipFromSource(subImageRect); } } + + QScriptValue emmisiveValue = properties.property("emmisive"); + if (emmisiveValue.isValid()) { + _emmisive = emmisiveValue.toBool(); + } } QScriptValue Image3DOverlay::getProperty(const QString& property) { @@ -156,6 +163,9 @@ QScriptValue Image3DOverlay::getProperty(const QString& property) { if (property == "offsetPosition") { return vec3toScriptValue(_scriptEngine, getOffsetPosition()); } + if (property == "emmisive") { + return _emmisive; + } return Billboard3DOverlay::getProperty(property); } diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index f848023fbe..0e40c73619 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -46,6 +46,7 @@ public: private: QString _url; NetworkTexturePointer _texture; + bool _emmisive; QRect _fromImage; // where from in the image to sample }; From e9f52b12116ea4e67c2c083dae73cb6002e6fdd5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 14:40:30 -0800 Subject: [PATCH 03/38] properly scale avatar collision shape --- interface/src/Application.cpp | 5 +- interface/src/avatar/Avatar.cpp | 76 +++++++++++-------- interface/src/avatar/Avatar.h | 12 +-- interface/src/avatar/AvatarManager.cpp | 26 +++---- interface/src/avatar/AvatarMotionState.h | 2 +- interface/src/avatar/Hand.cpp | 6 +- interface/src/avatar/MyAvatar.cpp | 46 +++++++---- interface/src/avatar/MyAvatar.h | 5 +- .../src/avatar/MyCharacterController.cpp | 2 +- interface/src/avatar/SkeletonModel.cpp | 2 +- interface/src/ui/ApplicationCompositor.cpp | 2 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/src/ui/overlays/OverlaysPayload.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 2 +- 14 files changed, 108 insertions(+), 82 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 930d3b0b8f..c34d2ce649 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1260,15 +1260,14 @@ void Application::paintGL() { hmdOffset.x = -hmdOffset.x; _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror + mirrorBodyOrientation * hmdOffset); - } else { _myCamera.setRotation(myAvatar->getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f))); _myCamera.setPosition(myAvatar->getDefaultEyePosition() - + glm::vec3(0, _raiseMirror * myAvatar->getAvatarScale(), 0) + + glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0) + (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) * glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); } diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 7a234f2b47..8231d1ebdd 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -99,7 +99,8 @@ Avatar::Avatar(RigPointer rig) : // we may have been created in the network thread, but we live in the main thread moveToThread(qApp->thread()); - setAvatarScale(1.0f); + setScale(glm::vec3(1.0f)); // avatar scale is uniform + // give the pointer to our head to inherited _headData variable from AvatarData _headData = static_cast(new Head(this)); _handData = static_cast(new Hand(this)); @@ -143,15 +144,28 @@ AABox Avatar::getBounds() const { float Avatar::getLODDistance() const { return DependencyManager::get()->getAvatarLODDistanceMultiplier() * - glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getAvatarScale(); + glm::distance(qApp->getCamera()->getPosition(), getPosition()) / getUniformScale(); +} + +void Avatar::animateScaleChanges(float deltaTime) { + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform + rebuildCollisionShape(); + } } void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - setAvatarScale(_targetScale); - } + animateScaleChanges(deltaTime); // update the billboard render flag const float BILLBOARD_HYSTERESIS_PROPORTION = 0.1f; @@ -164,7 +178,7 @@ void Avatar::simulate(float deltaTime) { _shouldRenderBillboard = true; qCDebug(interfaceapp) << "Billboarding" << (isMyAvatar() ? "myself" : getSessionUUID()) << "for LOD" << getLODDistance(); } - + const bool isControllerLogging = DependencyManager::get()->getRenderDistanceControllerIsLogging(); float renderDistance = DependencyManager::get()->getRenderDistance(); const float SKIP_HYSTERESIS_PROPORTION = isControllerLogging ? 0.0f : BILLBOARD_HYSTERESIS_PROPORTION; @@ -210,7 +224,7 @@ void Avatar::simulate(float deltaTime) { _skeletonModel.getHeadPosition(headPosition); Head* head = getHead(); head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, false, _shouldRenderBillboard); } } @@ -238,12 +252,12 @@ void Avatar::simulate(float deltaTime) { measureMotionDerivatives(deltaTime); } -bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) { +bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const { const float HEAD_SPHERE_RADIUS = 0.1f; glm::vec3 theirLookAt = dynamic_pointer_cast(avatar)->getHead()->getLookAtPosition(); glm::vec3 myEyePosition = getHead()->getEyePosition(); - return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getAvatarScale()); + return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getUniformScale()); } void Avatar::slamPosition(const glm::vec3& newPosition) { @@ -423,7 +437,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { const float BASE_LIGHT_DISTANCE = 2.0f; const float LIGHT_EXPONENT = 1.0f; const float LIGHT_CUTOFF = glm::radians(80.0f); - float distance = BASE_LIGHT_DISTANCE * getAvatarScale(); + float distance = BASE_LIGHT_DISTANCE * getUniformScale(); glm::vec3 position = glm::mix(_skeletonModel.getTranslation(), getHead()->getFaceModel().getTranslation(), 0.9f); glm::quat orientation = getOrientation(); foreach (const AvatarManager::LocalLight& light, DependencyManager::get()->getLocalLights()) { @@ -479,7 +493,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); position = getHead()->getRightEyePosition(); @@ -489,7 +503,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { eyeDiameter = DEFAULT_EYE_DIAMETER; } DependencyManager::get()->renderSolidSphereInstance(batch, - Transform(transform).postScale(eyeDiameter * getAvatarScale() / 2.0f + RADIUS_INCREMENT), + Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT), glm::vec4(LOOKING_AT_ME_COLOR, alpha)); } @@ -590,9 +604,9 @@ void Avatar::simulateAttachments(float deltaTime) { glm::quat jointRotation; if (_skeletonModel.getJointPositionInWorldFrame(jointIndex, jointPosition) && _skeletonModel.getJointRotationInWorldFrame(jointIndex, jointRotation)) { - model->setTranslation(jointPosition + jointRotation * attachment.translation * getAvatarScale()); + model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale()); model->setRotation(jointRotation * attachment.rotation); - model->setScaleToFit(true, getAvatarScale() * attachment.scale, true); // hack to force rescale + model->setScaleToFit(true, getUniformScale() * attachment.scale, true); // hack to force rescale model->setSnapModelToCenter(false); // hack to force resnap model->setSnapModelToCenter(true); model->simulate(deltaTime); @@ -647,7 +661,7 @@ void Avatar::renderBillboard(RenderArgs* renderArgs) { } float Avatar::getBillboardSize() const { - return getAvatarScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); + return getUniformScale() * BILLBOARD_DISTANCE * glm::tan(glm::radians(BILLBOARD_FIELD_OF_VIEW / 2.0f)); } #ifdef DEBUG @@ -796,7 +810,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& frustum, co } void Avatar::setSkeletonOffset(const glm::vec3& offset) { - const float MAX_OFFSET_LENGTH = getAvatarScale() * 0.5f; + const float MAX_OFFSET_LENGTH = getUniformScale() * 0.5f; float offsetLength = glm::length(offset); if (offsetLength > MAX_OFFSET_LENGTH) { _skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset; @@ -905,7 +919,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const { void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const { //Scale a world space vector as if it was relative to the position - positionToScale = getPosition() + getAvatarScale() * (positionToScale - getPosition()); + positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition()); } void Avatar::setFaceModelURL(const QUrl& faceModelURL) { @@ -945,7 +959,7 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { for (int i = 0; i < attachmentData.size(); i++) { _attachmentModels[i]->setURL(attachmentData.at(i).modelURL); _attachmentModels[i]->setSnapModelToCenter(true); - _attachmentModels[i]->setScaleToFit(true, getAvatarScale() * _attachmentData.at(i).scale); + _attachmentModels[i]->setScaleToFit(true, getUniformScale() * _attachmentData.at(i).scale); } } @@ -1033,15 +1047,6 @@ void Avatar::renderJointConnectingCone(gpu::Batch& batch, glm::vec3 position1, g } } -void Avatar::setAvatarScale(float scale) { - if (_targetScale * (1.0f - RESCALING_TOLERANCE) < scale && - scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) { - setScale(glm::vec3(_targetScale)); - } else { - setScale(glm::vec3(scale)); - } -} - float Avatar::getSkeletonHeight() const { Extents extents = _skeletonModel.getBindExtents(); return extents.maximum.y - extents.minimum.y; @@ -1053,7 +1058,7 @@ float Avatar::getHeadHeight() const { // HACK: We have a really odd case when fading out for some models where this value explodes float result = extents.maximum.y - extents.minimum.y; - if (result >= 0.0f && result < 100.0f * getAvatarScale() ) { + if (result >= 0.0f && result < 100.0f * getUniformScale() ) { return result; } } @@ -1096,13 +1101,20 @@ void Avatar::setShowDisplayName(bool showDisplayName) { // virtual void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { - shapeInfo.setCapsuleY(_skeletonModel.getBoundingCapsuleRadius(), 0.5f * _skeletonModel.getBoundingCapsuleHeight()); - shapeInfo.setOffset(_skeletonModel.getBoundingCapsuleOffset()); + float uniformScale = getUniformScale(); + shapeInfo.setCapsuleY(uniformScale * _skeletonModel.getBoundingCapsuleRadius(), + 0.5f * uniformScale * _skeletonModel.getBoundingCapsuleHeight()); + shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } // virtual -void Avatar::rebuildSkeletonBody() { - DependencyManager::get()->updateAvatarPhysicsShape(this); +void Avatar::rebuildCollisionShape() { + if (_motionState) { + _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); + } else { + // adebug TODO: move most of updateAvatarPhysicsShape() to here + DependencyManager::get()->updateAvatarPhysicsShape(this); + } } glm::vec3 Avatar::getLeftPalmPosition() { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index cdb995efea..379ab8b627 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -36,7 +36,6 @@ namespace render { static const float SCALING_RATIO = .05f; static const float SMOOTHING_RATIO = .05f; // 0 < ratio < 1 -static const float RESCALING_TOLERANCE = .02f; static const float BILLBOARD_FIELD_OF_VIEW = 30.0f; // degrees static const float BILLBOARD_DISTANCE = 5.56f; // meters @@ -89,7 +88,7 @@ public: SkeletonModel& getSkeletonModel() { return _skeletonModel; } const SkeletonModel& getSkeletonModel() const { return _skeletonModel; } glm::vec3 getChestPosition() const; - float getAvatarScale() const { return getScale().y; } + float getUniformScale() const { return getScale().y; } const Head* getHead() const { return static_cast(_headData); } Head* getHead() { return static_cast(_headData); } Hand* getHand() { return static_cast(_handData); } @@ -154,7 +153,7 @@ public: // (otherwise floating point error will cause problems at large positions). void applyPositionDelta(const glm::vec3& delta); - virtual void rebuildSkeletonBody(); + virtual void rebuildCollisionShape(); virtual void computeShapeInfo(ShapeInfo& shapeInfo); @@ -199,14 +198,15 @@ protected: float _stringLength; bool _moving; ///< set when position is changing - bool isLookingAtMe(AvatarSharedPointer avatar); - // protected methods... + bool isLookingAtMe(AvatarSharedPointer avatar) const; + + virtual void animateScaleChanges(float deltaTime); + glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getBodyUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; - void setAvatarScale(float scale); void measureMotionDerivatives(float deltaTime); float getSkeletonHeight() const; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 7c1a52f1b3..562bea3542 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -203,7 +203,7 @@ void AvatarManager::simulateAvatarFades(float deltaTime) { while (fadingIterator != _avatarFades.end()) { auto avatar = std::static_pointer_cast(*fadingIterator); avatar->startUpdate(); - avatar->setTargetScale(avatar->getAvatarScale() * SHRINK_RATE); + avatar->setTargetScale(avatar->getUniformScale() * SHRINK_RATE); if (avatar->getTargetScale() <= MIN_FADE_SCALE) { avatar->removeFromScene(*fadingIterator, scene, pendingChanges); fadingIterator = _avatarFades.erase(fadingIterator); @@ -375,19 +375,17 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - AvatarMotionState* motionState = avatar->getMotionState(); - if (motionState) { - motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - ShapeInfo shapeInfo; - avatar->computeShapeInfo(shapeInfo); - btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); - if (shape) { - AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); - avatar->setMotionState(motionState); - _motionStatesToAdd.insert(motionState); - _avatarMotionStates.insert(motionState); - } + // adebug TODO: move most of this logic to MyAvatar class + assert(!avatar->getMotionState()); + + ShapeInfo shapeInfo; + avatar->computeShapeInfo(shapeInfo); + btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); + if (shape) { + AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); + avatar->setMotionState(motionState); + _motionStatesToAdd.insert(motionState); + _avatarMotionStates.insert(motionState); } } diff --git a/interface/src/avatar/AvatarMotionState.h b/interface/src/avatar/AvatarMotionState.h index 1c49705f23..b5101d2c70 100644 --- a/interface/src/avatar/AvatarMotionState.h +++ b/interface/src/avatar/AvatarMotionState.h @@ -46,7 +46,7 @@ public: virtual float getObjectFriction() const; virtual float getObjectLinearDamping() const; virtual float getObjectAngularDamping() const; - + virtual glm::vec3 getObjectPosition() const; virtual glm::quat getObjectRotation() const; virtual glm::vec3 getObjectLinearVelocity() const; diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 4f16449aa2..fe03d22f0b 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -37,7 +37,7 @@ void Hand::simulate(float deltaTime, bool isMine) { void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { float avatarScale = 1.0f; if (_owningAvatar) { - avatarScale = _owningAvatar->getAvatarScale(); + avatarScale = _owningAvatar->getUniformScale(); } const float alpha = 1.0f; @@ -62,7 +62,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { transform.setRotation(palm.getRotation()); transform.postScale(SPHERE_RADIUS); DependencyManager::get()->renderSolidSphereInstance(batch, transform, grayColor); - + // draw a green sphere at the old "finger tip" transform = Transform(); position = palm.getTipPosition(); @@ -72,7 +72,7 @@ void Hand::renderHandTargets(RenderArgs* renderArgs, bool isMine) { DependencyManager::get()->renderSolidSphereInstance(batch, transform, greenColor); } } - + const float AXIS_RADIUS = 0.1f * SPHERE_RADIUS; const float AXIS_LENGTH = 10.0f * SPHERE_RADIUS; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9331682714..926d41f1ca 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,13 +284,26 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); +void MyAvatar::animateScaleChanges(float deltaTime) { + // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState + float currentScale = getUniformScale(); + if (currentScale != _targetScale) { + const float SCALE_ANIMATION_TIMESCALE = 1.0f; + float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + const float CLOSE_ENOUGH = 0.05f; + if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + animatedScale = _targetScale; + } + setScale(glm::vec3(animatedScale)); + rebuildCollisionShape(); + } +} + void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); - if (getAvatarScale() != _targetScale) { - float scale = (1.0f - SMOOTHING_RATIO) * getAvatarScale() + SMOOTHING_RATIO * _targetScale; - setAvatarScale(scale); - } + animateScaleChanges(deltaTime); { PerformanceTimer perfTimer("transform"); @@ -337,7 +350,7 @@ void MyAvatar::simulate(float deltaTime) { headPosition = getPosition(); } head->setPosition(headPosition); - head->setScale(getAvatarScale()); + head->setScale(getUniformScale()); head->simulate(deltaTime, true); } @@ -681,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setAvatarScale(getAvatarScale()); + setScale(glm::vec3(getUniformScale())); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); @@ -809,7 +822,7 @@ void MyAvatar::updateLookAtTargetAvatar() { float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition); avatar->setIsLookAtTarget(false); if (!avatar->isMyAvatar() && avatar->isInitialized() && - (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getAvatarScale())) { + (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) { float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - cameraPosition)); if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { _lookAtTargetAvatar = avatarPointer; @@ -1036,14 +1049,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::rebuildSkeletonBody() { +void MyAvatar::rebuildCollisionShape() { // compute localAABox - float radius = _skeletonModel.getBoundingCapsuleRadius(); - float height = _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; + float scale = getUniformScale(); + float radius = scale * _skeletonModel.getBoundingCapsuleRadius(); + float height = scale * _skeletonModel.getBoundingCapsuleHeight() + 2.0f * radius; glm::vec3 corner(-radius, -0.5f * height, -radius); - corner += _skeletonModel.getBoundingCapsuleOffset(); - glm::vec3 scale(2.0f * radius, height, 2.0f * radius); - _characterController.setLocalBoundingBox(corner, scale); + corner += scale * _skeletonModel.getBoundingCapsuleOffset(); + glm::vec3 diagonal(2.0f * radius, height, 2.0f * radius); + _characterController.setLocalBoundingBox(corner, diagonal); } void MyAvatar::prepareForPhysicsSimulation() { @@ -1331,7 +1345,7 @@ const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f; bool MyAvatar::cameraInsideHead() const { const Head* head = getHead(); const glm::vec3 cameraPosition = qApp->getCamera()->getPosition(); - return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getAvatarScale()); + return glm::length(cameraPosition - head->getEyePosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale()); } bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const { @@ -1455,11 +1469,11 @@ glm::vec3 MyAvatar::applyKeyboardMotor(float deltaTime, const glm::vec3& localVe if (isHovering) { // we're flying --> complex acceleration curve with high max speed float motorSpeed = glm::length(_keyboardMotorVelocity); - float finalMaxMotorSpeed = getAvatarScale() * MAX_KEYBOARD_MOTOR_SPEED; + float finalMaxMotorSpeed = getUniformScale() * MAX_KEYBOARD_MOTOR_SPEED; float speedGrowthTimescale = 2.0f; float speedIncreaseFactor = 1.8f; motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale , 0.0f, 1.0f) * speedIncreaseFactor; - const float maxBoostSpeed = getAvatarScale() * MAX_BOOST_SPEED; + const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED; if (motorSpeed < maxBoostSpeed) { // an active keyboard motor should never be slower than this float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 514261bf16..bce6521c07 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -249,7 +249,7 @@ public slots: Q_INVOKABLE void updateMotionBehaviorFromMenu(); - virtual void rebuildSkeletonBody() override; + virtual void rebuildCollisionShape() override; Q_INVOKABLE QUrl getAnimGraphUrl() const { return _animGraphUrl; } @@ -263,6 +263,9 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); +protected: + void animateScaleChanges(float deltaTime); + signals: void audioListenerModeChanged(); void transformChanged(); diff --git a/interface/src/avatar/MyCharacterController.cpp b/interface/src/avatar/MyCharacterController.cpp index 23d601e58e..c7f2945757 100644 --- a/interface/src/avatar/MyCharacterController.cpp +++ b/interface/src/avatar/MyCharacterController.cpp @@ -32,7 +32,7 @@ MyCharacterController::~MyCharacterController() { void MyCharacterController::updateShapeIfNecessary() { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { - _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; + _pendingFlags &= ~PENDING_FLAG_UPDATE_SHAPE; // compute new dimensions from avatar's bounding box float x = _boxScale.x; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 342f8315e1..47c22e9f08 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -69,7 +69,7 @@ void SkeletonModel::initJointStates() { _headClipDistance = -(meshExtents.minimum.z / _scale.z - _defaultEyeModelPosition.z); _headClipDistance = std::max(_headClipDistance, DEFAULT_NEAR_CLIP); - _owningAvatar->rebuildSkeletonBody(); + _owningAvatar->rebuildCollisionShape(); emit skeletonLoaded(); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 99285c6558..e5ecdfe217 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -386,7 +386,7 @@ bool ApplicationCompositor::calculateRayUICollisionPoint(const glm::vec3& positi glm::vec3 relativeDirection = glm::normalize(inverseOrientation * direction); float t; - if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getAvatarScale(), &t)){ + if (raySphereIntersect(relativeDirection, relativePosition, _oculusUIRadius * myAvatar->getUniformScale(), &t)){ result = position + direction * t; return true; } diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 9a995263cd..f7ef0c9d56 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -199,7 +199,7 @@ void PreferencesDialog::loadPreferences() { ui.leanScaleSpin->setValue(myAvatar->getLeanScale()); - ui.avatarScaleSpin->setValue(myAvatar->getAvatarScale()); + ui.avatarScaleSpin->setValue(myAvatar->getUniformScale()); ui.avatarAnimationEdit->setText(myAvatar->getAnimGraphUrl().toString()); ui.maxOctreePPSSpin->setValue(qApp->getMaxOctreePacketsPerSecond()); diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 1b1c48c3ca..753106fa0a 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -68,7 +68,7 @@ namespace render { glm::vec3 myAvatarPosition = avatar->getPosition(); float angle = glm::degrees(glm::angle(myAvatarRotation)); glm::vec3 axis = glm::axis(myAvatarRotation); - float myAvatarScale = avatar->getAvatarScale(); + float myAvatarScale = avatar->getUniformScale(); Transform transform = Transform(); transform.setTranslation(myAvatarPosition); transform.setRotation(glm::angleAxis(angle, axis)); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d241df7e0e..dce973fb33 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -90,7 +90,7 @@ const QUrl& AvatarData::defaultFullAvatarModelUrl() { // There are a number of possible strategies for this set of tools through endRender, below. void AvatarData::nextAttitude(glm::vec3 position, glm::quat orientation) { avatarLock.lock(); - Transform trans; + Transform trans = getTransform(); trans.setTranslation(position); trans.setRotation(orientation); SpatiallyNestable::setTransform(trans); From 33634cdaa16e8faec4fb375f5efcb6ae9e0d27ef Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 10 Dec 2015 18:09:58 -0800 Subject: [PATCH 04/38] properly delete departing avatars --- interface/src/avatar/Avatar.cpp | 21 +++++++++++++-------- interface/src/avatar/Avatar.h | 5 ++++- interface/src/avatar/AvatarManager.cpp | 16 ++++++++-------- interface/src/avatar/AvatarManager.h | 14 +++++++------- libraries/avatars/src/AvatarData.h | 5 +++++ 5 files changed, 37 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8231d1ebdd..a0fa822512 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,11 +150,12 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { + const float SCALE_ANIMATION_TIMESCALE = 0.5f; + float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; + float animatedScale = currentScale + deltaTime * scaleVelocity; + const float MIN_SCALE_SPEED = 0.3f; + if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { + // close enough animatedScale = _targetScale; } setScale(glm::vec3(animatedScale)); // avatar scale is uniform @@ -165,6 +166,9 @@ void Avatar::animateScaleChanges(float deltaTime) { void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); + if (!isDead() && !_motionState) { + DependencyManager::get()->updateAvatarPhysicsShape(this); + } animateScaleChanges(deltaTime); // update the billboard render flag @@ -1107,13 +1111,14 @@ void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) { shapeInfo.setOffset(uniformScale * _skeletonModel.getBoundingCapsuleOffset()); } +void Avatar::setMotionState(AvatarMotionState* motionState) { + _motionState = motionState; +} + // virtual void Avatar::rebuildCollisionShape() { if (_motionState) { _motionState->addDirtyFlags(Simulation::DIRTY_SHAPE); - } else { - // adebug TODO: move most of updateAvatarPhysicsShape() to here - DependencyManager::get()->updateAvatarPhysicsShape(this); } } diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 379ab8b627..4926212b4d 100644 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -157,7 +157,6 @@ public: virtual void computeShapeInfo(ShapeInfo& shapeInfo); - void setMotionState(AvatarMotionState* motionState) { _motionState = motionState; } AvatarMotionState* getMotionState() { return _motionState; } virtual void setPosition(const glm::vec3& position) override; @@ -172,6 +171,10 @@ public slots: glm::quat getRightPalmRotation(); protected: + friend class AvatarManager; + + void setMotionState(AvatarMotionState* motionState); + SkeletonModel _skeletonModel; glm::vec3 _skeletonOffset; QVector _attachmentModels; diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 562bea3542..38f191872e 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -223,14 +223,14 @@ AvatarSharedPointer AvatarManager::newSharedAvatar() { AvatarSharedPointer AvatarManager::addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer) { auto newAvatar = AvatarHashMap::addAvatar(sessionUUID, mixerWeakPointer); auto rawRenderableAvatar = std::static_pointer_cast(newAvatar); - + render::ScenePointer scene = qApp->getMain3DScene(); render::PendingChanges pendingChanges; if (DependencyManager::get()->shouldRenderAvatars()) { rawRenderableAvatar->addToScene(rawRenderableAvatar, scene, pendingChanges); } scene->enqueuePendingChanges(pendingChanges); - + return newAvatar; } @@ -251,7 +251,7 @@ void AvatarManager::removeAvatarMotionState(AvatarSharedPointer avatar) { // virtual void AvatarManager::removeAvatar(const QUuid& sessionUUID) { QWriteLocker locker(&_hashLock); - + auto removedAvatar = _avatarHash.take(sessionUUID); if (removedAvatar) { handleRemovedAvatar(removedAvatar); @@ -260,7 +260,8 @@ void AvatarManager::removeAvatar(const QUuid& sessionUUID) { void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar) { AvatarHashMap::handleRemovedAvatar(removedAvatar); - + + removedAvatar->die(); removeAvatarMotionState(removedAvatar); _avatarFades.push_back(removedAvatar); } @@ -268,7 +269,7 @@ void AvatarManager::handleRemovedAvatar(const AvatarSharedPointer& removedAvatar void AvatarManager::clearOtherAvatars() { // clear any avatars that came from an avatar-mixer QWriteLocker locker(&_hashLock); - + AvatarHash::iterator avatarIterator = _avatarHash.begin(); while (avatarIterator != _avatarHash.end()) { auto avatar = std::static_pointer_cast(avatarIterator.value()); @@ -278,7 +279,7 @@ void AvatarManager::clearOtherAvatars() { } else { auto removedAvatar = avatarIterator.value(); avatarIterator = _avatarHash.erase(avatarIterator); - + handleRemovedAvatar(removedAvatar); } } @@ -375,7 +376,6 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { - // adebug TODO: move most of this logic to MyAvatar class assert(!avatar->getMotionState()); ShapeInfo shapeInfo; @@ -414,6 +414,6 @@ AvatarSharedPointer AvatarManager::getAvatarBySessionID(const QUuid& sessionID) if (sessionID == _myAvatar->getSessionUUID()) { return _myAvatar; } - + return findAvatar(sessionID); } diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index 84a4bc44b8..d63df9fb76 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -52,7 +52,7 @@ public: glm::vec3 color; glm::vec3 direction; }; - + Q_INVOKABLE void setLocalLights(const QVector& localLights); Q_INVOKABLE QVector getLocalLights() const; // Currently, your own avatar will be included as the null avatar id. @@ -67,7 +67,7 @@ public: void handleCollisionEvents(const CollisionEvents& collisionEvents); void updateAvatarPhysicsShape(Avatar* avatar); - + // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } Q_INVOKABLE float getRenderDistanceInverseLowLimit() { return _renderDistanceController.getControlledValueLowLimit(); } @@ -80,7 +80,7 @@ public: Q_INVOKABLE void setRenderDistanceKD(float newValue) { _renderDistanceController.setKD(newValue); } Q_INVOKABLE void setRenderDistanceInverseLowLimit(float newValue) { _renderDistanceController.setControlledValueLowLimit(newValue); } Q_INVOKABLE void setRenderDistanceInverseHighLimit(float newValue); - + public slots: void setShouldShowReceiveStats(bool shouldShowReceiveStats) { _shouldShowReceiveStats = shouldShowReceiveStats; } void updateAvatarRenderStatus(bool shouldRenderAvatars); @@ -90,19 +90,19 @@ private: AvatarManager(const AvatarManager& other); void simulateAvatarFades(float deltaTime); - + // virtual overrides virtual AvatarSharedPointer newSharedAvatar(); virtual AvatarSharedPointer addAvatar(const QUuid& sessionUUID, const QWeakPointer& mixerWeakPointer); void removeAvatarMotionState(AvatarSharedPointer avatar); - + virtual void removeAvatar(const QUuid& sessionUUID); virtual void handleRemovedAvatar(const AvatarSharedPointer& removedAvatar); - + QVector _avatarFades; std::shared_ptr _myAvatar; quint64 _lastSendAvatarDataTime = 0; // Controls MyAvatar send data rate. - + QVector _localLights; bool _shouldShowReceiveStats = false; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1fa33ff606..cbd15f2ce1 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -342,6 +342,9 @@ public: glm::vec3 getClientGlobalPosition() { return _globalPosition; } + void die() { _isDead = true; } + bool isDead() const { return _isDead; } + public slots: void sendAvatarDataPacket(); void sendIdentityPacket(); @@ -413,6 +416,8 @@ protected: // updates about one avatar to another. glm::vec3 _globalPosition; + bool _isDead { false }; + private: friend void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); static QUrl _defaultFullAvatarModelUrl; From bab07516f032db80e2475b42d90cc94283276a7f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:11 -0800 Subject: [PATCH 05/38] fix size of rendered bounding capsule --- interface/src/avatar/Avatar.cpp | 3 ++- interface/src/avatar/SkeletonModel.cpp | 23 +++++++++++++---------- interface/src/avatar/SkeletonModel.h | 2 +- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index a0fa822512..9e881f49ea 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -454,7 +454,8 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) { bool renderBounding = Menu::getInstance()->isOptionChecked(MenuOption::RenderBoundingCollisionShapes); if (renderBounding && shouldRenderHead(renderArgs) && _skeletonModel.isRenderable()) { PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes"); - _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, 0.7f); + const float BOUNDING_SHAPE_ALPHA = 0.7f; + _skeletonModel.renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA); } // If this is the avatar being looked at, render a little ball above their head diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 47c22e9f08..e8d952973b 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -338,35 +338,38 @@ void SkeletonModel::computeBoundingShape() { return; } - _rig->computeAvatarBoundingCapsule(geometry, - _boundingCapsuleRadius, - _boundingCapsuleHeight, - _boundingCapsuleLocalOffset); + float radius, height; + glm::vec3 offset; + _rig->computeAvatarBoundingCapsule(geometry, radius, height, offset); + float invScale = 1.0f / _owningAvatar->getUniformScale(); + _boundingCapsuleRadius = invScale * radius; + _boundingCapsuleHeight = invScale * height; + _boundingCapsuleLocalOffset = invScale * offset; } -void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float alpha) { +void SkeletonModel::renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha) { auto geometryCache = DependencyManager::get(); auto deferredLighting = DependencyManager::get(); // draw a blue sphere at the capsule top point - glm::vec3 topPoint = _translation + getRotation() * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * glm::vec3(0.0f, 1.0f, 0.0f)); + glm::vec3 topPoint = _translation + getRotation() * (scale * (_boundingCapsuleLocalOffset + (0.5f * _boundingCapsuleHeight) * Vectors::UNIT_Y)); deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(topPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(topPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.6f, 0.6f, 0.8f, alpha)); // draw a yellow sphere at the capsule bottom point - glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, _boundingCapsuleHeight, 0.0f); + glm::vec3 bottomPoint = topPoint - glm::vec3(0.0f, scale * _boundingCapsuleHeight, 0.0f); glm::vec3 axis = topPoint - bottomPoint; deferredLighting->renderSolidSphereInstance(batch, - Transform().setTranslation(bottomPoint).postScale(_boundingCapsuleRadius), + Transform().setTranslation(bottomPoint).postScale(scale * _boundingCapsuleRadius), glm::vec4(0.8f, 0.8f, 0.6f, alpha)); // draw a green cylinder between the two points glm::vec3 origin(0.0f); batch.setModelTransform(Transform().setTranslation(bottomPoint)); deferredLighting->bindSimpleProgram(batch); - Avatar::renderJointConnectingCone(batch, origin, axis, _boundingCapsuleRadius, _boundingCapsuleRadius, + Avatar::renderJointConnectingCone(batch, origin, axis, scale * _boundingCapsuleRadius, scale * _boundingCapsuleRadius, glm::vec4(0.6f, 0.8f, 0.6f, alpha)); } diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 9b73119238..7541a002dc 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -89,7 +89,7 @@ public: /// \return whether or not the head was found. glm::vec3 getDefaultEyeModelPosition() const; - void renderBoundingCollisionShapes(gpu::Batch& batch, float alpha); + void renderBoundingCollisionShapes(gpu::Batch& batch, float scale, float alpha); float getBoundingCapsuleRadius() const { return _boundingCapsuleRadius; } float getBoundingCapsuleHeight() const { return _boundingCapsuleHeight; } const glm::vec3 getBoundingCapsuleOffset() const { return _boundingCapsuleLocalOffset; } From cd1e3810ca43c7d3822c7581096f79dd2bd5ac18 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:06:31 -0800 Subject: [PATCH 06/38] set the scale of avatar on login, don't animate --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 926d41f1ca..73ff332a37 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -694,7 +694,7 @@ void MyAvatar::loadData() { _leanScale = loadSetting(settings, "leanScale", 0.05f); _targetScale = loadSetting(settings, "scale", 1.0f); - setScale(glm::vec3(getUniformScale())); + setScale(glm::vec3(_targetScale)); _animGraphUrl = settings.value("animGraphURL", "").toString(); _fullAvatarURLFromPreferences = settings.value("fullAvatarURL", AvatarData::defaultFullAvatarModelUrl()).toUrl(); From c3823de353ea40d96501fce20b84c778759991d3 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 14 Dec 2015 12:07:03 -0800 Subject: [PATCH 07/38] setClampedTargetScale()-->setTargetScaleVerbose() --- interface/src/ui/PreferencesDialog.cpp | 2 +- libraries/avatars/src/AvatarData.cpp | 5 +---- libraries/avatars/src/AvatarData.h | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index f7ef0c9d56..a38cc13100 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -256,7 +256,7 @@ void PreferencesDialog::savePreferences() { myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum()); myAvatar->setLeanScale(ui.leanScaleSpin->value()); - myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value()); + myAvatar->setTargetScaleVerbose(ui.avatarScaleSpin->value()); if (myAvatar->getAnimGraphUrl() != ui.avatarAnimationEdit->text()) { // If changed, destroy the old and start with the new myAvatar->setAnimGraphUrl(ui.avatarAnimationEdit->text()); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index dce973fb33..645e0ad7fc 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -132,10 +132,7 @@ void AvatarData::setTargetScale(float targetScale) { _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); } -void AvatarData::setClampedTargetScale(float targetScale) { - - targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); - +void AvatarData::setTargetScaleVerbose(float targetScale) { setTargetScale(targetScale); qCDebug(avatars) << "Changed scale to " << _targetScale; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cbd15f2ce1..64c215cee7 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -172,7 +172,7 @@ public: AvatarData(); virtual ~AvatarData(); - + static const QUrl& defaultFullAvatarModelUrl(); virtual bool isMyAvatar() const { return false; } @@ -237,7 +237,7 @@ public: // Scale float getTargetScale() const; void setTargetScale(float targetScale); - void setClampedTargetScale(float targetScale); + void setTargetScaleVerbose(float targetScale); // Hand State Q_INVOKABLE void setHandState(char s) { _handState = s; } @@ -261,7 +261,7 @@ public: Q_INVOKABLE bool isJointDataValid(const QString& name) const; Q_INVOKABLE glm::quat getJointRotation(const QString& name) const; Q_INVOKABLE glm::vec3 getJointTranslation(const QString& name) const; - + Q_INVOKABLE virtual QVector getJointRotations() const; Q_INVOKABLE virtual void setJointRotations(QVector jointRotations); Q_INVOKABLE virtual void setJointTranslations(QVector jointTranslations); From 9b0c199ed75752d71556adcc27244aacee49aa72 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:30:56 -0800 Subject: [PATCH 08/38] updateAvatarPhysicsShape-->addAvatarToSimulation --- interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/AvatarManager.cpp | 3 ++- interface/src/avatar/AvatarManager.h | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 9e881f49ea..504124c4a7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -167,7 +167,7 @@ void Avatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); if (!isDead() && !_motionState) { - DependencyManager::get()->updateAvatarPhysicsShape(this); + DependencyManager::get()->addAvatarToSimulation(this); } animateScaleChanges(deltaTime); diff --git a/interface/src/avatar/AvatarManager.cpp b/interface/src/avatar/AvatarManager.cpp index 38f191872e..312742e778 100644 --- a/interface/src/avatar/AvatarManager.cpp +++ b/interface/src/avatar/AvatarManager.cpp @@ -375,13 +375,14 @@ void AvatarManager::handleCollisionEvents(const CollisionEvents& collisionEvents } } -void AvatarManager::updateAvatarPhysicsShape(Avatar* avatar) { +void AvatarManager::addAvatarToSimulation(Avatar* avatar) { assert(!avatar->getMotionState()); ShapeInfo shapeInfo; avatar->computeShapeInfo(shapeInfo); btCollisionShape* shape = ObjectMotionState::getShapeManager()->getShape(shapeInfo); if (shape) { + // we don't add to the simulation now, we put it on a list to be added later AvatarMotionState* motionState = new AvatarMotionState(avatar, shape); avatar->setMotionState(motionState); _motionStatesToAdd.insert(motionState); diff --git a/interface/src/avatar/AvatarManager.h b/interface/src/avatar/AvatarManager.h index d63df9fb76..1b165495c3 100644 --- a/interface/src/avatar/AvatarManager.h +++ b/interface/src/avatar/AvatarManager.h @@ -66,7 +66,7 @@ public: void handleOutgoingChanges(const VectorOfMotionStates& motionStates); void handleCollisionEvents(const CollisionEvents& collisionEvents); - void updateAvatarPhysicsShape(Avatar* avatar); + void addAvatarToSimulation(Avatar* avatar); // Expose results and parameter-tuning operations to other systems, such as stats and javascript. Q_INVOKABLE float getRenderDistance() { return _renderDistance; } From 7baee8c39138e80c05238dd0e93f2671a7cb90dc Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 15:34:16 -0800 Subject: [PATCH 09/38] use glm::clamp() instead of std::min() and max() --- libraries/avatars/src/AvatarData.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 645e0ad7fc..2ed9a47e02 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -129,7 +129,7 @@ float AvatarData::getTargetScale() const { } void AvatarData::setTargetScale(float targetScale) { - _targetScale = std::max(MIN_AVATAR_SCALE, std::min(MAX_AVATAR_SCALE, targetScale)); + _targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE); } void AvatarData::setTargetScaleVerbose(float targetScale) { From 0e1e5db7eb808a71f209e7c219e74a87b29ddf58 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 15 Dec 2015 16:29:39 -0800 Subject: [PATCH 10/38] only need one animateScaleChanges() implementation --- interface/src/avatar/Avatar.cpp | 13 ++++++++----- interface/src/avatar/MyAvatar.cpp | 16 ---------------- interface/src/avatar/MyAvatar.h | 3 --- 3 files changed, 8 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 504124c4a7..f8040754d7 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -150,14 +150,17 @@ float Avatar::getLODDistance() const { void Avatar::animateScaleChanges(float deltaTime) { float currentScale = getUniformScale(); if (currentScale != _targetScale) { + // use exponential decay toward _targetScale const float SCALE_ANIMATION_TIMESCALE = 0.5f; - float scaleVelocity = (_targetScale - currentScale) / SCALE_ANIMATION_TIMESCALE; - float animatedScale = currentScale + deltaTime * scaleVelocity; - const float MIN_SCALE_SPEED = 0.3f; - if (fabsf(scaleVelocity) < MIN_SCALE_SPEED) { - // close enough + float blendFactor = glm::clamp(deltaTime / SCALE_ANIMATION_TIMESCALE, 0.0f, 1.0f); + float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; + + // snap to the end when we get close enough + const float MIN_RELATIVE_SCALE_ERROR = 0.03f; + if (fabsf(_targetScale - currentScale) / _targetScale < 0.03f) { animatedScale = _targetScale; } + setScale(glm::vec3(animatedScale)); // avatar scale is uniform rebuildCollisionShape(); } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 73ff332a37..5c8230bd88 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -284,22 +284,6 @@ void MyAvatar::update(float deltaTime) { extern QByteArray avatarStateToFrame(const AvatarData* _avatar); extern void avatarStateFromFrame(const QByteArray& frameData, AvatarData* _avatar); -void MyAvatar::animateScaleChanges(float deltaTime) { - // HACK: override Avatar::animateScaleChanges() until MyAvatar has a MotionState - float currentScale = getUniformScale(); - if (currentScale != _targetScale) { - const float SCALE_ANIMATION_TIMESCALE = 1.0f; - float blendFactor = deltaTime / SCALE_ANIMATION_TIMESCALE; - float animatedScale = (1.0f - blendFactor) * currentScale + blendFactor * _targetScale; - const float CLOSE_ENOUGH = 0.05f; - if (fabsf(animatedScale - _targetScale) / _targetScale < CLOSE_ENOUGH) { - animatedScale = _targetScale; - } - setScale(glm::vec3(animatedScale)); - rebuildCollisionShape(); - } -} - void MyAvatar::simulate(float deltaTime) { PerformanceTimer perfTimer("simulate"); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index bce6521c07..019ba0f992 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -263,9 +263,6 @@ public slots: glm::vec3 getPositionForAudio(); glm::quat getOrientationForAudio(); -protected: - void animateScaleChanges(float deltaTime); - signals: void audioListenerModeChanged(); void transformChanged(); From 08f75917876e1e50f7a7c1a4c9f051a12355b117 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 16 Dec 2015 10:02:47 -0800 Subject: [PATCH 11/38] Fix misspelling --- interface/src/ui/overlays/Image3DOverlay.cpp | 16 ++++++++-------- interface/src/ui/overlays/Image3DOverlay.h | 2 +- .../render-utils/src/DeferredLightingEffect.cpp | 4 ++-- .../render-utils/src/DeferredLightingEffect.h | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 6e4c274943..7d105a6ccf 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -27,7 +27,7 @@ QString const Image3DOverlay::TYPE = "image3d"; Image3DOverlay::Image3DOverlay() { _isLoaded = false; - _emmisive = false; + _emissive = false; } Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : @@ -35,7 +35,7 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), _fromImage(image3DOverlay->_fromImage), - _emmisive(image3DOverlay->_emmisive) + _emissive(image3DOverlay->_emissive) { } @@ -96,7 +96,7 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emmisive, true); + DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emissive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -147,9 +147,9 @@ void Image3DOverlay::setProperties(const QScriptValue &properties) { } } - QScriptValue emmisiveValue = properties.property("emmisive"); - if (emmisiveValue.isValid()) { - _emmisive = emmisiveValue.toBool(); + QScriptValue emissiveValue = properties.property("emissive"); + if (emissiveValue.isValid()) { + _emissive = emissiveValue.toBool(); } } @@ -163,8 +163,8 @@ QScriptValue Image3DOverlay::getProperty(const QString& property) { if (property == "offsetPosition") { return vec3toScriptValue(_scriptEngine, getOffsetPosition()); } - if (property == "emmisive") { - return _emmisive; + if (property == "emissive") { + return _emissive; } return Billboard3DOverlay::getProperty(property); diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index 0e40c73619..f2cc3789ee 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -46,7 +46,7 @@ public: private: QString _url; NetworkTexturePointer _texture; - bool _emmisive; + bool _emissive; QRect _fromImage; // where from in the image to sample }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 10b58b156b..dcadaa5177 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -169,8 +169,8 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) { gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, - bool emmisive, bool depthBias) { - SimpleProgramKey config{textured, culled, emmisive, depthBias}; + bool emissive, bool depthBias) { + SimpleProgramKey config{textured, culled, emissive, depthBias}; gpu::PipelinePointer pipeline = getPipeline(config); batch.setPipeline(pipeline); diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index 9c4809a82e..eee5993c29 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -38,7 +38,7 @@ public: /// Sets up the state necessary to render static untextured geometry with the simple program. gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, - bool emmisive = false, bool depthBias = false); + bool emissive = false, bool depthBias = false); void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec4& color); void renderSolidSphereInstance(gpu::Batch& batch, const Transform& xfm, const glm::vec3& color) { From 711d02ba2f44d7bef93c36e8079642d35e72e105 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:26:24 -0600 Subject: [PATCH 12/38] Consolidating installer checkpoint --- CMakeLists.txt | 42 ++--- cmake/macros/ConsolidateStackComponents.cmake | 37 ++-- cmake/modules/FindOpenSSL.cmake | 1 - tools/nsis/release.nsi | 176 ++++++++++++++++++ 4 files changed, 207 insertions(+), 49 deletions(-) create mode 100644 tools/nsis/release.nsi diff --git a/CMakeLists.txt b/CMakeLists.txt index a8271abd8e..836b808a4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12.2) +cmake_minimum_required(VERSION 3.3.2) if (USE_ANDROID_TOOLCHAIN) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake") @@ -230,32 +230,14 @@ endif () include_application_version() if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - message(STATUS "+++++ Package for deployment will be generated on this build +++++") - - file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment) - - set(ICONPATH_INTERFACE "$INSTDIR/${PATH_INSTALL_DATA}/interface.ico") - set(ICONPATH_STACK_MANAGER "$INSTDIR/${PATH_INSTALL_DATA}/stack-manager.ico") - string(REPLACE "/" "\\\\" ICONPATH_INTERFACE ${ICONPATH_INTERFACE}) - string(REPLACE "/" "\\\\" ICONPATH_STACK_MANAGER ${ICONPATH_STACK_MANAGER}) - - set(CPACK_PACKAGE_NAME "High Fidelity") - set(CPACK_PACKAGE_VENDOR "High Fidelity, Inc") - set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "High Fidelity Interface and Stack") - set(CPACK_PACKAGE_VERSION "${BUILD_SEQ}") - set(CPACK_PACKAGE_VERSION_MAJOR "${BUILD_SEQ}") - set(CPACK_PACKAGE_VERSION_MINOR "0") - set(CPACK_PACKAGE_VERSION_PATCH "0") - set(CPACK_PACKAGE_INSTALL_DIRECTORY "High Fidelity-${BUILD_SEQ}") - set(CPACK_NSIS_EXECUTABLES_DIRECTORY ".") - set(CPACK_PACKAGE_EXECUTABLES - stack-manager "Stack Manager" - interface "Interface" - ) - - if (WIN32) - install(DIRECTORY ${CMAKE_BINARY_DIR}/full-stack-deployment/ DESTINATION "./") - endif (WIN32) - - include(CPack) -endif () + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") + find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) + if (NOT MAKENSIS_COMMAND) + message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") + endif () + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager + COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" + ) +endif () \ No newline at end of file diff --git a/cmake/macros/ConsolidateStackComponents.cmake b/cmake/macros/ConsolidateStackComponents.cmake index 4bcc777751..ca272f6485 100644 --- a/cmake/macros/ConsolidateStackComponents.cmake +++ b/cmake/macros/ConsolidateStackComponents.cmake @@ -1,26 +1,27 @@ macro(CONSOLIDATE_STACK_COMPONENTS) - if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32) - - # Copy all the output for this target into the common deployment location - add_custom_command( - TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/full-stack-deployment - ) - - # Copy icon files for interface and stack manager - if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager") - if (TARGET_NAME STREQUAL "interface") - set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico") - set (ICON_DESTINATION_NAME "interface.ico") - elseif (TARGET_NAME STREQUAL "stack-manager") - set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico") - set (ICON_DESTINATION_NAME "stack-manager.ico") - endif () + if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) + if (WIN32) + # Copy all the output for this target into the common deployment location add_custom_command( TARGET ${TARGET_NAME} POST_BUILD - COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME} + COMMAND "${CMAKE_COMMAND}" -E copy_directory $ ${CMAKE_BINARY_DIR}/full-stack-deployment ) + + # Copy icon files for interface and stack manager + if (TARGET_NAME STREQUAL "interface" OR TARGET_NAME STREQUAL "stack-manager") + if (TARGET_NAME STREQUAL "interface") + set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/icon/interface.ico") + set (ICON_DESTINATION_NAME "interface.ico") + elseif (TARGET_NAME STREQUAL "stack-manager") + set (ICON_FILE_PATH "${PROJECT_SOURCE_DIR}/assets/icon.ico") + set (ICON_DESTINATION_NAME "stack-manager.ico") + endif () + add_custom_command( + TARGET ${TARGET_NAME} POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy ${ICON_FILE_PATH} ${CMAKE_BINARY_DIR}/full-stack-deployment/${ICON_DESTINATION_NAME} + ) + endif () endif () endif () diff --git a/cmake/modules/FindOpenSSL.cmake b/cmake/modules/FindOpenSSL.cmake index 6893948d01..9d9557ad9e 100644 --- a/cmake/modules/FindOpenSSL.cmake +++ b/cmake/modules/FindOpenSSL.cmake @@ -256,7 +256,6 @@ if (WIN32) # For some reason fixup misses the following DLL and only copies libeay32. There's gotta be a better way to handle this # but for now resorting to the following interm solution if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - message(STATUS "*********** Copying SSL DLL from ${OPENSSL_DLL_PATH}/ssleay32.dll") add_custom_command( TARGET ${TARGET_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy ${OPENSSL_DLL_PATH}/ssleay32.dll ${CMAKE_BINARY_DIR}/full-stack-deployment/ diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi new file mode 100644 index 0000000000..5b2cce5c61 --- /dev/null +++ b/tools/nsis/release.nsi @@ -0,0 +1,176 @@ +!include LogicLib.nsh +!include x64.nsh + +!define srcdir "E:\development\md-hifi\build\full-stack-deployment" ;$%INSTALLER_SOURCE_DIR% +!define setup "E:\development\md-hifi\build\installer-test.exe" ;$%INSTALLER_NAME% +!define scriptsdir "E:\development\md-hifi\examples" ;$%INSTALLER_SCRIPTS_DIR% +!define company "High Fidelity" +!define prodname "Interface" +!define exec "interface.exe" +!define icon "${srcdir}\interface.ico" +!define regkey "Software\${company}\${prodname}" +!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prodname}" +!define install_dir_company "$PROGRAMFILES64\${company}" +!define install_dir_product "${install_dir_company}\${prodname}" +!define startmenu_company "$SMPROGRAMS\${company}" +!define startmenu_product "${startmenu_company}\${prodname}" +!define uninstaller "uninstall.exe" + +;-------------------------------- + +XPStyle on +ShowInstDetails hide +ShowUninstDetails hide + +Name "${prodname}" +Caption "${prodname}" + +!ifdef icon + Icon "${icon}" +!endif + +OutFile "${setup}" + +SetDateSave on +SetDatablockOptimize on +CRCCheck on +SilentInstall normal + +InstallDir "${install_dir_product}" +InstallDirRegKey HKLM "${regkey}" "" + +; Page components +Page directory +Page components +Page instfiles + +UninstPage uninstConfirm +UninstPage instfiles + +;-------------------------------- + +AutoCloseWindow true +ShowInstDetails show + + +!ifdef screenimage + + ; set up background image + ; uses BgImage plugin + + Function .onGUIInit + ; extract background BMP into temp plugin directory + InitPluginsDir + File /oname=$PLUGINSDIR\1.bmp "${screenimage}" + + BgImage::SetBg /NOUNLOAD /FILLSCREEN $PLUGINSDIR\1.bmp + BgImage::Redraw /NOUNLOAD + FunctionEnd + + Function .onGUIEnd + ; Destroy must not have /NOUNLOAD so NSIS will be able to unload and delete BgImage before it exits + BgImage::Destroy + FunctionEnd + +!endif + +; Optional Component Selection +Section /o "DDE Face Recognition" SEC01 + SetOutPath "$INSTDIR" + CreateDirectory $INSTDIR\dde + NSISdl::download "https://s3-us-west-1.amazonaws.com/hifi-production/optionals/dde-installer.exe" "$INSTDIR\dde-installer.exe" + ExecWait '"$INSTDIR\dde-installer.exe" /q:a /t:"$INSTDIR\dde"' +SectionEnd + +; beginning (invisible) section +Section "Registry Entries and Procotol Handler" SEC02 + + SectionIn RO + + WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" + WriteRegStr HKLM "${uninstkey}" "DisplayName" "${prodname} (remove only)" + WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' + WriteRegStr HKCR "${prodname}\Shell\open\command\" "" '"$INSTDIR\${exec} "%1"' + + !ifdef icon + WriteRegStr HKCR "${prodname}\DefaultIcon" "" "$INSTDIR\${icon}" + !endif + + ; hifi:// protocol handler registry entries + WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' + WriteRegStr HKCR 'hifi' 'URL Protocol' '' + WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${icon},1' + WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${exec} --url "%1"' + + SetOutPath $INSTDIR + + ; package all files, recursively, preserving attributes + ; assume files are in the correct places + File /r "${srcdir}\" + !ifdef icon + File /a "${icon}" + !endif + ; any application-specific files + !ifdef files + !include "${files}" + !endif + SetOutPath "$DOCUMENTS\${company}\Scripts" + File /r "${scriptsdir}\" + SetOutPath $INSTDIR + WriteUninstaller "${uninstaller}" + Exec '"$INSTDIR\2013_vcredist_x64.exe" /q /norestart' + Exec '"$INSTDIR\2010_vcredist_x86.exe" /q /norestart' +SectionEnd + +; create shortcuts +Section "Start Menu Shortcuts" SEC03 + + SectionIn RO + + ; This should install the shortcuts for "All Users" + SetShellVarContext all + CreateDirectory "${startmenu_product}" + SetOutPath $INSTDIR ; for working directory + !ifdef icon + CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\${icon}" + !else + CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" + !endif + + CreateShortCut "${startmenu_product}\Uninstall ${prodname}.lnk" "$INSTDIR\${uninstaller}" +SectionEnd + +; Uninstaller +; All section names prefixed by "Un" will be in the uninstaller + +UninstallText "This will uninstall ${prodname}." + +!ifdef icon + UninstallIcon "${icon}" +!endif + +Section "Uninstall" SEC04 + + SectionIn RO + + ; Explicitly remove all added shortcuts + SetShellVarContext all + DELETE "${startmenu_product}\${prodname}.lnk" + DELETE "${startmenu_product}\Uninstall ${prodname}.lnk" + + RMDIR "${startmenu_product}" + ; This should remove the High Fidelity folder in Start Menu if it's empty + RMDIR "${startmenu_company}" + + RMDIR /r "$INSTDIR" + ; This should remove the High Fidelity folder in Program Files if it's empty + RMDIR "${install_dir_company}" + + !ifdef unfiles + !include "${unfiles}" + !endif + ; It's good practice to put the registry key removal at the very end + DeleteRegKey HKLM "${uninstkey}" + DeleteRegKey HKLM "${regkey}" + DeleteRegKey HKCR 'hifi' +SectionEnd \ No newline at end of file From 56ef52022dd17d9defc3fe25c144337b0826eb33 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:28:05 -0600 Subject: [PATCH 13/38] Removing unwanted changes --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 7741445842..a2eb058ae6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,3 @@ -### TESTING BUILD - DO NOT MERGE ### - High Fidelity (hifi) is an early-stage technology lab experimenting with Virtual Worlds and VR. In this repository you'll find the source to many of the components in our From 5ed422e3a19687a941fb5476212a30d854ccaaec Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 14:28:49 -0600 Subject: [PATCH 14/38] Removing unwanted changes --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 836b808a4c..b2ed36a8c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,9 +67,9 @@ if ((NOT MSVC12) AND (NOT MSVC14)) CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X) if (COMPILER_SUPPORTS_CXX11) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") elseif(COMPILER_SUPPORTS_CXX0X) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x") else() message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.") endif() @@ -235,9 +235,9 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) if (NOT MAKENSIS_COMMAND) message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") endif () - add_custom_target( - build-package ALL - DEPENDS interface assignment-client domain-server stack-manager + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - ) + ) endif () \ No newline at end of file From cbed8bf35a8001c309b8a136fbd5c04650e96251 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 15:12:14 -0600 Subject: [PATCH 15/38] NSIS Changes --- CMakeLists.txt | 3 ++ tools/nsis/release.nsi | 71 +++++++++++++++++------------------------- 2 files changed, 32 insertions(+), 42 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b2ed36a8c5..69e6365c8c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -238,6 +238,9 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) add_custom_target( build-package ALL DEPENDS interface assignment-client domain-server stack-manager + COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/this-is-a-test.exe + COMMANE set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" ) endif () \ No newline at end of file diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi index 5b2cce5c61..86ea055e6b 100644 --- a/tools/nsis/release.nsi +++ b/tools/nsis/release.nsi @@ -1,19 +1,18 @@ !include LogicLib.nsh !include x64.nsh -!define srcdir "E:\development\md-hifi\build\full-stack-deployment" ;$%INSTALLER_SOURCE_DIR% -!define setup "E:\development\md-hifi\build\installer-test.exe" ;$%INSTALLER_NAME% -!define scriptsdir "E:\development\md-hifi\examples" ;$%INSTALLER_SCRIPTS_DIR% -!define company "High Fidelity" -!define prodname "Interface" -!define exec "interface.exe" -!define icon "${srcdir}\interface.ico" -!define regkey "Software\${company}\${prodname}" -!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${prodname}" +!define srcdir $%INSTALLER_SOURCE_DIR% +!define setup $%INSTALLER_NAME% +!define scriptsdir $%INSTALLER_SCRIPTS_DIR% +!define company $%INSTALLER_COMPANY% +!define interface_exec "interface.exe" +!define stack_manager_exec "stack-manager.exe" +!define interface_icon "interface.ico" +!define stack_manager_icon "stack-manager.ico" +!define regkey "Software\${company}" +!define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${company}" !define install_dir_company "$PROGRAMFILES64\${company}" -!define install_dir_product "${install_dir_company}\${prodname}" !define startmenu_company "$SMPROGRAMS\${company}" -!define startmenu_product "${startmenu_company}\${prodname}" !define uninstaller "uninstall.exe" ;-------------------------------- @@ -22,8 +21,8 @@ XPStyle on ShowInstDetails hide ShowUninstDetails hide -Name "${prodname}" -Caption "${prodname}" +Name "${company}" +Caption "${company}" !ifdef icon Icon "${icon}" @@ -36,7 +35,7 @@ SetDatablockOptimize on CRCCheck on SilentInstall normal -InstallDir "${install_dir_product}" +InstallDir "${install_dir_company}" InstallDirRegKey HKLM "${regkey}" "" ; Page components @@ -88,35 +87,28 @@ Section "Registry Entries and Procotol Handler" SEC02 SectionIn RO WriteRegStr HKLM "${regkey}" "Install_Dir" "$INSTDIR" - WriteRegStr HKLM "${uninstkey}" "DisplayName" "${prodname} (remove only)" + WriteRegStr HKLM "${uninstkey}" "DisplayName" "${company} (remove only)" WriteRegStr HKLM "${uninstkey}" "UninstallString" '"$INSTDIR\${uninstaller}"' - WriteRegStr HKCR "${prodname}\Shell\open\command\" "" '"$INSTDIR\${exec} "%1"' - - !ifdef icon - WriteRegStr HKCR "${prodname}\DefaultIcon" "" "$INSTDIR\${icon}" - !endif + WriteRegStr HKCR "${company}\Shell\open\command\" "" '"$INSTDIR\${interface_exec} "%1"' + WriteRegStr HKCR "${company}\DefaultIcon" "" "$INSTDIR\${interface_icon}" ; hifi:// protocol handler registry entries WriteRegStr HKCR 'hifi' '' 'URL:Alert Protocol' WriteRegStr HKCR 'hifi' 'URL Protocol' '' - WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${icon},1' - WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${exec} --url "%1"' + WriteRegStr HKCR 'hifi\DefaultIcon' '' '$INSTDIR\${interface_icon},1' + WriteRegStr HKCR 'hifi\shell\open\command' '' '$INSTDIR\${interface_exec} --url "%1"' SetOutPath $INSTDIR ; package all files, recursively, preserving attributes ; assume files are in the correct places File /r "${srcdir}\" - !ifdef icon - File /a "${icon}" - !endif + File /a "${srcdir}\${interface_icon}" + File /a "${srcdir}\${stack_manager_icon}" ; any application-specific files !ifdef files !include "${files}" !endif - SetOutPath "$DOCUMENTS\${company}\Scripts" - File /r "${scriptsdir}\" - SetOutPath $INSTDIR WriteUninstaller "${uninstaller}" Exec '"$INSTDIR\2013_vcredist_x64.exe" /q /norestart' Exec '"$INSTDIR\2010_vcredist_x86.exe" /q /norestart' @@ -129,24 +121,20 @@ Section "Start Menu Shortcuts" SEC03 ; This should install the shortcuts for "All Users" SetShellVarContext all - CreateDirectory "${startmenu_product}" + CreateDirectory "${startmenu_company}" SetOutPath $INSTDIR ; for working directory - !ifdef icon - CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" "" "$INSTDIR\${icon}" - !else - CreateShortCut "${startmenu_product}\${prodname}.lnk" "$INSTDIR\${exec}" - !endif - - CreateShortCut "${startmenu_product}\Uninstall ${prodname}.lnk" "$INSTDIR\${uninstaller}" + CreateShortCut "${startmenu_company}\Interface.lnk" "$INSTDIR\${interface_exec}" "" "$INSTDIR\${interface_icon}" + CreateShortCut "${startmenu_company}\Stack Manager.lnk" "$INSTDIR\${stack_manager_exec}" "" "$INSTDIR\${stack_manager_icon}" + CreateShortCut "${startmenu_company}\Uninstall ${company}.lnk" "$INSTDIR\${uninstaller}" SectionEnd ; Uninstaller ; All section names prefixed by "Un" will be in the uninstaller -UninstallText "This will uninstall ${prodname}." +UninstallText "This will uninstall ${company}." !ifdef icon - UninstallIcon "${icon}" + UninstallIcon "${interface_icon}" !endif Section "Uninstall" SEC04 @@ -155,11 +143,10 @@ Section "Uninstall" SEC04 ; Explicitly remove all added shortcuts SetShellVarContext all - DELETE "${startmenu_product}\${prodname}.lnk" - DELETE "${startmenu_product}\Uninstall ${prodname}.lnk" + DELETE "${startmenu_company}\Interface.lnk" + DELETE "${startmenu_company}\Stack Manager.lnk" + DELETE "${startmenu_company}\Uninstall ${company}.lnk" - RMDIR "${startmenu_product}" - ; This should remove the High Fidelity folder in Start Menu if it's empty RMDIR "${startmenu_company}" RMDIR /r "$INSTDIR" From 66770cc907c654d03b01dd6dc3b5a294467955b8 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:11:35 -0600 Subject: [PATCH 16/38] Finishing touches --- CMakeLists.txt | 6 ++++-- cmake/macros/IncludeApplicationVersion.cmake | 17 +++++++++++++---- tools/nsis/release.nsi | 13 +++++++------ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69e6365c8c..ca3e381405 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -239,8 +239,10 @@ if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) build-package ALL DEPENDS interface assignment-client domain-server stack-manager COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment - COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/this-is-a-test.exe - COMMANE set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} + COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} + COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" ) endif () \ No newline at end of file diff --git a/cmake/macros/IncludeApplicationVersion.cmake b/cmake/macros/IncludeApplicationVersion.cmake index a91aad6acc..753a12a01c 100644 --- a/cmake/macros/IncludeApplicationVersion.cmake +++ b/cmake/macros/IncludeApplicationVersion.cmake @@ -14,13 +14,22 @@ macro(INCLUDE_APPLICATION_VERSION) # We are relying on Jenkins defined environment variables to determine the origin of this build # and will only package if this is a PR or Release build if (DEFINED ENV{JOB_ID}) - set (DEPLOY_PACKAGE 1) - set (BUILD_SEQ $ENV{JOB_ID}) + set(DEPLOY_PACKAGE 1) + set(BUILD_SEQ $ENV{JOB_ID}) + set(INSTALLER_COMPANY "High Fidelity") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(INSTALLER_NAME "interface-win64-${BUILD_SEQ}.exe") elseif (DEFINED ENV{ghprbPullId}) - set (DEPLOY_PACKAGE 1) - set (BUILD_SEQ "PR-$ENV{ghprbPullId}") + set(DEPLOY_PACKAGE 1) + set(BUILD_SEQ "PR-$ENV{ghprbPullId}") + set(INSTALLER_COMPANY "High Fidelity - PR") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}\\${BUILD_SEQ}") + set(INSTALLER_NAME "pr-interface-win64-${BUILD_SEQ}.exe") else () set(BUILD_SEQ "dev") + set(INSTALLER_COMPANY "High Fidelity - Dev") + set(INSTALLER_DIRECTORY "${INSTALLER_COMPANY}") + set(INSTALLER_NAME "dev-interface-win64.exe") endif () configure_file("${MACRO_DIR}/ApplicationVersion.h.in" "${PROJECT_BINARY_DIR}/includes/ApplicationVersion.h") include_directories("${PROJECT_BINARY_DIR}/includes") diff --git a/tools/nsis/release.nsi b/tools/nsis/release.nsi index 86ea055e6b..9bc75e5274 100644 --- a/tools/nsis/release.nsi +++ b/tools/nsis/release.nsi @@ -1,18 +1,19 @@ !include LogicLib.nsh !include x64.nsh -!define srcdir $%INSTALLER_SOURCE_DIR% -!define setup $%INSTALLER_NAME% -!define scriptsdir $%INSTALLER_SCRIPTS_DIR% -!define company $%INSTALLER_COMPANY% +!define srcdir "$%INSTALLER_SOURCE_DIR%" +!define setup "$%INSTALLER_NAME%" +!define scriptsdir "$%INSTALLER_SCRIPTS_DIR%" +!define company "$%INSTALLER_COMPANY%" +!define install_directory "$%INSTALLER_DIRECTORY%" !define interface_exec "interface.exe" !define stack_manager_exec "stack-manager.exe" !define interface_icon "interface.ico" !define stack_manager_icon "stack-manager.ico" !define regkey "Software\${company}" !define uninstkey "Software\Microsoft\Windows\CurrentVersion\Uninstall\${company}" -!define install_dir_company "$PROGRAMFILES64\${company}" -!define startmenu_company "$SMPROGRAMS\${company}" +!define install_dir_company "$PROGRAMFILES64\${install_directory}" +!define startmenu_company "$SMPROGRAMS\${install_directory}" !define uninstaller "uninstall.exe" ;-------------------------------- From bd7fa266cffb2cf142b9da521b21d6bd99ee874a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Dec 2015 11:57:52 -0800 Subject: [PATCH 17/38] Bit of cleanup --- .../src/octree/OctreeQueryNode.cpp | 32 +------------- .../src/octree/OctreeQueryNode.h | 43 ++++++++++--------- .../src/octree/OctreeSendThread.cpp | 8 ++-- .../src/octree/OctreeSendThread.h | 16 +++---- assignment-client/src/octree/OctreeServer.cpp | 1 + 5 files changed, 37 insertions(+), 63 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index ffe2e24ca0..58fd39f73f 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -20,39 +20,11 @@ #include "OctreeSendThread.h" -OctreeQueryNode::OctreeQueryNode() : - _viewSent(false), - _octreePacket(), - _octreePacketWaiting(false), - _lastOctreePayload(new char[udt::MAX_PACKET_SIZE]), - _lastOctreePacketLength(0), - _duplicatePacketCount(0), - _firstSuppressedPacket(usecTimestampNow()), - _maxSearchLevel(1), - _maxLevelReachedInLastSearch(1), - _lastTimeBagEmpty(0), - _viewFrustumChanging(false), - _viewFrustumJustStoppedChanging(true), - _octreeSendThread(NULL), - _lastClientBoundaryLevelAdjust(0), - _lastClientOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE), - _lodChanged(false), - _lodInitialized(false), - _sequenceNumber(0), - _lastRootTimestamp(0), - _myPacketType(PacketType::Unknown), - _isShuttingDown(false), - _sentPacketHistory() -{ -} - OctreeQueryNode::~OctreeQueryNode() { _isShuttingDown = true; if (_octreeSendThread) { forceNodeShutdown(); } - - delete[] _lastOctreePayload; } void OctreeQueryNode::nodeKilled() { @@ -105,7 +77,7 @@ bool OctreeQueryNode::packetIsDuplicate() const { // of the entire packet, we need to compare only the packet content... if (_lastOctreePacketLength == _octreePacket->getPayloadSize()) { - if (memcmp(_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, + if (memcmp(&_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE, _octreePacket->getPayloadSize() - OCTREE_PACKET_EXTRA_HEADERS_SIZE) == 0) { return true; @@ -173,7 +145,7 @@ void OctreeQueryNode::resetOctreePacket() { // scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing // packet send rate. _lastOctreePacketLength = _octreePacket->getPayloadSize(); - memcpy(_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength); + memcpy(&_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength); // If we're moving, and the client asked for low res, then we force monochrome, otherwise, use // the clients requested color state. diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 89583492e0..130e7031d1 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -29,7 +29,7 @@ class OctreeServer; class OctreeQueryNode : public OctreeQuery { Q_OBJECT public: - OctreeQueryNode(); + OctreeQueryNode() {} virtual ~OctreeQueryNode(); void init(); // called after creation to set up some virtual items @@ -110,43 +110,44 @@ private slots: private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); - - bool _viewSent; + + bool _viewSent { false }; std::unique_ptr _octreePacket; bool _octreePacketWaiting; - char* _lastOctreePayload = nullptr; - unsigned int _lastOctreePacketLength; - int _duplicatePacketCount; - quint64 _firstSuppressedPacket; + unsigned int _lastOctreePacketLength { 0 }; + int _duplicatePacketCount { 0 }; + quint64 _firstSuppressedPacket { usecTimestampNow() }; - int _maxSearchLevel; - int _maxLevelReachedInLastSearch; + int _maxSearchLevel { 1 }; + int _maxLevelReachedInLastSearch { 1 }; ViewFrustum _currentViewFrustum; ViewFrustum _lastKnownViewFrustum; - quint64 _lastTimeBagEmpty; - bool _viewFrustumChanging; - bool _viewFrustumJustStoppedChanging; + quint64 _lastTimeBagEmpty { 0 }; + bool _viewFrustumChanging { false }; + bool _viewFrustumJustStoppedChanging { true }; - OctreeSendThread* _octreeSendThread; + OctreeSendThread* _octreeSendThread { nullptr }; // watch for LOD changes - int _lastClientBoundaryLevelAdjust; - float _lastClientOctreeSizeScale; - bool _lodChanged; - bool _lodInitialized; + int _lastClientBoundaryLevelAdjust { 0 }; + float _lastClientOctreeSizeScale { DEFAULT_OCTREE_SIZE_SCALE }; + bool _lodChanged { false }; + bool _lodInitialized { false }; - OCTREE_PACKET_SEQUENCE _sequenceNumber; + OCTREE_PACKET_SEQUENCE _sequenceNumber { 0 }; - quint64 _lastRootTimestamp; + quint64 _lastRootTimestamp { 0 }; - PacketType _myPacketType; - bool _isShuttingDown; + PacketType _myPacketType { PacketType::Unknown }; + bool _isShuttingDown { false }; SentPacketHistory _sentPacketHistory; QQueue _nackedSequenceNumbers; quint64 _sceneSendStartTime = 0; + + std::array _lastOctreePayload; }; #endif // hifi_OctreeQueryNode_h diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index b4eb75ede9..dbd6d117dc 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -14,6 +14,7 @@ #include #include +#include "OctreeQueryNode.h" #include "OctreeSendThread.h" #include "OctreeServer.h" #include "OctreeServerConsts.h" @@ -25,10 +26,7 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), _node(node), - _nodeUUID(node->getUUID()), - _packetData(), - _nodeMissingCount(0), - _isShuttingDown(false) + _nodeUUID(node->getUUID()) { QString safeServerName("Octree"); @@ -46,6 +44,8 @@ OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePoint } OctreeSendThread::~OctreeSendThread() { + setIsShuttingDown(); + QString safeServerName("Octree"); if (_myServer) { safeServerName = _myServer->getMyServerName(); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 6775e56820..64a9c59465 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -18,8 +18,7 @@ #include -#include "OctreeQueryNode.h" - +class OctreeQueryNode; class OctreeServer; using AtomicUIntStat = std::atomic; @@ -48,17 +47,18 @@ protected: virtual bool process(); private: - OctreeServer* _myServer; + int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); + int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); + + + OctreeServer* _myServer { nullptr }; SharedNodePointer _node; QUuid _nodeUUID; - int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); - int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); - OctreePacketData _packetData; - int _nodeMissingCount; - bool _isShuttingDown; + int _nodeMissingCount { 0 }; + bool _isShuttingDown { false }; }; #endif // hifi_OctreeSendThread_h diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index ec34ad4410..d32968596a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -25,6 +25,7 @@ #include "../AssignmentClient.h" +#include "OctreeQueryNode.h" #include "OctreeServerConsts.h" OctreeServer* OctreeServer::_instance = NULL; From b65cdd286524e806283898bd54af32c6b5e5def7 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 14 Dec 2015 15:26:50 -0800 Subject: [PATCH 18/38] Add logging categories to assignment client. --- assignment-client/src/AssignmentClient.cpp | 37 ++++++++++--------- .../src/AssignmentClientLogging.cpp | 14 +++++++ .../src/AssignmentClientLogging.h | 19 ++++++++++ 3 files changed, 52 insertions(+), 18 deletions(-) create mode 100644 assignment-client/src/AssignmentClientLogging.cpp create mode 100644 assignment-client/src/AssignmentClientLogging.h diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index fc0cfe1abb..bbee597797 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -35,6 +35,7 @@ #include "AssignmentActionFactory.h" #include "AssignmentClient.h" +#include "AssignmentClientLogging.h" #include "avatars/ScriptableAvatar.h" const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client"; @@ -84,7 +85,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri // check for a wallet UUID on the command line or in the config // this would represent where the user running AC wants funds sent to if (!walletUUID.isNull()) { - qDebug() << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); + qCDebug(assigmnentclient) << "The destination wallet UUID for credits is" << uuidStringWithoutCurlyBraces(walletUUID); _requestAssignment.setWalletUUID(walletUUID); } @@ -98,13 +99,13 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri _assignmentServerSocket.setObjectName("AssigmentServer"); nodeList->setAssignmentServerSocket(_assignmentServerSocket); - qDebug() << "Assignment server socket is" << _assignmentServerSocket; + qCDebug(assigmnentclient) << "Assignment server socket is" << _assignmentServerSocket; // call a timer function every ASSIGNMENT_REQUEST_INTERVAL_MSECS to ask for assignment, if required - qDebug() << "Waiting for assignment -" << _requestAssignment; + qCDebug(assigmnentclient) << "Waiting for assignment -" << _requestAssignment; if (_assignmentServerHostname != "localhost") { - qDebug () << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); + qCDebug(assigmnentclient) << "- will attempt to connect to domain-server on" << _assignmentServerSocket.getPort(); } connect(&_requestTimer, SIGNAL(timeout()), SLOT(sendAssignmentRequest())); @@ -122,7 +123,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri _assignmentClientMonitorSocket = HifiSockAddr(DEFAULT_ASSIGNMENT_CLIENT_MONITOR_HOSTNAME, assignmentMonitorPort); _assignmentClientMonitorSocket.setObjectName("AssignmentClientMonitor"); - qDebug() << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; + qCDebug(assigmnentclient) << "Assignment-client monitor socket is" << _assignmentClientMonitorSocket; // Hook up a timer to send this child's status to the Monitor once per second setUpStatusToMonitor(); @@ -133,7 +134,7 @@ AssignmentClient::AssignmentClient(Assignment::Type requestAssignmentType, QStri } void AssignmentClient::stopAssignmentClient() { - qDebug() << "Forced stop of assignment-client."; + qCDebug(assigmnentclient) << "Forced stop of assignment-client."; _requestTimer.stop(); _statsTimerACM.stop(); @@ -209,14 +210,14 @@ void AssignmentClient::sendAssignmentRequest() { quint16 localAssignmentServerPort; if (nodeList->getLocalServerPortFromSharedMemory(DOMAIN_SERVER_LOCAL_PORT_SMEM_KEY, localAssignmentServerPort)) { if (localAssignmentServerPort != _assignmentServerSocket.getPort()) { - qDebug() << "Port for local assignment server read from shared memory is" + qCDebug(assigmnentclient) << "Port for local assignment server read from shared memory is" << localAssignmentServerPort; _assignmentServerSocket.setPort(localAssignmentServerPort); nodeList->setAssignmentServerSocket(_assignmentServerSocket); } } else { - qDebug() << "Failed to read local assignment server port from shared memory" + qCWarning(assigmnentclient) << "Failed to read local assignment server port from shared memory" << "- will send assignment request to previous assignment server socket."; } } @@ -226,13 +227,13 @@ void AssignmentClient::sendAssignmentRequest() { } void AssignmentClient::handleCreateAssignmentPacket(QSharedPointer message) { - qDebug() << "Received a PacketType::CreateAssignment - attempting to unpack."; + qCDebug(assigmnentclient) << "Received a PacketType::CreateAssignment - attempting to unpack."; // construct the deployed assignment from the packet data _currentAssignment = AssignmentFactory::unpackAssignment(*message); if (_currentAssignment && !_isAssigned) { - qDebug() << "Received an assignment -" << *_currentAssignment; + qDebug(assigmnentclient) << "Received an assignment -" << *_currentAssignment; _isAssigned = true; auto nodeList = DependencyManager::get(); @@ -242,7 +243,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointergetDomainHandler().setSockAddr(message->getSenderSockAddr(), _assignmentServerHostname); nodeList->getDomainHandler().setAssignmentUUID(_currentAssignment->getUUID()); - qDebug() << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); + qCDebug(assigmnentclient) << "Destination IP for assignment is" << nodeList->getDomainHandler().getIP().toString(); // start the deployed assignment QThread* workerThread = new QThread; @@ -270,7 +271,7 @@ void AssignmentClient::handleCreateAssignmentPacket(QSharedPointerstarted() workerThread->start(); } else { - qDebug() << "Received an assignment that could not be unpacked. Re-requesting."; + qCWarning(assigmnentclient) << "Received an assignment that could not be unpacked. Re-requesting."; } } @@ -278,12 +279,12 @@ void AssignmentClient::handleStopNodePacket(QSharedPointer mess const HifiSockAddr& senderSockAddr = message->getSenderSockAddr(); if (senderSockAddr.getAddress() == QHostAddress::LocalHost || - senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { - qDebug() << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; - + senderSockAddr.getAddress() == QHostAddress::LocalHostIPv6) { + + qCDebug(assigmnentclient) << "AssignmentClientMonitor at" << senderSockAddr << "requested stop via PacketType::StopNode."; QCoreApplication::quit(); } else { - qDebug() << "Got a stop packet from other than localhost."; + qCWarning(assigmnentclient) << "Got a stop packet from other than localhost."; } } @@ -303,7 +304,7 @@ void AssignmentClient::handleAuthenticationRequest() { // ask the account manager to log us in from the env variables accountManager.requestAccessToken(username, password); } else { - qDebug() << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString()) + qCWarning(assigmnentclient) << "Authentication was requested against" << qPrintable(accountManager.getAuthURL().toString()) << "but both or one of" << qPrintable(DATA_SERVER_USERNAME_ENV) << "/" << qPrintable(DATA_SERVER_PASSWORD_ENV) << "are not set. Unable to authenticate."; @@ -321,7 +322,7 @@ void AssignmentClient::assignmentCompleted() { // reset the logging target to the the CHILD_TARGET_NAME LogHandler::getInstance().setTargetName(ASSIGNMENT_CLIENT_TARGET_NAME); - qDebug() << "Assignment finished or never started - waiting for new assignment."; + qCDebug(assigmnentclient) << "Assignment finished or never started - waiting for new assignment."; auto nodeList = DependencyManager::get(); diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp new file mode 100644 index 0000000000..3e9dbdc53c --- /dev/null +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -0,0 +1,14 @@ +// +// AssignmentClientLogging.cpp +// assignment-client/src +// +// Created by Clement on 12/14/15. +// Copyright 2015 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 +// + +#include "AssignmentClientLogging.h" + +Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignmentclient") \ No newline at end of file diff --git a/assignment-client/src/AssignmentClientLogging.h b/assignment-client/src/AssignmentClientLogging.h new file mode 100644 index 0000000000..d6b5ee90e0 --- /dev/null +++ b/assignment-client/src/AssignmentClientLogging.h @@ -0,0 +1,19 @@ +// +// AssignmentClientLogging.h +// assignment-client/src +// +// Created by Clement on 12/14/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AssignmentClientLogging_h +#define hifi_AssignmentClientLogging_h + +#include + +Q_DECLARE_LOGGING_CATEGORY(assigmnentclient) + +#endif // hifi_AssignmentClientLogging_h \ No newline at end of file From 09701fdcf1cebe6d17249c4653bf4ad27499737d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 10 Dec 2015 14:14:20 -0800 Subject: [PATCH 19/38] deadlock 101 --- assignment-client/src/octree/OctreeServer.cpp | 25 ++++++++++++------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index d32968596a..9f0e7919e4 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1460,15 +1460,22 @@ void OctreeServer::didCallWriteDatagram(OctreeSendThread* thread) { void OctreeServer::stopTrackingThread(OctreeSendThread* thread) { - QMutexLocker lockerA(&_threadsDidProcessMutex); - QMutexLocker lockerB(&_threadsDidPacketDistributorMutex); - QMutexLocker lockerC(&_threadsDidHandlePacketSendMutex); - QMutexLocker lockerD(&_threadsDidCallWriteDatagramMutex); - - _threadsDidProcess.remove(thread); - _threadsDidPacketDistributor.remove(thread); - _threadsDidHandlePacketSend.remove(thread); - _threadsDidCallWriteDatagram.remove(thread); + { + QMutexLocker locker(&_threadsDidProcessMutex); + _threadsDidProcess.remove(thread); + } + { + QMutexLocker locker(&_threadsDidPacketDistributorMutex); + _threadsDidPacketDistributor.remove(thread); + } + { + QMutexLocker locker(&_threadsDidHandlePacketSendMutex); + _threadsDidHandlePacketSend.remove(thread); + } + { + QMutexLocker locker(&_threadsDidCallWriteDatagramMutex); + _threadsDidCallWriteDatagram.remove(thread); + } } int howManyThreadsDidSomething(QMutex& mutex, QMap& something, quint64 since) { From 346c28f9e21e231a89e6af8c7f65df4044c8f61e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 15:02:04 -0800 Subject: [PATCH 20/38] Remove OctreeServer's static instance --- assignment-client/src/octree/OctreeServer.cpp | 15 ++------------- assignment-client/src/octree/OctreeServer.h | 2 -- libraries/networking/src/LimitedNodeList.h | 2 +- 3 files changed, 3 insertions(+), 16 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9f0e7919e4..4f572760b1 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -28,7 +28,6 @@ #include "OctreeQueryNode.h" #include "OctreeServerConsts.h" -OctreeServer* OctreeServer::_instance = NULL; int OctreeServer::_clientCount = 0; const int MOVING_AVERAGE_SAMPLE_COUNTS = 1000000; @@ -232,13 +231,6 @@ OctreeServer::OctreeServer(ReceivedMessage& message) : _started(time(0)), _startedUSecs(usecTimestampNow()) { - if (_instance) { - qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]"; - } - - qDebug() << "Octree Server starting... setting _instance to=[" << this << "]"; - _instance = this; - _averageLoopTime.updateAverage(0); qDebug() << "Octree server starting... [" << this << "]"; @@ -282,9 +274,6 @@ OctreeServer::~OctreeServer() { _tree.reset(); qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]"; - if (_instance == this) { - _instance = NULL; // we are gone - } qDebug() << qPrintable(_safeServerName) << "server DONE shutting down... [" << this << "]"; } @@ -1118,8 +1107,8 @@ void OctreeServer::domainSettingsRequestComplete() { setvbuf(stdout, NULL, _IOLBF, 0); #endif - nodeList->linkedDataCreateCallback = [] (Node* node) { - auto queryNodeData = _instance->createOctreeQueryNode(); + nodeList->linkedDataCreateCallback = [this](Node* node) { + auto queryNodeData = createOctreeQueryNode(); queryNodeData->init(); node->setLinkedData(std::move(queryNodeData)); }; diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 80668f841c..51fe6d46c3 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -187,8 +187,6 @@ protected: int _backupInterval; int _maxBackupVersions; - static OctreeServer* _instance; - time_t _started; quint64 _startedUSecs; QString _safeServerName; diff --git a/libraries/networking/src/LimitedNodeList.h b/libraries/networking/src/LimitedNodeList.h index c89949b9fd..87ed12ac66 100644 --- a/libraries/networking/src/LimitedNodeList.h +++ b/libraries/networking/src/LimitedNodeList.h @@ -129,7 +129,7 @@ public: qint64 sendPacketList(std::unique_ptr packetList, const HifiSockAddr& sockAddr); qint64 sendPacketList(std::unique_ptr packetList, const Node& destinationNode); - void (*linkedDataCreateCallback)(Node *); + std::function linkedDataCreateCallback; size_t size() const { return _nodeHash.size(); } From 562d9ac2de4507f1250096992b0611e9280b497a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:30:31 -0800 Subject: [PATCH 21/38] Forward QThread's finished signal in GenericThread --- libraries/shared/src/GenericThread.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 66af2e01c8..4fdd2eb1d2 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -38,9 +38,10 @@ void GenericThread::initialize(bool isThreaded, QThread::Priority priority) { _thread->setObjectName(objectName()); // when the worker thread is started, call our engine's run.. - connect(_thread, SIGNAL(started()), this, SLOT(threadRoutine())); + connect(_thread, &QThread::started, this, &GenericThread::threadRoutine); + connect(_thread, &QThread::finished, this, &GenericThread::finished); - this->moveToThread(_thread); + moveToThread(_thread); // Starts an event loop, and emits _thread->started() _thread->start(); @@ -82,5 +83,4 @@ void GenericThread::threadRoutine() { if (_isThreaded && _thread) { _thread->quit(); } - emit finished(); } From 95da71b19c9812b6ff020cbc741b11c39bcfd279 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:33:40 -0800 Subject: [PATCH 22/38] Assignment don't inherit from NodeData This is an artefact from an old design that stuck around --- libraries/networking/src/Assignment.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 399deaa314..97caedcfb3 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -23,7 +23,7 @@ const int MAX_PAYLOAD_BYTES = 1024; const QString emptyPool = QString(); /// Holds information used for request, creation, and deployment of assignments -class Assignment : public NodeData { +class Assignment : public QObject { Q_OBJECT public: From 3cd1eea1dc67f1b22c5f4cee610a473765909bfe Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:35:22 -0800 Subject: [PATCH 23/38] Use weak pointer to the Node instead of strong ownership --- .../src/octree/OctreeSendThread.cpp | 44 +++++++++---------- .../src/octree/OctreeSendThread.h | 7 ++- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index dbd6d117dc..6215712c6c 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -25,8 +25,7 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), - _node(node), - _nodeUUID(node->getUUID()) + _node(node) { QString safeServerName("Octree"); @@ -56,8 +55,6 @@ OctreeSendThread::~OctreeSendThread() { OctreeServer::clientDisconnected(); OctreeServer::stopTrackingThread(this); - - _node.clear(); } void OctreeSendThread::setIsShuttingDown() { @@ -79,15 +76,17 @@ bool OctreeSendThread::process() { // don't do any send processing until the initial load of the octree is complete... if (_myServer->isInitialLoadComplete()) { - if (_node) { + if (auto node = _node.lock()) { _nodeMissingCount = 0; - OctreeQueryNode* nodeData = static_cast(_node->getLinkedData()); + OctreeQueryNode* nodeData = static_cast(node->getLinkedData()); // Sometimes the node data has not yet been linked, in which case we can't really do anything if (nodeData && !nodeData->isShuttingDown()) { bool viewFrustumChanged = nodeData->updateCurrentViewFrustum(); - packetDistributor(nodeData, viewFrustumChanged); + packetDistributor(node, nodeData, viewFrustumChanged); } + } else { + return false; // exit early if we're shutting down } } @@ -123,7 +122,8 @@ AtomicUIntStat OctreeSendThread::_totalSpecialBytes { 0 }; AtomicUIntStat OctreeSendThread::_totalSpecialPackets { 0 }; -int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) { +int OctreeSendThread::handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, + int& truePacketsSent) { OctreeServer::didHandlePacketSend(this); // if we're shutting down, then exit early @@ -183,12 +183,12 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes // actually send it OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(statsPacket, *_node); + DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); packetSent = true; } else { // not enough room in the packet, send two packets OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(statsPacket, *_node); + DependencyManager::get()->sendUnreliablePacket(statsPacket, *node); // since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since // there was nothing else to send. @@ -219,7 +219,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes packetsSent++; OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *_node); + DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); @@ -251,7 +251,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) { // just send the octree packet OctreeServer::didCallWriteDatagram(this); - DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *_node); + DependencyManager::get()->sendUnreliablePacket(nodeData->getPacket(), *node); packetSent = true; int packetSizeWithHeader = nodeData->getPacket().getDataSize(); @@ -293,7 +293,7 @@ int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytes } /// Version of octree element distributor that sends the deepest LOD level at once -int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) { +int OctreeSendThread::packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged) { OctreeServer::didPacketDistributor(this); @@ -322,7 +322,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // If we have a packet waiting, and our desired want color, doesn't match the current waiting packets color // then let's just send that waiting packet. if (nodeData->isPacketWaiting()) { - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } else { nodeData->resetOctreePacket(); } @@ -355,7 +355,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus //unsigned long encodeTime = nodeData->stats.getTotalEncodeTime(); //unsigned long elapsedTime = nodeData->stats.getElapsedTime(); - int packetsJustSent = handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); packetsSentThisInterval += packetsJustSent; // If we're starting a full scene, then definitely we want to empty the elementBag @@ -431,8 +431,8 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Our trackSend() function is implemented by the server subclass, and will be called back // during the encodeTreeBitstream() as new entities/data elements are sent - params.trackSend = [this](const QUuid& dataID, quint64 dataEdited) { - _myServer->trackSend(dataID, dataEdited, _nodeUUID); + params.trackSend = [this, node](const QUuid& dataID, quint64 dataEdited) { + _myServer->trackSend(dataID, dataEdited, node->getUUID()); }; // TODO: should this include the lock time or not? This stat is sent down to the client, @@ -481,7 +481,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus unsigned int writtenSize = _packetData.getFinalizedSize() + sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); if (writtenSize > nodeData->getAvailable()) { - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); } nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize()); @@ -501,7 +501,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus int targetSize = MAX_OCTREE_PACKET_DATA_SIZE; if (sendNow) { quint64 packetSendingStart = usecTimestampNow(); - packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent); + packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent); quint64 packetSendingEnd = usecTimestampNow(); packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart); @@ -538,9 +538,9 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus // Here's where we can/should allow the server to send other data... // send the environment packet // TODO: should we turn this into a while loop to better handle sending multiple special packets - if (_myServer->hasSpecialPacketsToSend(_node) && !nodeData->isShuttingDown()) { + if (_myServer->hasSpecialPacketsToSend(node) && !nodeData->isShuttingDown()) { int specialPacketsSent = 0; - trueBytesSent += _myServer->sendSpecialPackets(_node, nodeData, specialPacketsSent); + trueBytesSent += _myServer->sendSpecialPackets(node, nodeData, specialPacketsSent); nodeData->resetOctreePacket(); // because nodeData's _sequenceNumber has changed truePacketsSent += specialPacketsSent; packetsSentThisInterval += specialPacketsSent; @@ -556,7 +556,7 @@ int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrus while (nodeData->hasNextNackedPacket() && packetsSentThisInterval < maxPacketsPerInterval) { const NLPacket* packet = nodeData->getNextNackedPacket(); if (packet) { - DependencyManager::get()->sendUnreliablePacket(*packet, *_node); + DependencyManager::get()->sendUnreliablePacket(*packet, *node); truePacketsSent++; packetsSentThisInterval++; diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index 64a9c59465..e3c47343b0 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -47,13 +47,12 @@ protected: virtual bool process(); private: - int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); - int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged); + int handlePacketSend(SharedNodePointer node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent); + int packetDistributor(SharedNodePointer node, OctreeQueryNode* nodeData, bool viewFrustumChanged); OctreeServer* _myServer { nullptr }; - SharedNodePointer _node; - QUuid _nodeUUID; + QWeakPointer _node; OctreePacketData _packetData; From 51ec7ae2edbce416fd4c0bf477deec94eff46c28 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Dec 2015 16:51:28 -0800 Subject: [PATCH 24/38] Keep UUID of node in send thread --- assignment-client/src/octree/OctreeSendThread.cpp | 5 +++-- assignment-client/src/octree/OctreeSendThread.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeSendThread.cpp b/assignment-client/src/octree/OctreeSendThread.cpp index 6215712c6c..2ff06c7439 100644 --- a/assignment-client/src/octree/OctreeSendThread.cpp +++ b/assignment-client/src/octree/OctreeSendThread.cpp @@ -25,12 +25,13 @@ quint64 endSceneSleepTime = 0; OctreeSendThread::OctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) : _myServer(myServer), - _node(node) + _node(node), + _nodeUuid(node->getUUID()) { QString safeServerName("Octree"); // set our QThread object name so we can identify this thread while debugging - setObjectName(QString("Octree Send Thread (%1)").arg(uuidStringWithoutCurlyBraces(node->getUUID()))); + setObjectName(QString("Octree Send Thread (%1)").arg(uuidStringWithoutCurlyBraces(_nodeUuid))); if (_myServer) { safeServerName = _myServer->getMyServerName(); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index e3c47343b0..c77a327e70 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -31,6 +31,7 @@ public: virtual ~OctreeSendThread(); void setIsShuttingDown(); + QUuid getNodeUuid() const { return _nodeUuid; } static AtomicUIntStat _totalBytes; static AtomicUIntStat _totalWastedBytes; @@ -53,6 +54,7 @@ private: OctreeServer* _myServer { nullptr }; QWeakPointer _node; + QUuid _nodeUuid; OctreePacketData _packetData; From a541fdd2df445d864dfa7b4435dee65b0317694c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 10:04:20 -0800 Subject: [PATCH 25/38] Move OctreeSendThread to the OctreeServer --- .../src/octree/OctreeQueryNode.cpp | 44 ------------ .../src/octree/OctreeQueryNode.h | 11 +-- .../src/octree/OctreeSendThread.h | 2 + assignment-client/src/octree/OctreeServer.cpp | 72 +++++++++---------- assignment-client/src/octree/OctreeServer.h | 5 +- libraries/shared/src/GenericThread.cpp | 1 - 6 files changed, 40 insertions(+), 95 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.cpp b/assignment-client/src/octree/OctreeQueryNode.cpp index 58fd39f73f..044b44a165 100644 --- a/assignment-client/src/octree/OctreeQueryNode.cpp +++ b/assignment-client/src/octree/OctreeQueryNode.cpp @@ -20,52 +20,8 @@ #include "OctreeSendThread.h" -OctreeQueryNode::~OctreeQueryNode() { - _isShuttingDown = true; - if (_octreeSendThread) { - forceNodeShutdown(); - } -} - void OctreeQueryNode::nodeKilled() { _isShuttingDown = true; - if (_octreeSendThread) { - // just tell our thread we want to shutdown, this is asynchronous, and fast, we don't need or want it to block - // while the thread actually shuts down - _octreeSendThread->setIsShuttingDown(); - } -} - -void OctreeQueryNode::forceNodeShutdown() { - _isShuttingDown = true; - if (_octreeSendThread) { - // we really need to force our thread to shutdown, this is synchronous, we will block while the thread actually - // shuts down because we really need it to shutdown, and it's ok if we wait for it to complete - OctreeSendThread* sendThread = _octreeSendThread; - _octreeSendThread = NULL; - sendThread->setIsShuttingDown(); - sendThread->terminate(); - delete sendThread; - } -} - -void OctreeQueryNode::sendThreadFinished() { - // We've been notified by our thread that it is shutting down. So we can clean up our reference to it, and - // delete the actual thread object. Cleaning up our thread will correctly unroll all refereces to shared - // pointers to our node as well as the octree server assignment - if (_octreeSendThread) { - OctreeSendThread* sendThread = _octreeSendThread; - _octreeSendThread = NULL; - delete sendThread; - } -} - -void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node) { - _octreeSendThread = new OctreeSendThread(myServer, node); - - // we want to be notified when the thread finishes - connect(_octreeSendThread, &GenericThread::finished, this, &OctreeQueryNode::sendThreadFinished); - _octreeSendThread->initialize(true); } bool OctreeQueryNode::packetIsDuplicate() const { diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 130e7031d1..4313d101fd 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -29,8 +29,8 @@ class OctreeServer; class OctreeQueryNode : public OctreeQuery { Q_OBJECT public: - OctreeQueryNode() {} - virtual ~OctreeQueryNode(); + OctreeQueryNode() = default; + virtual ~OctreeQueryNode() = default; void init(); // called after creation to set up some virtual items virtual PacketType getMyPacketType() const = 0; @@ -79,9 +79,6 @@ public: OctreeSceneStats stats; - void initializeOctreeSendThread(OctreeServer* myServer, const SharedNodePointer& node); - bool isOctreeSendThreadInitalized() { return _octreeSendThread; } - void dumpOutOfView(); quint64 getLastRootTimestamp() const { return _lastRootTimestamp; } @@ -92,7 +89,6 @@ public: void sceneStart(quint64 sceneSendStartTime) { _sceneSendStartTime = sceneSendStartTime; } void nodeKilled(); - void forceNodeShutdown(); bool isShuttingDown() const { return _isShuttingDown; } void octreePacketSent() { packetSent(*_octreePacket); } @@ -104,9 +100,6 @@ public: bool hasNextNackedPacket() const; const NLPacket* getNextNackedPacket(); -private slots: - void sendThreadFinished(); - private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); diff --git a/assignment-client/src/octree/OctreeSendThread.h b/assignment-client/src/octree/OctreeSendThread.h index c77a327e70..38f5de722f 100644 --- a/assignment-client/src/octree/OctreeSendThread.h +++ b/assignment-client/src/octree/OctreeSendThread.h @@ -31,6 +31,8 @@ public: virtual ~OctreeSendThread(); void setIsShuttingDown(); + bool isShuttingDown() { return _isShuttingDown; } + QUuid getNodeUuid() const { return _nodeUuid; } static AtomicUIntStat _totalBytes; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 4f572760b1..f42431589e 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -868,16 +868,28 @@ void OctreeServer::parsePayload() { } } +void OctreeServer::removeSendThread() { + auto sendThread = static_cast(sender()); + + // This deletes the unique_ptr, so sendThread is destructed after that line + _sendThreads.erase(sendThread->getNodeUuid()); +} + void OctreeServer::handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { - if (!_isFinished) { + if (!_isFinished && !_isShuttingDown) { // If we got a query packet, then we're talking to an agent, and we // need to make sure we have it in our nodeList. auto nodeList = DependencyManager::get(); nodeList->updateNodeWithDataFromPacket(message, senderNode); - OctreeQueryNode* nodeData = dynamic_cast(senderNode->getLinkedData()); - if (nodeData && !nodeData->isOctreeSendThreadInitalized()) { - nodeData->initializeOctreeSendThread(this, senderNode); + auto it = _sendThreads.find(senderNode->getUUID()); + if (it == _sendThreads.end() || it->second->isShuttingDown()) { + auto sendThread = std::unique_ptr(new OctreeSendThread(this, senderNode)); + + // we want to be notified when the thread finishes + connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); + sendThread->initialize(true); + _sendThreads.emplace(senderNode->getUUID(), std::move(sendThread)); } } } @@ -1157,6 +1169,12 @@ void OctreeServer::nodeAdded(SharedNodePointer node) { void OctreeServer::nodeKilled(SharedNodePointer node) { quint64 start = usecTimestampNow(); + + // Shutdown send thread + auto it = _sendThreads.find(node->getUUID()); + if (it != _sendThreads.end()) { + it->second->setIsShuttingDown(); + } // calling this here since nodeKilled slot in ReceivedPacketProcessor can't be triggered by signals yet!! _octreeInboundPacketProcessor->nodeKilled(node); @@ -1178,24 +1196,6 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { trackViewerGone(node->getUUID()); } -void OctreeServer::forceNodeShutdown(SharedNodePointer node) { - quint64 start = usecTimestampNow(); - - qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node; - OctreeQueryNode* nodeData = dynamic_cast(node->getLinkedData()); - if (nodeData) { - nodeData->forceNodeShutdown(); // tell our node data and sending threads that we'd like to shut down - } else { - qDebug() << qPrintable(_safeServerName) << "server node missing linked data node:" << *node; - } - - quint64 end = usecTimestampNow(); - quint64 usecsElapsed = (end - start); - qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: " - << usecsElapsed << " usecs for node:" << *node; -} - - void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish..."; @@ -1204,9 +1204,8 @@ void OctreeServer::aboutToFinish() { qDebug() << qPrintable(_safeServerName) << "inform Octree Inbound Packet Processor that we are shutting down..."; // we're going down - set the NodeList linkedDataCallback to NULL so we do not create any more OctreeQueryNode objects. - // This ensures that when we forceNodeShutdown below for each node we don't get any more newly connecting nodes - auto nodeList = DependencyManager::get(); - nodeList->linkedDataCreateCallback = NULL; + // This ensures that we don't get any more newly connecting nodes + DependencyManager::get()->linkedDataCreateCallback = NULL; if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); @@ -1216,27 +1215,20 @@ void OctreeServer::aboutToFinish() { _jurisdictionSender->terminating(); } - QSet nodesToShutdown; - - // Force a shutdown of all of our OctreeSendThreads. - // At this point it has to be impossible for a linkedDataCreateCallback to be called for a new node - nodeList->eachNode([&nodesToShutdown](const SharedNodePointer& node) { - nodesToShutdown << node; - }); - - // What follows is a hack to force OctreeSendThreads to cleanup before the OctreeServer is gone. - // I would prefer to allow the SharedNodePointer ref count drop to zero to do this automatically - // but that isn't possible as long as the OctreeSendThread has an OctreeServer* that it uses. - for (auto& node : nodesToShutdown) { - qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node; - forceNodeShutdown(node); + // Shut down all the send threads + for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { + it->second->disconnect(this); // Disconnect so that removeSendThread doesn't get called later + it->second->setIsShuttingDown(); } + + // Wait on all send threads to be done before continuing + _sendThreads.clear(); if (_persistThread) { _persistThread->aboutToFinish(); _persistThread->terminating(); } - + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 51fe6d46c3..98f6c79893 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -124,7 +124,6 @@ public: bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url, bool skipSubHandler); virtual void aboutToFinish(); - void forceNodeShutdown(SharedNodePointer node); public slots: /// runs the octree server assignment @@ -138,6 +137,7 @@ private slots: void handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode); void handleOctreeDataNackPacket(QSharedPointer message, SharedNodePointer senderNode); void handleJurisdictionRequestPacket(QSharedPointer message, SharedNodePointer senderNode); + void removeSendThread(); protected: virtual OctreePointer createTree() = 0; @@ -190,6 +190,9 @@ protected: time_t _started; quint64 _startedUSecs; QString _safeServerName; + + using SendThreads = std::unordered_map>; + SendThreads _sendThreads; static int _clientCount; static SimpleMovingAverage _averageLoopTime; diff --git a/libraries/shared/src/GenericThread.cpp b/libraries/shared/src/GenericThread.cpp index 4fdd2eb1d2..c1c31ab50a 100644 --- a/libraries/shared/src/GenericThread.cpp +++ b/libraries/shared/src/GenericThread.cpp @@ -15,7 +15,6 @@ GenericThread::GenericThread() : - QObject(), _stopThread(false), _isThreaded(false) // assume non-threaded, must call initialize() { From b4dc3b1b472f1fc5dc8cbedd1691ebca0d746f42 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:07:19 -0800 Subject: [PATCH 26/38] Fix windows compile error. --- assignment-client/src/octree/OctreeServer.cpp | 2 +- libraries/networking/src/LimitedNodeList.cpp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index f42431589e..75252ddf8c 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1205,7 +1205,7 @@ void OctreeServer::aboutToFinish() { // we're going down - set the NodeList linkedDataCallback to NULL so we do not create any more OctreeQueryNode objects. // This ensures that we don't get any more newly connecting nodes - DependencyManager::get()->linkedDataCreateCallback = NULL; + DependencyManager::get()->linkedDataCreateCallback = nullptr; if (_octreeInboundPacketProcessor) { _octreeInboundPacketProcessor->terminating(); diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 4419ba882a..0b194b017e 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -40,7 +40,6 @@ const char SOLO_NODE_TYPES[2] = { }; LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) : - linkedDataCreateCallback(NULL), _sessionUUID(), _nodeHash(), _nodeMutex(QReadWriteLock::Recursive), From a655557af0249cb9ed15d6321f51533d42896fa6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:11:34 -0800 Subject: [PATCH 27/38] Make variable name more obvious --- assignment-client/src/octree/OctreeServer.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 75252ddf8c..acc9537a56 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1173,7 +1173,8 @@ void OctreeServer::nodeKilled(SharedNodePointer node) { // Shutdown send thread auto it = _sendThreads.find(node->getUUID()); if (it != _sendThreads.end()) { - it->second->setIsShuttingDown(); + auto& sendThread = *it->second; + sendThread.setIsShuttingDown(); } // calling this here since nodeKilled slot in ReceivedPacketProcessor can't be triggered by signals yet!! @@ -1217,8 +1218,9 @@ void OctreeServer::aboutToFinish() { // Shut down all the send threads for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { - it->second->disconnect(this); // Disconnect so that removeSendThread doesn't get called later - it->second->setIsShuttingDown(); + auto& sendThread = *it->second; + sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later + sendThread.setIsShuttingDown(); } // Wait on all send threads to be done before continuing From df24fafe49c2ae3563ab9a54b513a680baf41165 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:28:26 -0800 Subject: [PATCH 28/38] CR feedback --- assignment-client/src/octree/OctreeServer.cpp | 17 +++++++++++------ assignment-client/src/octree/OctreeServer.h | 6 +++++- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index acc9537a56..9cb809f48f 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -868,6 +868,16 @@ void OctreeServer::parsePayload() { } } +OctreeServer::UniqueSendThread OctreeServer::createSendThread(const SharedNodePointer& node) { + auto sendThread = std::unique_ptr(new OctreeSendThread(this, node)); + + // we want to be notified when the thread finishes + connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); + sendThread->initialize(true); + + return sendThread; +} + void OctreeServer::removeSendThread() { auto sendThread = static_cast(sender()); @@ -884,12 +894,7 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa auto it = _sendThreads.find(senderNode->getUUID()); if (it == _sendThreads.end() || it->second->isShuttingDown()) { - auto sendThread = std::unique_ptr(new OctreeSendThread(this, senderNode)); - - // we want to be notified when the thread finishes - connect(sendThread.get(), &GenericThread::finished, this, &OctreeServer::removeSendThread); - sendThread->initialize(true); - _sendThreads.emplace(senderNode->getUUID(), std::move(sendThread)); + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } } } diff --git a/assignment-client/src/octree/OctreeServer.h b/assignment-client/src/octree/OctreeServer.h index 98f6c79893..2aabb97428 100644 --- a/assignment-client/src/octree/OctreeServer.h +++ b/assignment-client/src/octree/OctreeServer.h @@ -140,6 +140,9 @@ private slots: void removeSendThread(); protected: + using UniqueSendThread = std::unique_ptr; + using SendThreads = std::unordered_map; + virtual OctreePointer createTree() = 0; bool readOptionBool(const QString& optionName, const QJsonObject& settingsSectionObject, bool& result); bool readOptionInt(const QString& optionName, const QJsonObject& settingsSectionObject, int& result); @@ -153,6 +156,8 @@ protected: QString getFileLoadTime(); QString getConfiguration(); QString getStatusLink(); + + UniqueSendThread createSendThread(const SharedNodePointer& node); int _argc; const char** _argv; @@ -191,7 +196,6 @@ protected: quint64 _startedUSecs; QString _safeServerName; - using SendThreads = std::unordered_map>; SendThreads _sendThreads; static int _clientCount; From 0f7093bed7b259211f29d06bb1a38752c9ce47f6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:35:12 -0800 Subject: [PATCH 29/38] Whitespace --- assignment-client/src/octree/OctreeQueryNode.h | 2 +- assignment-client/src/octree/OctreeServer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeQueryNode.h b/assignment-client/src/octree/OctreeQueryNode.h index 4313d101fd..0ec876e674 100644 --- a/assignment-client/src/octree/OctreeQueryNode.h +++ b/assignment-client/src/octree/OctreeQueryNode.h @@ -103,7 +103,7 @@ public: private: OctreeQueryNode(const OctreeQueryNode &); OctreeQueryNode& operator= (const OctreeQueryNode&); - + bool _viewSent { false }; std::unique_ptr _octreePacket; bool _octreePacketWaiting; diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9cb809f48f..9961b5d688 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1235,7 +1235,7 @@ void OctreeServer::aboutToFinish() { _persistThread->aboutToFinish(); _persistThread->terminating(); } - + qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish..."; } From b55d8f750fed1368ab84e1af2ebb992b8c53fde0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:47:40 -0800 Subject: [PATCH 30/38] CR --- assignment-client/src/octree/OctreeServer.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 9961b5d688..937998f28a 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -1222,14 +1222,15 @@ void OctreeServer::aboutToFinish() { } // Shut down all the send threads - for (auto it = _sendThreads.begin(); it != _sendThreads.end(); ++it) { - auto& sendThread = *it->second; + for (auto& it : _sendThreads) { + auto& sendThread = *it.second; sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later sendThread.setIsShuttingDown(); } - // Wait on all send threads to be done before continuing - _sendThreads.clear(); + // Clear will destruct all the unique_ptr to OctreeSendThreads which will call the GenericThread's dtor + // which waits on the thread to be done before returning + _sendThreads.clear(); // Cleans up all the send threads. if (_persistThread) { _persistThread->aboutToFinish(); From 6bda8d3f18fb32a252e35ba0234965b97c567513 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 11:48:23 -0800 Subject: [PATCH 31/38] CR logging category --- assignment-client/src/AssignmentClientLogging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/assignment-client/src/AssignmentClientLogging.cpp b/assignment-client/src/AssignmentClientLogging.cpp index 3e9dbdc53c..890187ecaa 100644 --- a/assignment-client/src/AssignmentClientLogging.cpp +++ b/assignment-client/src/AssignmentClientLogging.cpp @@ -11,4 +11,4 @@ #include "AssignmentClientLogging.h" -Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignmentclient") \ No newline at end of file +Q_LOGGING_CATEGORY(assigmnentclient, "hifi.assignment-client") \ No newline at end of file From b709c8162c71a05a099273c60db01fba66a5010d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 14:24:52 -0800 Subject: [PATCH 32/38] Fix node flapping race --- assignment-client/src/octree/OctreeServer.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 937998f28a..04b6845ad8 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -879,10 +879,11 @@ OctreeServer::UniqueSendThread OctreeServer::createSendThread(const SharedNodePo } void OctreeServer::removeSendThread() { - auto sendThread = static_cast(sender()); - - // This deletes the unique_ptr, so sendThread is destructed after that line - _sendThreads.erase(sendThread->getNodeUuid()); + // If the object has been deleted since the event was queued, sender() will return nullptr + if (auto sendThread = qobject_cast(sender())) { + // This deletes the unique_ptr, so sendThread is destructed after that line + _sendThreads.erase(sendThread->getNodeUuid()); + } } void OctreeServer::handleOctreeQueryPacket(QSharedPointer message, SharedNodePointer senderNode) { @@ -893,7 +894,13 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa nodeList->updateNodeWithDataFromPacket(message, senderNode); auto it = _sendThreads.find(senderNode->getUUID()); - if (it == _sendThreads.end() || it->second->isShuttingDown()) { + if (it == _sendThreads.end()) { + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); + } else if (it->second->isShuttingDown()) { + auto& sendThread = *it->second; + sendThread.setIsShuttingDown(); + _sendThreads.erase(it); // Remove right away and wait on thread to be + _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } } @@ -1224,7 +1231,6 @@ void OctreeServer::aboutToFinish() { // Shut down all the send threads for (auto& it : _sendThreads) { auto& sendThread = *it.second; - sendThread.disconnect(this); // Disconnect so that removeSendThread doesn't get called later sendThread.setIsShuttingDown(); } From a7b61cf791387695126b9da9a56233ab06ab170a Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:39:09 -0600 Subject: [PATCH 33/38] Couple of fixes --- CMakeLists.txt | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ca3e381405..13d5b2bc79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3.2) +cmake_minimum_required(VERSION 3.2) if (USE_ANDROID_TOOLCHAIN) set(CMAKE_TOOLCHAIN_FILE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/android/android.toolchain.cmake") @@ -228,21 +228,4 @@ if (HIFI_MEMORY_DEBUGGING) endif () include_application_version() - -if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE) - file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") - find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) - if (NOT MAKENSIS_COMMAND) - message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") - endif () - add_custom_target( - build-package ALL - DEPENDS interface assignment-client domain-server stack-manager - COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment - COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} - COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples - COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} - COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} - COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" - ) -endif () \ No newline at end of file +generate_installers() \ No newline at end of file From bbe444ffc1a4833f7b4bab49d81d02a02494782c Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Wed, 16 Dec 2015 16:40:51 -0600 Subject: [PATCH 34/38] Forgot to add file --- cmake/macros/GenerateInstallers.cmake | 30 +++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 cmake/macros/GenerateInstallers.cmake diff --git a/cmake/macros/GenerateInstallers.cmake b/cmake/macros/GenerateInstallers.cmake new file mode 100644 index 0000000000..570e24332b --- /dev/null +++ b/cmake/macros/GenerateInstallers.cmake @@ -0,0 +1,30 @@ +# +# GenerateInstallers.cmake +# cmake/macros +# +# Created by Leonardo Murillo on 12/16/2015. +# Copyright 2015 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 +# + +macro(GENERATE_INSTALLERS) + if (DEFINED DEPLOY_PACKAGE AND DEPLOY_PACKAGE AND WIN32) + file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/full-stack-deployment") + find_program(MAKENSIS_COMMAND makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\NSIS]) + if (NOT MAKENSIS_COMMAND) + message(FATAL_ERROR "The Nullsoft Scriptable Install Systems is required for generating packaged installers on Windows (http://nsis.sourceforge.net/)") + endif () + add_custom_target( + build-package ALL + DEPENDS interface assignment-client domain-server stack-manager + COMMAND set INSTALLER_SOURCE_DIR=${CMAKE_BINARY_DIR}/full-stack-deployment + COMMAND set INSTALLER_NAME=${CMAKE_BINARY_DIR}/${INSTALLER_NAME} + COMMAND set INSTALLER_SCRIPTS_DIR=${CMAKE_SOURCE_DIR}/examples + COMMAND set INSTALLER_COMPANY=${INSTALLER_COMPANY} + COMMAND set INSTALLER_DIRECTORY=${INSTALLER_DIRECTORY} + COMMAND CMD /C "\"${MAKENSIS_COMMAND}\" ${CMAKE_SOURCE_DIR}/tools/nsis/release.nsi" + ) + endif () +endmacro() \ No newline at end of file From 364a70bb46106143a66a9d2f5da038c04c0b2ce0 Mon Sep 17 00:00:00 2001 From: AlessandroSigna Date: Wed, 16 Dec 2015 15:39:45 -0800 Subject: [PATCH 35/38] Fix to avoid MVS warning --- interface/src/ui/overlays/Image3DOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 7d105a6ccf..f1e0f08a3a 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -34,8 +34,8 @@ Image3DOverlay::Image3DOverlay(const Image3DOverlay* image3DOverlay) : Billboard3DOverlay(image3DOverlay), _url(image3DOverlay->_url), _texture(image3DOverlay->_texture), - _fromImage(image3DOverlay->_fromImage), - _emissive(image3DOverlay->_emissive) + _emissive(image3DOverlay->_emissive), + _fromImage(image3DOverlay->_fromImage) { } From 2c8be15e6671df5e74f0241d1185d119a504df16 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Dec 2015 15:56:22 -0800 Subject: [PATCH 36/38] Unnecessary shutdown (Already shutting down) --- assignment-client/src/octree/OctreeServer.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/assignment-client/src/octree/OctreeServer.cpp b/assignment-client/src/octree/OctreeServer.cpp index 04b6845ad8..410aa922dc 100644 --- a/assignment-client/src/octree/OctreeServer.cpp +++ b/assignment-client/src/octree/OctreeServer.cpp @@ -897,8 +897,6 @@ void OctreeServer::handleOctreeQueryPacket(QSharedPointer messa if (it == _sendThreads.end()) { _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); } else if (it->second->isShuttingDown()) { - auto& sendThread = *it->second; - sendThread.setIsShuttingDown(); _sendThreads.erase(it); // Remove right away and wait on thread to be _sendThreads.emplace(senderNode->getUUID(), createSendThread(senderNode)); From 1b0856307976ab348027491b795997b0368551f9 Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 16 Dec 2015 16:56:49 -0800 Subject: [PATCH 37/38] ParticleEffectEntityItem: fix for invalid iterator increment Was causing an assert in debug, due to calling ++ on an invalid iterator. In release this might lead to memory corruption. --- libraries/entities/src/ParticleEffectEntityItem.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 5600c85650..533b077a9c 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -595,19 +595,24 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta void ParticleEffectEntityItem::stepSimulation(float deltaTime) { // update particles between head and tail + int popCount = 0; for (Particle& particle : _particles) { particle.lifetime += deltaTime; // if particle has died. if (particle.lifetime >= _lifespan) { // move head forward - _particles.pop_front(); + popCount++; } else { // Otherwise update it integrateParticle(particle, deltaTime); } } + for (int i = 0; i < popCount; i++) { + _particles.pop_front(); + } + // emit new particles, but only if we are emmitting if (getIsEmitting() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) { From 2eecb61da5a5c9f130522e0cf3cd6907fc5ef95b Mon Sep 17 00:00:00 2001 From: "Anthony J. Thibault" Date: Wed, 16 Dec 2015 19:08:31 -0800 Subject: [PATCH 38/38] Prefer erase over repeated pop_front calls --- libraries/entities/src/ParticleEffectEntityItem.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 533b077a9c..165afd1536 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -608,10 +608,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { integrateParticle(particle, deltaTime); } } - - for (int i = 0; i < popCount; i++) { - _particles.pop_front(); - } + _particles.erase(_particles.begin(), _particles.begin() + popCount); // emit new particles, but only if we are emmitting if (getIsEmitting() && _emitRate > 0.0f && _lifespan > 0.0f && _polarStart <= _polarFinish) {