diff --git a/assignment-client/src/AssignmentClient.cpp b/assignment-client/src/AssignmentClient.cpp index 970b6518ec..aa20f2ff29 100644 --- a/assignment-client/src/AssignmentClient.cpp +++ b/assignment-client/src/AssignmentClient.cpp @@ -18,6 +18,7 @@ #include #include "AssignmentFactory.h" +#include "AssignmentThread.h" #include "AssignmentClient.h" @@ -28,7 +29,7 @@ int hifiSockAddrMeta = qRegisterMetaType("HifiSockAddr"); AssignmentClient::AssignmentClient(int &argc, char **argv) : QCoreApplication(argc, argv), - _currentAssignment(NULL) + _currentAssignment() { setOrganizationName("High Fidelity"); setOrganizationDomain("highfidelity.io"); @@ -124,7 +125,7 @@ void AssignmentClient::readPendingDatagrams() { if (nodeList->packetVersionAndHashMatch(receivedPacket)) { if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) { // construct the deployed assignment from the packet data - _currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket); + _currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket)); if (_currentAssignment) { qDebug() << "Received an assignment -" << *_currentAssignment; @@ -137,14 +138,13 @@ void AssignmentClient::readPendingDatagrams() { qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString(); // start the deployed assignment - QThread* workerThread = new QThread(this); + AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this); - connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); - - connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); - connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); - connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); - connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); + connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run); + connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit); + connect(_currentAssignment.data(), &ThreadedAssignment::finished, + this, &AssignmentClient::assignmentCompleted); + connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater); _currentAssignment->moveToThread(workerThread); @@ -153,7 +153,7 @@ void AssignmentClient::readPendingDatagrams() { // let the assignment handle the incoming datagrams for its duration disconnect(&nodeList->getNodeSocket(), 0, this, 0); - connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment, + connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(), &ThreadedAssignment::readPendingDatagrams); // Starts an event loop, and emits workerThread->started() @@ -202,10 +202,12 @@ void AssignmentClient::assignmentCompleted() { NodeList* nodeList = NodeList::getInstance(); // have us handle incoming NodeList datagrams again - disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment, 0); + disconnect(&nodeList->getNodeSocket(), 0, _currentAssignment.data(), 0); connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, this, &AssignmentClient::readPendingDatagrams); - _currentAssignment = NULL; + // clear our current assignment shared pointer now that we're done with it + // if the assignment thread is still around it has its own shared pointer to the assignment + _currentAssignment.clear(); // reset our NodeList by switching back to unassigned and clearing the list nodeList->setOwnerType(NodeType::Unassigned); diff --git a/assignment-client/src/AssignmentClient.h b/assignment-client/src/AssignmentClient.h index 29187fa3d6..c267c6238b 100644 --- a/assignment-client/src/AssignmentClient.h +++ b/assignment-client/src/AssignmentClient.h @@ -24,7 +24,7 @@ private slots: void handleAuthenticationRequest(); private: Assignment _requestAssignment; - ThreadedAssignment* _currentAssignment; + SharedAssignmentPointer _currentAssignment; }; #endif /* defined(__hifi__AssignmentClient__) */ diff --git a/assignment-client/src/AssignmentThread.cpp b/assignment-client/src/AssignmentThread.cpp new file mode 100644 index 0000000000..dfe093aa7b --- /dev/null +++ b/assignment-client/src/AssignmentThread.cpp @@ -0,0 +1,16 @@ +// +// AssignmentThread.cpp +// hifi +// +// Created by Stephen Birarda on 2014-03-28. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#include "AssignmentThread.h" + +AssignmentThread::AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent) : + QThread(parent), + _assignment(assignment) +{ + +} \ No newline at end of file diff --git a/assignment-client/src/AssignmentThread.h b/assignment-client/src/AssignmentThread.h new file mode 100644 index 0000000000..b55ac10676 --- /dev/null +++ b/assignment-client/src/AssignmentThread.h @@ -0,0 +1,23 @@ +// +// AssignmentThread.h +// hifi +// +// Created by Stephen Birarda on 2014-03-28. +// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AssignmentThread__ +#define __hifi__AssignmentThread__ + +#include + +#include + +class AssignmentThread : public QThread { +public: + AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent); +private: + SharedAssignmentPointer _assignment; +}; + +#endif /* defined(__hifi__AssignmentThread__) */ diff --git a/interface/interface_en.ts b/interface/interface_en.ts index 8ca6f7d269..519e2b61c1 100644 --- a/interface/interface_en.ts +++ b/interface/interface_en.ts @@ -14,12 +14,12 @@ - + Open Script - + JavaScript Files (*.js) @@ -27,25 +27,25 @@ ChatWindow - - + + Chat - - + + Connecting to XMPP... - - + + online now: - + day %n day @@ -53,7 +53,7 @@ - + hour %n hour @@ -61,7 +61,7 @@ - + minute %n minute @@ -76,7 +76,7 @@ - + %1 online now: diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5b08997b7c..c6fc522fca 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2189,19 +2189,26 @@ void Application::updateShadowMap() { (_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); loadViewFrustum(_myCamera, _viewFrustum); glm::vec3 points[] = { - inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale)), - inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale)) }; - glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale), + glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale), + glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale), + glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale), + glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) }; + glm::vec3 center; for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { - minima = glm::min(minima, points[i]); - maxima = glm::max(maxima, points[i]); + center += points[i]; } + center /= (float)(sizeof(points) / sizeof(points[0])); + float radius = 0.0f; + for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { + radius = qMax(radius, glm::distance(points[i], center)); + } + center = inverseRotation * center; + glm::vec3 minima(center.x - radius, center.y - radius, center.z - radius); + glm::vec3 maxima(center.x + radius, center.y + radius, center.z + radius); // stretch out our extents in z so that we get all of the avatars minima.z -= _viewFrustum.getFarClip() * 0.5f; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 67f2e2caec..2f0b3df277 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -522,7 +522,7 @@ void Audio::handleAudioInput() { if (audioMixer && audioMixer->getActiveSocket()) { MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); - glm::quat headOrientation = interfaceAvatar->getHead()->getTweakedOrientation(); + glm::quat headOrientation = interfaceAvatar->getHead()->getFinalOrientation(); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index e1764374ea..7748c466c7 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -924,14 +924,17 @@ void Menu::goTo() { int dialogReturn = gotoDialog.exec(); if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) { - LocationManager* manager = &LocationManager::getInstance(); - manager->goTo(gotoDialog.textValue()); - connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); + goToUser(gotoDialog.textValue()); } - sendFakeEnterEvent(); } +void Menu::goToUser(const QString& user) { + LocationManager* manager = &LocationManager::getInstance(); + manager->goTo(user); + connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); +} + void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) { QMessageBox msgBox; msgBox.setText("Both user and location exists with same name"); @@ -1099,13 +1102,23 @@ void Menu::showMetavoxelEditor() { } void Menu::showChat() { + QMainWindow* mainWindow = Application::getInstance()->getWindow(); if (!_chatWindow) { - Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); - - } else { - if (!_chatWindow->toggleViewAction()->isChecked()) { - _chatWindow->toggleViewAction()->trigger(); - } + mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow()); + } + if (!_chatWindow->toggleViewAction()->isChecked()) { + int width = _chatWindow->width(); + int y = qMax((mainWindow->height() - _chatWindow->height()) / 2, 0); + _chatWindow->move(mainWindow->width(), y); + _chatWindow->resize(0, _chatWindow->height()); + _chatWindow->toggleViewAction()->trigger(); + + QPropertyAnimation* slideAnimation = new QPropertyAnimation(_chatWindow, "geometry", _chatWindow); + slideAnimation->setStartValue(_chatWindow->geometry()); + slideAnimation->setEndValue(QRect(mainWindow->width() - width, _chatWindow->y(), + width, _chatWindow->height())); + slideAnimation->setDuration(250); + slideAnimation->start(QAbstractAnimation::DeleteWhenStopped); } } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6b41430eaf..c7c4c6ecea 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -122,6 +122,7 @@ public slots: void importSettings(); void exportSettings(); void goTo(); + void goToUser(const QString& user); void pasteToVoxel(); void toggleLoginMenuItem(); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 94e1416e68..16181f46b9 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -246,7 +246,8 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { const float DISPLAYNAME_DISTANCE = 10.0f; setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); - if (renderMode != NORMAL_RENDER_MODE) { + if (renderMode != NORMAL_RENDER_MODE || (isMyAvatar() && + Application::getInstance()->getCamera()->getMode() == CAMERA_MODE_FIRST_PERSON)) { return; } renderDisplayName(); @@ -312,9 +313,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { void Avatar::renderBody(RenderMode renderMode) { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { // render the billboard until both models are loaded - if (renderMode != SHADOW_RENDER_MODE) { - renderBillboard(); - } + renderBillboard(); return; } _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); @@ -762,25 +761,6 @@ bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const { return false; } -void Avatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { - // compute lean angles - glm::vec3 leverAxis = contactPoint - getPosition(); - float leverLength = glm::length(leverAxis); - if (leverLength > EPSILON) { - glm::quat bodyRotation = getOrientation(); - glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f); - glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f); - - leverAxis = leverAxis / leverLength; - glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis; - // we use the small-angle approximation for sine below to compute the length of - // the opposite side of a narrow right triangle - float sideways = - glm::dot(effectivePenetration, xAxis) / leverLength; - float forward = glm::dot(effectivePenetration, zAxis) / leverLength; - getHead()->addLean(sideways, forward); - } -} - float Avatar::getBoundingRadius() const { // TODO: also use head model when computing the avatar's bounding radius return _skeletonModel.getBoundingRadius(); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 685705bfc4..f2ee400ba2 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -145,7 +145,7 @@ public: /// \return true if we expect the avatar would move as a result of the collision bool collisionWouldMoveAvatar(CollisionInfo& collision) const; - void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration); + virtual void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { } /// \return bounding radius of avatar virtual float getBoundingRadius() const; diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 19faa0da42..19120d10be 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -50,9 +50,9 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation))); - state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) - * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) - * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) + state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2])) + * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1])) + * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0])) * joint.rotation; } @@ -60,7 +60,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ // likewise with the eye joints glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); - glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getTweakedOrientation() * IDENTITY_FRONT, 0.0f)); + glm::vec3 front = glm::vec3(inverse * glm::vec4(_owningHead->getFinalOrientation() * IDENTITY_FRONT, 0.0f)); glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() + _owningHead->getSaccade() - _translation, 1.0f)); glm::quat between = rotationBetween(front, lookAt); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 750fae7b2a..daf82f2599 100644 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -156,7 +156,8 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) { //palm.addToPenetration(averagePenetration); } else { // someone else's hand against MyAvatar - averageContactPoint /= float(handCollisions.size()); + // TODO: submit collision info to MyAvatar which should lean accordingly + averageContactPoint /= (float)handCollisions.size(); avatar->applyCollision(averageContactPoint, totalPenetration); } } diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index fc18eed885..ffa0975ccb 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -36,9 +36,11 @@ Head::Head(Avatar* owningAvatar) : _leftEyeBlinkVelocity(0.0f), _rightEyeBlinkVelocity(0.0f), _timeWithoutTalking(0.0f), - _pitchTweak(0.f), - _yawTweak(0.f), - _rollTweak(0.f), + _deltaPitch(0.f), + _deltaYaw(0.f), + _deltaRoll(0.f), + _deltaLeanSideways(0.f), + _deltaLeanForward(0.f), _isCameraMoving(false), _faceModel(this) { @@ -50,13 +52,12 @@ void Head::init() { } void Head::reset() { - _yaw = _pitch = _roll = 0.0f; + _baseYaw = _basePitch = _baseRoll = 0.0f; _leanForward = _leanSideways = 0.0f; _faceModel.reset(); } void Head::simulate(float deltaTime, bool isMine, bool billboard) { - // Update audio trailing average for rendering facial animations Faceshift* faceshift = Application::getInstance()->getFaceshift(); Visage* visage = Application::getInstance()->getVisage(); @@ -165,6 +166,19 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { _eyePosition = calculateAverageEyePosition(); } +void Head::relaxLean(float deltaTime) { + // restore rotation, lean to neutral positions + const float LEAN_RELAXATION_PERIOD = 0.25f; // seconds + float relaxationFactor = 1.f - glm::min(deltaTime / LEAN_RELAXATION_PERIOD, 1.f); + _deltaYaw *= relaxationFactor; + _deltaPitch *= relaxationFactor; + _deltaRoll *= relaxationFactor; + _leanSideways *= relaxationFactor; + _leanForward *= relaxationFactor; + _deltaLeanSideways *= relaxationFactor; + _deltaLeanForward *= relaxationFactor; +} + void Head::render(float alpha, bool forShadowMap) { if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); @@ -178,14 +192,14 @@ void Head::setScale (float scale) { _scale = scale; } -glm::quat Head::getTweakedOrientation() const { +glm::quat Head::getFinalOrientation() const { return _owningAvatar->getOrientation() * glm::quat(glm::radians( - glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() ))); + glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() ))); } glm::quat Head::getCameraOrientation () const { Avatar* owningAvatar = static_cast(_owningAvatar); - return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, 0.f, 0.0f))); + return owningAvatar->getWorldAlignedOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, 0.f, 0.0f))); } glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const { @@ -197,16 +211,21 @@ glm::vec3 Head::getScalePivot() const { return _faceModel.isActive() ? _faceModel.getTranslation() : _position; } -float Head::getTweakedYaw() const { - return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW); +float Head::getFinalYaw() const { + return glm::clamp(_baseYaw + _deltaYaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } -float Head::getTweakedPitch() const { - return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH); +float Head::getFinalPitch() const { + return glm::clamp(_basePitch + _deltaPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } -float Head::getTweakedRoll() const { - return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL); +float Head::getFinalRoll() const { + return glm::clamp(_baseRoll + _deltaRoll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); +} + +void Head::addLeanDeltas(float sideways, float forward) { + _deltaLeanSideways += sideways; + _deltaLeanForward += forward; } void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 733323abc5..8a03cfc7ad 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -44,9 +44,15 @@ public: void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; } void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } + void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } + void setLeanForward(float leanForward) { _leanForward = leanForward; } - glm::quat getTweakedOrientation() const; + /// \return orientationBody * orientationBase+Delta + glm::quat getFinalOrientation() const; + + /// \return orientationBody * orientationBasePitch glm::quat getCameraOrientation () const; + const glm::vec3& getAngularVelocity() const { return _angularVelocity; } void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; } @@ -57,6 +63,10 @@ public: glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } + float getLeanSideways() const { return _leanSideways; } + float getLeanForward() const { return _leanForward; } + float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; } + float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; } glm::quat getEyeRotation(const glm::vec3& eyePosition) const; @@ -67,21 +77,24 @@ public: float getAverageLoudness() const { return _averageLoudness; } glm::vec3 calculateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } - /// Returns the point about which scaling occurs. + /// \return the point about which scaling occurs. glm::vec3 getScalePivot() const; - void setPitchTweak(float pitch) { _pitchTweak = pitch; } - float getPitchTweak() const { return _pitchTweak; } + void setDeltaPitch(float pitch) { _deltaPitch = pitch; } + float getDeltaPitch() const { return _deltaPitch; } - void setYawTweak(float yaw) { _yawTweak = yaw; } - float getYawTweak() const { return _yawTweak; } + void setDeltaYaw(float yaw) { _deltaYaw = yaw; } + float getDeltaYaw() const { return _deltaYaw; } - void setRollTweak(float roll) { _rollTweak = roll; } - float getRollTweak() const { return _rollTweak; } + void setDeltaRoll(float roll) { _deltaRoll = roll; } + float getDeltaRoll() const { return _deltaRoll; } - virtual float getTweakedPitch() const; - virtual float getTweakedYaw() const; - virtual float getTweakedRoll() const; + virtual float getFinalPitch() const; + virtual float getFinalYaw() const; + virtual float getFinalRoll() const; + + void relaxLean(float deltaTime); + void addLeanDeltas(float sideways, float forward); private: // disallow copies of the Head, copy of owning Avatar is disallowed too @@ -106,10 +119,14 @@ private: float _rightEyeBlinkVelocity; float _timeWithoutTalking; - // tweaked angles affect the rendered head, but not the camera - float _pitchTweak; - float _yawTweak; - float _rollTweak; + // delta angles for local head rotation (driven by hardware input) + float _deltaPitch; + float _deltaYaw; + float _deltaRoll; + + // delta lean angles for lean perturbations (driven by collisions) + float _deltaLeanSideways; + float _deltaLeanForward; bool _isCameraMoving; FaceModel _faceModel; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 350b4fb2be..62ba24a384 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -94,7 +94,13 @@ void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) { } void MyAvatar::update(float deltaTime) { + Head* head = getHead(); + head->relaxLean(deltaTime); updateFromGyros(deltaTime); + if (Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { + // Faceshift drive is enabled, set the avatar drive based on the head position + moveWithLean(); + } // Update head mouse from faceshift if active Faceshift* faceshift = Application::getInstance()->getFaceshift(); @@ -112,15 +118,14 @@ void MyAvatar::update(float deltaTime) { //_headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height()); } - Head* head = getHead(); if (OculusManager::isConnected()) { float yaw, pitch, roll; // these angles will be in radians OculusManager::getEulerAngles(yaw, pitch, roll); // but these euler angles are stored in degrees - head->setYaw(yaw * DEGREES_PER_RADIAN); - head->setPitch(pitch * DEGREES_PER_RADIAN); - head->setRoll(roll * DEGREES_PER_RADIAN); + head->setBaseYaw(yaw * DEGREES_PER_RADIAN); + head->setBasePitch(pitch * DEGREES_PER_RADIAN); + head->setBaseRoll(roll * DEGREES_PER_RADIAN); } // Get audio loudness data from audio input device @@ -230,7 +235,7 @@ void MyAvatar::simulate(float deltaTime) { if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() && fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD && - fabs(getHead()->getYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { + fabs(getHead()->getBaseYaw()) > OCULUS_YAW_OFFSET_THRESHOLD) { // if we're wearing the oculus // and this acceleration is above the pull threshold @@ -240,7 +245,7 @@ void MyAvatar::simulate(float deltaTime) { _bodyYaw = getAbsoluteHeadYaw(); // set the head yaw to zero for this draw - getHead()->setYaw(0); + getHead()->setBaseYaw(0); // correct the oculus yaw offset OculusManager::updateYawOffset(); @@ -361,26 +366,16 @@ void MyAvatar::updateFromGyros(float deltaTime) { } } } - } else { - // restore rotation, lean to neutral positions - const float RESTORE_PERIOD = 0.25f; // seconds - float restorePercentage = glm::clamp(deltaTime/RESTORE_PERIOD, 0.f, 1.f); - head->setPitchTweak(glm::mix(head->getPitchTweak(), 0.0f, restorePercentage)); - head->setYawTweak(glm::mix(head->getYawTweak(), 0.0f, restorePercentage)); - head->setRollTweak(glm::mix(head->getRollTweak(), 0.0f, restorePercentage)); - head->setLeanSideways(glm::mix(head->getLeanSideways(), 0.0f, restorePercentage)); - head->setLeanForward(glm::mix(head->getLeanForward(), 0.0f, restorePercentage)); - return; - } + } // Set the rotation of the avatar's head (as seen by others, not affecting view frustum) // to be scaled. Pitch is greater to emphasize nodding behavior / synchrony. const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; - head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); - head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); - head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); + head->setDeltaPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); + head->setDeltaYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); + head->setDeltaRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); // Update torso lean distance based on accelerometer data const float TORSO_LENGTH = 0.5f; @@ -390,13 +385,11 @@ void MyAvatar::updateFromGyros(float deltaTime) { -MAX_LEAN, MAX_LEAN)); head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); +} - // if Faceshift drive is enabled, set the avatar drive based on the head position - if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { - return; - } - +void MyAvatar::moveWithLean() { // Move with Lean by applying thrust proportional to leaning + Head* head = getHead(); glm::quat orientation = head->getCameraOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 right = orientation * IDENTITY_RIGHT; @@ -506,7 +499,7 @@ void MyAvatar::saveData(QSettings* settings) { settings->setValue("bodyPitch", _bodyPitch); settings->setValue("bodyRoll", _bodyRoll); - settings->setValue("headPitch", getHead()->getPitch()); + settings->setValue("headPitch", getHead()->getBasePitch()); settings->setValue("position_x", _position.x); settings->setValue("position_y", _position.y); @@ -532,7 +525,7 @@ void MyAvatar::loadData(QSettings* settings) { _bodyPitch = loadSetting(settings, "bodyPitch", 0.0f); _bodyRoll = loadSetting(settings, "bodyRoll", 0.0f); - getHead()->setPitch(loadSetting(settings, "headPitch", 0.0f)); + getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); _position.x = loadSetting(settings, "position_x", 0.0f); _position.y = loadSetting(settings, "position_y", 0.0f); @@ -575,9 +568,9 @@ void MyAvatar::orbit(const glm::vec3& position, int deltaX, int deltaY) { setOrientation(orientation); // then vertically - float oldPitch = getHead()->getPitch(); - getHead()->setPitch(oldPitch - deltaY * ANGULAR_SCALE); - rotation = glm::angleAxis(glm::radians((getHead()->getPitch() - oldPitch)), orientation * IDENTITY_RIGHT); + float oldPitch = getHead()->getBasePitch(); + getHead()->setBasePitch(oldPitch - deltaY * ANGULAR_SCALE); + rotation = glm::angleAxis(glm::radians((getHead()->getBasePitch() - oldPitch)), orientation * IDENTITY_RIGHT); setPosition(position + rotation * (getPosition() - position)); } @@ -683,7 +676,7 @@ void MyAvatar::updateThrust(float deltaTime) { _thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up; _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime; _bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_SPEED * deltaTime; - getHead()->setPitch(getHead()->getPitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime); + getHead()->setBasePitch(getHead()->getBasePitch() + (_driveKeys[ROT_UP] - _driveKeys[ROT_DOWN]) * PITCH_SPEED * deltaTime); // If thrust keys are being held down, slowly increase thrust to allow reaching great speeds if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) { @@ -1153,3 +1146,21 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { } } + +void MyAvatar::applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration) { + glm::vec3 leverAxis = contactPoint - getPosition(); + float leverLength = glm::length(leverAxis); + if (leverLength > EPSILON) { + // compute lean perturbation angles + glm::quat bodyRotation = getOrientation(); + glm::vec3 xAxis = bodyRotation * glm::vec3(1.f, 0.f, 0.f); + glm::vec3 zAxis = bodyRotation * glm::vec3(0.f, 0.f, 1.f); + + leverAxis = leverAxis / leverLength; + glm::vec3 effectivePenetration = penetration - glm::dot(penetration, leverAxis) * leverAxis; + // use the small-angle approximation for sine + float sideways = - glm::dot(effectivePenetration, xAxis) / leverLength; + float forward = glm::dot(effectivePenetration, zAxis) / leverLength; + getHead()->addLeanDeltas(sideways, forward); + } +} diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index cbb625aa2f..38edc5356e 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -34,6 +34,7 @@ public: void update(float deltaTime); void simulate(float deltaTime); void updateFromGyros(float deltaTime); + void moveWithLean(); void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); void renderBody(RenderMode renderMode); @@ -87,6 +88,9 @@ public: virtual void clearJointData(int index); virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); + + void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration); + public slots: void goHome(); void increaseSize(); diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index b4746a39d2..c44d2ebdea 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -72,11 +72,15 @@ void SkeletonModel::getHandShapes(int jointIndex, QVector& shapes) const FBXGeometry& geometry = _geometry->getFBXGeometry(); for (int i = 0; i < _jointStates.size(); i++) { const FBXJoint& joint = geometry.joints[i]; + int parentIndex = joint.parentIndex; if (i == jointIndex) { // this shape is the hand shapes.push_back(_shapes[i]); + if (parentIndex != -1) { + // also add the forearm + shapes.push_back(_shapes[parentIndex]); + } } else { - int parentIndex = joint.parentIndex; while (parentIndex != -1) { if (parentIndex == jointIndex) { // this shape is a child of the hand @@ -146,7 +150,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin direction += fingerVector / length; } fingerVector = glm::inverse(palmRotation) * fingerVector * -sign; - IndexValue indexValue = { int(i), atan2f(fingerVector.z, fingerVector.x) }; + IndexValue indexValue = { (int)i, atan2f(fingerVector.z, fingerVector.x) }; fingerIndices.append(indexValue); } qSort(fingerIndices.begin(), fingerIndices.end()); @@ -199,8 +203,8 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); - state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanSideways(), - glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanForward(), + state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(), + glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(), glm::normalize(inverse * axes[0])) * joint.rotation; } diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 6846f79825..9a8ba43e34 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1594,7 +1594,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) int numVertices = extracted.mesh.vertices.size(); jointShapeInfo.numVertices = numVertices; if (numVertices > 0) { - averageVertex /= float(jointShapeInfo.numVertices); + averageVertex /= (float)jointShapeInfo.numVertices; float averageRadius = 0.f; foreach (const glm::vec3& vertex, extracted.mesh.vertices) { averageRadius += glm::distance(vertex, averageVertex); @@ -1625,7 +1625,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } else { // collide the joint like a sphere if (jointShapeInfo.numVertices > 0) { - jointShapeInfo.averageVertex /= float(jointShapeInfo.numVertices); + jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices; joint.shapePosition = jointShapeInfo.averageVertex; } else { joint.shapePosition = glm::vec3(0.f); @@ -1635,7 +1635,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) && jointShapeInfo.numVertices > 0) { // the bone projection algorithm was not able to compute the joint radius // so we use an alternative measure - jointShapeInfo.averageRadius /= float(jointShapeInfo.numVertices); + jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices; joint.boneRadius = jointShapeInfo.averageRadius; } } diff --git a/interface/src/renderer/GeometryCache.cpp b/interface/src/renderer/GeometryCache.cpp index c4a0d15baa..b835e91a12 100644 --- a/interface/src/renderer/GeometryCache.cpp +++ b/interface/src/renderer/GeometryCache.cpp @@ -31,11 +31,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) { GLfloat* vertexData = new GLfloat[vertices * 3]; GLfloat* vertex = vertexData; for (int i = 0; i < stacks - 1; i++) { - float phi = PI_OVER_TWO * float(i) / float(stacks - 1); + float phi = PI_OVER_TWO * (float)i / (float)(stacks - 1); float z = sinf(phi), radius = cosf(phi); for (int j = 0; j < slices; j++) { - float theta = TWO_PI * float(j) / float(slices); + float theta = TWO_PI * (float)j / (float)slices; *(vertex++) = sinf(theta) * radius; *(vertex++) = cosf(theta) * radius; @@ -181,7 +181,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) { float y = (float)i / (stacks - 1); for (int j = 0; j <= slices; j++) { - float theta = 3.f * PI_OVER_TWO + PI * float(j) / float(slices); + float theta = 3.f * PI_OVER_TWO + PI * (float)j / (float)slices; //normals *(vertex++) = sinf(theta); diff --git a/interface/src/ui/BandwidthMeter.cpp b/interface/src/ui/BandwidthMeter.cpp index dfc142fb95..64ff74b846 100644 --- a/interface/src/ui/BandwidthMeter.cpp +++ b/interface/src/ui/BandwidthMeter.cpp @@ -160,7 +160,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { // Center of coordinate system -> upper left of bar glPushMatrix(); - glTranslatef(float(barX), float(y), 0.0f); + glTranslatef((float)barX, (float)y, 0.0f); // Render captions setColorRGBA(COLOR_TEXT); @@ -202,7 +202,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { // Render scale indicators setColorRGBA(COLOR_INDICATOR); for (int j = NUMBER_OF_MARKERS; --j > 0;) { - renderVerticalLine(int(barWidth * j / NUMBER_OF_MARKERS), 0, h); + renderVerticalLine((barWidth * j) / NUMBER_OF_MARKERS, 0, h); } // Render bars @@ -210,8 +210,8 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) { for (size_t i = 0; i < N_CHANNELS; ++i) { ChannelIndex chIdx = ChannelIndex(i); - int wIn = int(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); - int wOut = int(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); + int wIn = (int)(barWidth * inputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); + int wOut = (int)(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax); setColorRGBA(channelInfo(chIdx).colorRGBA); diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 55f32c5c7c..6963c208c5 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -6,13 +6,12 @@ // Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // -#include +#include #include #include #include #include #include -#include #include #include "Application.h" @@ -31,17 +30,18 @@ ChatWindow::ChatWindow() : ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0) { - QWidget* widget = new QWidget(); - setWidget(widget); - - ui->setupUi(widget); + ui->setupUi(this); + + // remove the title bar (see the Qt docs on setTitleBarWidget) + setTitleBarWidget(new QWidget()); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); - ui->messagePlainTextEdit->installEventFilter(this); + ui->messagesGridLayout->setColumnStretch(0, 1); + ui->messagesGridLayout->setColumnStretch(1, 3); - ui->closeButton->hide(); + ui->messagePlainTextEdit->installEventFilter(this); #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); @@ -76,41 +76,48 @@ ChatWindow::~ChatWindow() { } void ChatWindow::keyPressEvent(QKeyEvent* event) { - QWidget::keyPressEvent(event); + QDockWidget::keyPressEvent(event); if (event->key() == Qt::Key_Escape) { hide(); } } void ChatWindow::showEvent(QShowEvent* event) { - QWidget::showEvent(event); + QDockWidget::showEvent(event); if (!event->spontaneous()) { + activateWindow(); ui->messagePlainTextEdit->setFocus(); } } bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { - Q_UNUSED(sender); - - if (event->type() != QEvent::KeyPress) { - return false; - } - QKeyEvent* keyEvent = static_cast(event); - if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && - (keyEvent->modifiers() & Qt::ShiftModifier) == 0) { - QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed(); - if (!messageText.isEmpty()) { -#ifdef HAVE_QXMPP - const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); - QXmppMessage message; - message.setTo(publicChatRoom->jid()); - message.setType(QXmppMessage::GroupChat); - message.setBody(messageText); - XmppClient::getInstance().getXMPPClient().sendPacket(message); -#endif - ui->messagePlainTextEdit->document()->clear(); + if (sender == ui->messagePlainTextEdit) { + if (event->type() != QEvent::KeyPress) { + return false; } - return true; + QKeyEvent* keyEvent = static_cast(event); + if ((keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) && + (keyEvent->modifiers() & Qt::ShiftModifier) == 0) { + QString messageText = ui->messagePlainTextEdit->document()->toPlainText().trimmed(); + if (!messageText.isEmpty()) { + #ifdef HAVE_QXMPP + const QXmppMucRoom* publicChatRoom = XmppClient::getInstance().getPublicChatRoom(); + QXmppMessage message; + message.setTo(publicChatRoom->jid()); + message.setType(QXmppMessage::GroupChat); + message.setBody(messageText); + XmppClient::getInstance().getXMPPClient().sendPacket(message); + #endif + ui->messagePlainTextEdit->document()->clear(); + } + return true; + } + } else { + if (event->type() != QEvent::MouseButtonRelease) { + return false; + } + QString user = sender->property("user").toString(); + Menu::getInstance()->goToUser(user); } return false; } @@ -138,8 +145,9 @@ void ChatWindow::addTimeStamp() { timeLabel->setStyleSheet("color: palette(shadow);" "background-color: palette(highlight);" "padding: 4px;"); + timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); timeLabel->setAlignment(Qt::AlignHCenter); - ui->messagesFormLayout->addRow(timeLabel); + ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2); numMessagesAfterLastTimeStamp = 0; } } @@ -187,13 +195,21 @@ void ChatWindow::participantsChanged() { delete item; } foreach (const QString& participant, participants) { - QLabel* userLabel = new QLabel(getParticipantName(participant)); + QString participantName = getParticipantName(participant); + QLabel* userLabel = new QLabel(); + userLabel->setText(participantName); userLabel->setStyleSheet("background-color: palette(light);" "border-radius: 5px;" "color: #267077;" - "padding: 2px;" + "padding-top: 3px;" + "padding-right: 2px;" + "padding-bottom: 2px;" + "padding-left: 2px;" "border: 1px solid palette(shadow);" "font-weight: bold"); + userLabel->setProperty("user", participantName); + userLabel->setCursor(Qt::PointingHandCursor); + userLabel->installEventFilter(this); ui->usersWidget->layout()->addWidget(userLabel); } } @@ -204,19 +220,25 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { } QLabel* userLabel = new QLabel(getParticipantName(message.from())); - userLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); userLabel->setStyleSheet("padding: 2px; font-weight: bold"); - userLabel->setAlignment(Qt::AlignTop); + userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight); QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "\\1")); messageLabel->setWordWrap(true); messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); messageLabel->setOpenExternalLinks(true); - messageLabel->setStyleSheet("padding: 2px; margin-right: 20px"); - messageLabel->setAlignment(Qt::AlignTop); + messageLabel->setStyleSheet("padding-bottom: 2px; padding-left: 2px; padding-top: 2px; padding-right: 20px"); + messageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft); - ui->messagesFormLayout->addRow(userLabel, messageLabel); - ui->messagesFormLayout->parentWidget()->updateGeometry(); + if (getParticipantName(message.from()) == AccountManager::getInstance().getUsername()) { + userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea"); + messageLabel->setStyleSheet(messageLabel->styleSheet() + "; background-color: #e1e8ea"); + } + + ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0); + ui->messagesGridLayout->addWidget(messageLabel, ui->messagesGridLayout->rowCount() - 1, 1); + ui->messagesGridLayout->parentWidget()->updateGeometry(); Application::processEvents(); QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); verticalScrollBar->setSliderPosition(verticalScrollBar->maximum()); diff --git a/interface/src/ui/Oscilloscope.cpp b/interface/src/ui/Oscilloscope.cpp index 90d2d49926..a47586b436 100644 --- a/interface/src/ui/Oscilloscope.cpp +++ b/interface/src/ui/Oscilloscope.cpp @@ -127,7 +127,7 @@ void Oscilloscope::render(int x, int y) { } // fetch low pass factor (and convert to fix point) / downsample factor - int lowPassFixPt = -int(std::numeric_limits::min()) * _lowPassCoeff; + int lowPassFixPt = -(int)(std::numeric_limits::min()) * _lowPassCoeff; unsigned downsample = _downsampleRatio; // keep half of the buffer for writing and ensure an even vertex count unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u; @@ -141,7 +141,7 @@ void Oscilloscope::render(int x, int y) { short const* inPtr = _samples + _writePos[ch]; short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch; int sample = 0, x = usedWidth; - for (int i = int(usedSamples); --i >= 0 ;) { + for (int i = (int)usedSamples; --i >= 0 ;) { if (inPtr == basePtr) { // handle boundary, reading the circular sample buffer inPtr = endPtr; diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 1106fca3cd..60a0c6badd 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -1,7 +1,7 @@ ChatWindow - + 0 @@ -13,180 +13,188 @@ 400 - 0 + 238 - - Chat - font-family: Helvetica, Arial, sans-serif; - - - 0 - - - 8 - - - 8 - - - 8 - - - 8 - - - - - - 0 - 0 - - - - Connecting to XMPP... - - - Qt::AlignCenter - - - - - - - + + QDockWidget::NoDockWidgetFeatures + + + Qt::NoDockWidgetArea + + + Chat + + + + + 0 + + + 8 + + + 8 + + + 8 + + + 8 + + + + + + 0 + 0 + + + + Connecting to XMPP... + + + Qt::AlignCenter + + + + + + + + + + 0 + 0 + + + + font-weight: bold; color: palette(shadow); margin-bottom: 4px; + + + online now: + + + + + + + + 0 + 0 + + + + + 16 + 16 + + + + Qt::NoFocus + + + + + + + :/images/close.svg:/images/close.svg + + + true + + + + + + + + + + + + margin-top: 12px; + + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 382 + 16 + + - + 0 0 - font-weight: bold; color: palette(shadow); margin-bottom: 4px; - - - online now: + margin-top: 0px; + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + - - - - - - 0 - 0 - - - - - 16 - 16 - - - - Qt::NoFocus - - - - - - - :/images/close.svg:/images/close.svg - - - true - - - - - - - - - - - - margin-top: 12px; - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 358 - 464 - + + + + + + + 0 + 0 + + + + + 0 + 60 + - margin-top: 0px; + border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContents + + + true - - - QFormLayout::AllNonFixedFieldsGrow - - - 0 - - - 0 - - - 4 - - - 4 - - - 4 - - - 4 - - - - - - - - - 0 - 0 - - - - - 0 - 60 - - - - border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; - - - QFrame::NoFrame - - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContents - - - true - - - - + + + messagePlainTextEdit diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index bb0fcd27e6..31639b6836 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -93,9 +93,9 @@ QByteArray AvatarData::toByteArray() { destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); // Head rotation (NOTE: This needs to become a quaternion to save two bytes) - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedYaw()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedPitch()); - destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedRoll()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalYaw()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalPitch()); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalRoll()); // Head lean X,Z (head lateral and fwd/back motion relative to torso) memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways)); @@ -288,9 +288,9 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } return maxAvailableSize; } - _headData->setYaw(headYaw); - _headData->setPitch(headPitch); - _headData->setRoll(headRoll); + _headData->setBaseYaw(headYaw); + _headData->setBasePitch(headPitch); + _headData->setBaseRoll(headRoll); } // 6 bytes // Head lean (relative to pelvis) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a89639d68d..2ea20c1041 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -128,8 +128,8 @@ public: void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } // access to Head().set/getMousePitch (degrees) - float getHeadPitch() const { return _headData->getPitch(); } - void setHeadPitch(float value) { _headData->setPitch(value); }; + float getHeadPitch() const { return _headData->getBasePitch(); } + void setHeadPitch(float value) { _headData->setBasePitch(value); }; // access to Head().set/getAverageLoudness float getAudioLoudness() const { return _headData->getAudioLoudness(); } diff --git a/libraries/avatars/src/HeadData.cpp b/libraries/avatars/src/HeadData.cpp index cf48aeabfa..e74ac043fb 100644 --- a/libraries/avatars/src/HeadData.cpp +++ b/libraries/avatars/src/HeadData.cpp @@ -14,9 +14,9 @@ #include "HeadData.h" HeadData::HeadData(AvatarData* owningAvatar) : - _yaw(0.0f), - _pitch(0.0f), - _roll(0.0f), + _baseYaw(0.0f), + _basePitch(0.0f), + _baseRoll(0.0f), _leanSideways(0.0f), _leanForward(0.0f), _lookAtPosition(0.0f, 0.0f, 0.0f), @@ -32,7 +32,7 @@ HeadData::HeadData(AvatarData* owningAvatar) : } glm::quat HeadData::getOrientation() const { - return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_pitch, _yaw, _roll))); + return _owningAvatar->getOrientation() * glm::quat(glm::radians(glm::vec3(_basePitch, _baseYaw, _baseRoll))); } void HeadData::setOrientation(const glm::quat& orientation) { @@ -44,27 +44,20 @@ void HeadData::setOrientation(const glm::quat& orientation) { // the rest goes to the head glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation)); - _pitch = eulers.x; - _yaw = eulers.y; - _roll = eulers.z; + _basePitch = eulers.x; + _baseYaw = eulers.y; + _baseRoll = eulers.z; } void HeadData::addYaw(float yaw) { - setYaw(_yaw + yaw); + setBaseYaw(_baseYaw + yaw); } void HeadData::addPitch(float pitch) { - setPitch(_pitch + pitch); + setBasePitch(_basePitch + pitch); } void HeadData::addRoll(float roll) { - setRoll(_roll + roll); -} - - -void HeadData::addLean(float sideways, float forwards) { - // Add lean as impulse - _leanSideways += sideways; - _leanForward += forwards; + setBaseRoll(_baseRoll + roll); } diff --git a/libraries/avatars/src/HeadData.h b/libraries/avatars/src/HeadData.h index b199ff19d2..c60627e3f9 100644 --- a/libraries/avatars/src/HeadData.h +++ b/libraries/avatars/src/HeadData.h @@ -32,19 +32,15 @@ public: virtual ~HeadData() { }; // degrees - float getLeanSideways() const { return _leanSideways; } - void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } - float getLeanForward() const { return _leanForward; } - void setLeanForward(float leanForward) { _leanForward = leanForward; } - float getYaw() const { return _yaw; } - void setYaw(float yaw) { _yaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } - float getPitch() const { return _pitch; } - void setPitch(float pitch) { _pitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } - float getRoll() const { return _roll; } - void setRoll(float roll) { _roll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } - virtual float getTweakedYaw() const { return _yaw; } - virtual float getTweakedPitch() const { return _pitch; } - virtual float getTweakedRoll() const { return _roll; } + float getBaseYaw() const { return _baseYaw; } + void setBaseYaw(float yaw) { _baseYaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } + float getBasePitch() const { return _basePitch; } + void setBasePitch(float pitch) { _basePitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } + float getBaseRoll() const { return _baseRoll; } + void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); } + virtual float getFinalYaw() const { return _baseYaw; } + virtual float getFinalPitch() const { return _basePitch; } + virtual float getFinalRoll() const { return _baseRoll; } glm::quat getOrientation() const; void setOrientation(const glm::quat& orientation); @@ -64,7 +60,6 @@ public: void addYaw(float yaw); void addPitch(float pitch); void addRoll(float roll); - void addLean(float sideways, float forwards); const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } @@ -73,9 +68,9 @@ public: protected: // degrees - float _yaw; - float _pitch; - float _roll; + float _baseYaw; + float _basePitch; + float _baseRoll; float _leanSideways; float _leanForward; diff --git a/libraries/metavoxels/src/MetavoxelData.cpp b/libraries/metavoxels/src/MetavoxelData.cpp index 397e10d45f..cab5a73076 100644 --- a/libraries/metavoxels/src/MetavoxelData.cpp +++ b/libraries/metavoxels/src/MetavoxelData.cpp @@ -1096,7 +1096,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin QScriptValue minimum = infoValue.property(guide->_minimumHandle); MetavoxelInfo info = { glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()), - float(infoValue.property(guide->_sizeHandle).toNumber()), guide->_visitation->info.inputValues, + (float)infoValue.property(guide->_sizeHandle).toNumber(), guide->_visitation->info.inputValues, guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() }; // extract and convert the values provided by the script diff --git a/libraries/shared/src/ThreadedAssignment.cpp b/libraries/shared/src/ThreadedAssignment.cpp index be49b18055..fdf2d91c36 100644 --- a/libraries/shared/src/ThreadedAssignment.cpp +++ b/libraries/shared/src/ThreadedAssignment.cpp @@ -20,18 +20,15 @@ ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : } -void ThreadedAssignment::deleteLater() { - // move the NodeList back to the QCoreApplication instance's thread - NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread()); - QObject::deleteLater(); -} - void ThreadedAssignment::setFinished(bool isFinished) { _isFinished = isFinished; if (_isFinished) { aboutToFinish(); emit finished(); + + // move the NodeList back to the QCoreApplication instance's thread + NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread()); } } diff --git a/libraries/shared/src/ThreadedAssignment.h b/libraries/shared/src/ThreadedAssignment.h index 5b78eed56d..f9652dd98d 100644 --- a/libraries/shared/src/ThreadedAssignment.h +++ b/libraries/shared/src/ThreadedAssignment.h @@ -9,6 +9,8 @@ #ifndef __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__ +#include + #include "Assignment.h" class ThreadedAssignment : public Assignment { @@ -22,7 +24,6 @@ public: public slots: /// threaded run of assignment virtual void run() = 0; - virtual void deleteLater(); virtual void readPendingDatagrams() = 0; virtual void sendStatsPacket(); @@ -36,5 +37,6 @@ signals: void finished(); }; +typedef QSharedPointer SharedAssignmentPointer; #endif /* defined(__hifi__ThreadedAssignment__) */ diff --git a/libraries/shared/src/qtimespan.cpp b/libraries/shared/src/qtimespan.cpp index 2ddddb30f3..f3482cfb14 100644 --- a/libraries/shared/src/qtimespan.cpp +++ b/libraries/shared/src/qtimespan.cpp @@ -1594,7 +1594,7 @@ void QTimeSpan::setFromMonths(qreal months) { Q_ASSERT_X(hasValidReference(), "setFromMonths", "Can not set interval from time unit month if there is no reference date."); - int fullMonths = int(months); + int fullMonths = (int)months; qreal fractionalMonth = months - fullMonths; QDateTime endDate = d->reference; @@ -1631,7 +1631,7 @@ void QTimeSpan::setFromYears(qreal years) { Q_ASSERT_X(hasValidReference(), "setFromYears", "Can not set interval from time unit year if there is no reference date."); - int fullYears = int(years); + int fullYears = (int)years; qreal fractionalYear = years - fullYears; QDateTime endDate = d->reference; diff --git a/tests/physics/src/ShapeColliderTests.cpp b/tests/physics/src/ShapeColliderTests.cpp index 4a2e648323..7aeec84651 100644 --- a/tests/physics/src/ShapeColliderTests.cpp +++ b/tests/physics/src/ShapeColliderTests.cpp @@ -192,7 +192,7 @@ void ShapeColliderTests::sphereMissesCapsule() { float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1); for (int i = 0; i < numberOfSteps; ++i) { // translate sphereA into world-frame - glm::vec3 localPosition = localStartPosition + (float(i) * delta) * yAxis; + glm::vec3 localPosition = localStartPosition + ((float)i * delta) * yAxis; sphereA.setPosition(rotation * localPosition + translation); // sphereA agains capsuleB