This commit is contained in:
Philip Rosedale 2014-03-28 16:48:15 -07:00
commit 78ee8706d6
34 changed files with 518 additions and 403 deletions

View file

@ -23,7 +23,7 @@ Running Interface
When you launch interface, you will automatically connect to our default domain: "root.highfidelity.io". When you launch interface, you will automatically connect to our default domain: "root.highfidelity.io".
If you don't see anything, make sure your preferences are pointing to If you don't see anything, make sure your preferences are pointing to
root.highfidelity.io, if you still have no luck it's possible our servers are root.highfidelity.io (set your domain via Cmnd+D/Cntrl+D), if you still have no luck it's possible our servers are
simply down; if you're experiencing a major bug, let us know by adding an issue to this repository. simply down; if you're experiencing a major bug, let us know by adding an issue to this repository.
Make sure to include details about your computer and how to reproduce the bug. Make sure to include details about your computer and how to reproduce the bug.

View file

@ -18,6 +18,7 @@
#include <SharedUtil.h> #include <SharedUtil.h>
#include "AssignmentFactory.h" #include "AssignmentFactory.h"
#include "AssignmentThread.h"
#include "AssignmentClient.h" #include "AssignmentClient.h"
@ -28,7 +29,7 @@ int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
AssignmentClient::AssignmentClient(int &argc, char **argv) : AssignmentClient::AssignmentClient(int &argc, char **argv) :
QCoreApplication(argc, argv), QCoreApplication(argc, argv),
_currentAssignment(NULL) _currentAssignment()
{ {
setOrganizationName("High Fidelity"); setOrganizationName("High Fidelity");
setOrganizationDomain("highfidelity.io"); setOrganizationDomain("highfidelity.io");
@ -124,7 +125,7 @@ void AssignmentClient::readPendingDatagrams() {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) { if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) { if (packetTypeForPacket(receivedPacket) == PacketTypeCreateAssignment) {
// construct the deployed assignment from the packet data // construct the deployed assignment from the packet data
_currentAssignment = AssignmentFactory::unpackAssignment(receivedPacket); _currentAssignment = SharedAssignmentPointer(AssignmentFactory::unpackAssignment(receivedPacket));
if (_currentAssignment) { if (_currentAssignment) {
qDebug() << "Received an assignment -" << *_currentAssignment; qDebug() << "Received an assignment -" << *_currentAssignment;
@ -137,14 +138,13 @@ void AssignmentClient::readPendingDatagrams() {
qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString(); qDebug() << "Destination IP for assignment is" << nodeList->getDomainInfo().getIP().toString();
// start the deployed assignment // start the deployed assignment
QThread* workerThread = new QThread(this); AssignmentThread* workerThread = new AssignmentThread(_currentAssignment, this);
connect(workerThread, SIGNAL(started()), _currentAssignment, SLOT(run())); connect(workerThread, &QThread::started, _currentAssignment.data(), &ThreadedAssignment::run);
connect(_currentAssignment.data(), &ThreadedAssignment::finished, workerThread, &QThread::quit);
connect(_currentAssignment, SIGNAL(finished()), this, SLOT(assignmentCompleted())); connect(_currentAssignment.data(), &ThreadedAssignment::finished,
connect(_currentAssignment, SIGNAL(finished()), workerThread, SLOT(quit())); this, &AssignmentClient::assignmentCompleted);
connect(_currentAssignment, SIGNAL(finished()), _currentAssignment, SLOT(deleteLater())); connect(workerThread, &QThread::finished, workerThread, &QThread::deleteLater);
connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));
_currentAssignment->moveToThread(workerThread); _currentAssignment->moveToThread(workerThread);
@ -153,7 +153,7 @@ void AssignmentClient::readPendingDatagrams() {
// let the assignment handle the incoming datagrams for its duration // let the assignment handle the incoming datagrams for its duration
disconnect(&nodeList->getNodeSocket(), 0, this, 0); disconnect(&nodeList->getNodeSocket(), 0, this, 0);
connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment, connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _currentAssignment.data(),
&ThreadedAssignment::readPendingDatagrams); &ThreadedAssignment::readPendingDatagrams);
// Starts an event loop, and emits workerThread->started() // Starts an event loop, and emits workerThread->started()
@ -202,10 +202,12 @@ void AssignmentClient::assignmentCompleted() {
NodeList* nodeList = NodeList::getInstance(); NodeList* nodeList = NodeList::getInstance();
// have us handle incoming NodeList datagrams again // 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); 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 // reset our NodeList by switching back to unassigned and clearing the list
nodeList->setOwnerType(NodeType::Unassigned); nodeList->setOwnerType(NodeType::Unassigned);

View file

@ -24,7 +24,7 @@ private slots:
void handleAuthenticationRequest(); void handleAuthenticationRequest();
private: private:
Assignment _requestAssignment; Assignment _requestAssignment;
ThreadedAssignment* _currentAssignment; SharedAssignmentPointer _currentAssignment;
}; };
#endif /* defined(__hifi__AssignmentClient__) */ #endif /* defined(__hifi__AssignmentClient__) */

View file

@ -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)
{
}

View file

@ -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 <QtCore/QThread>
#include <ThreadedAssignment.h>
class AssignmentThread : public QThread {
public:
AssignmentThread(const SharedAssignmentPointer& assignment, QObject* parent);
private:
SharedAssignmentPointer _assignment;
};
#endif /* defined(__hifi__AssignmentThread__) */

View file

@ -14,12 +14,12 @@
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Application.cpp" line="3610"/> <location filename="src/Application.cpp" line="3617"/>
<source>Open Script</source> <source>Open Script</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="src/Application.cpp" line="3611"/> <location filename="src/Application.cpp" line="3618"/>
<source>JavaScript Files (*.js)</source> <source>JavaScript Files (*.js)</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
@ -27,25 +27,25 @@
<context> <context>
<name>ChatWindow</name> <name>ChatWindow</name>
<message> <message>
<location filename="ui/chatWindow.ui" line="20"/> <location filename="ui/chatWindow.ui" line="29"/>
<location filename="../build/interface/ui_chatWindow.h" line="143"/> <location filename="../build/interface/ui_chatWindow.h" line="153"/>
<source>Chat</source> <source>Chat</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="ui/chatWindow.ui" line="50"/> <location filename="ui/chatWindow.ui" line="57"/>
<location filename="../build/interface/ui_chatWindow.h" line="144"/> <location filename="../build/interface/ui_chatWindow.h" line="154"/>
<source>Connecting to XMPP...</source> <source>Connecting to XMPP...</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message> <message>
<location filename="ui/chatWindow.ui" line="71"/> <location filename="ui/chatWindow.ui" line="78"/>
<location filename="../build/interface/ui_chatWindow.h" line="145"/> <location filename="../build/interface/ui_chatWindow.h" line="155"/>
<source> online now:</source> <source> online now:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="128"/> <location filename="src/ui/ChatWindow.cpp" line="135"/>
<source>day</source> <source>day</source>
<translation> <translation>
<numerusform>%n day</numerusform> <numerusform>%n day</numerusform>
@ -53,7 +53,7 @@
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="128"/> <location filename="src/ui/ChatWindow.cpp" line="135"/>
<source>hour</source> <source>hour</source>
<translation> <translation>
<numerusform>%n hour</numerusform> <numerusform>%n hour</numerusform>
@ -61,7 +61,7 @@
</translation> </translation>
</message> </message>
<message numerus="yes"> <message numerus="yes">
<location filename="src/ui/ChatWindow.cpp" line="128"/> <location filename="src/ui/ChatWindow.cpp" line="135"/>
<source>minute</source> <source>minute</source>
<translation> <translation>
<numerusform>%n minute</numerusform> <numerusform>%n minute</numerusform>
@ -76,7 +76,7 @@
</translation> </translation>
</message> </message>
<message> <message>
<location filename="src/ui/ChatWindow.cpp" line="183"/> <location filename="src/ui/ChatWindow.cpp" line="191"/>
<source>%1 online now:</source> <source>%1 online now:</source>
<translation type="unfinished"></translation> <translation type="unfinished"></translation>
</message> </message>

View file

@ -2189,19 +2189,26 @@ void Application::updateShadowMap() {
(_viewFrustum.getFarClip() - _viewFrustum.getNearClip()); (_viewFrustum.getFarClip() - _viewFrustum.getNearClip());
loadViewFrustum(_myCamera, _viewFrustum); loadViewFrustum(_myCamera, _viewFrustum);
glm::vec3 points[] = { glm::vec3 points[] = {
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale)), glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), nearScale),
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale)), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), nearScale),
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale)), glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), nearScale),
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale)), glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), nearScale),
inverseRotation * (glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale)), glm::mix(_viewFrustum.getNearTopLeft(), _viewFrustum.getFarTopLeft(), farScale),
inverseRotation * (glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale)), glm::mix(_viewFrustum.getNearTopRight(), _viewFrustum.getFarTopRight(), farScale),
inverseRotation * (glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale)), glm::mix(_viewFrustum.getNearBottomLeft(), _viewFrustum.getFarBottomLeft(), farScale),
inverseRotation * (glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale)) }; glm::mix(_viewFrustum.getNearBottomRight(), _viewFrustum.getFarBottomRight(), farScale) };
glm::vec3 minima(FLT_MAX, FLT_MAX, FLT_MAX), maxima(-FLT_MAX, -FLT_MAX, -FLT_MAX); glm::vec3 center;
for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) { for (size_t i = 0; i < sizeof(points) / sizeof(points[0]); i++) {
minima = glm::min(minima, points[i]); center += points[i];
maxima = glm::max(maxima, 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 // stretch out our extents in z so that we get all of the avatars
minima.z -= _viewFrustum.getFarClip() * 0.5f; minima.z -= _viewFrustum.getFarClip() * 0.5f;

View file

@ -532,7 +532,7 @@ void Audio::handleAudioInput() {
if (audioMixer && audioMixer->getActiveSocket()) { if (audioMixer && audioMixer->getActiveSocket()) {
MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar(); MyAvatar* interfaceAvatar = Application::getInstance()->getAvatar();
glm::vec3 headPosition = interfaceAvatar->getHead()->getPosition(); 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 // we need the amount of bytes in the buffer + 1 for type
// + 12 for 3 floats for position + float for bearing + 1 attenuation byte // + 12 for 3 floats for position + float for bearing + 1 attenuation byte

View file

@ -924,14 +924,17 @@ void Menu::goTo() {
int dialogReturn = gotoDialog.exec(); int dialogReturn = gotoDialog.exec();
if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) { if (dialogReturn == QDialog::Accepted && !gotoDialog.textValue().isEmpty()) {
LocationManager* manager = &LocationManager::getInstance(); goToUser(gotoDialog.textValue());
manager->goTo(gotoDialog.textValue());
connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision);
} }
sendFakeEnterEvent(); 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) { void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) {
QMessageBox msgBox; QMessageBox msgBox;
msgBox.setText("Both user and location exists with same name"); msgBox.setText("Both user and location exists with same name");
@ -1099,13 +1102,23 @@ void Menu::showMetavoxelEditor() {
} }
void Menu::showChat() { void Menu::showChat() {
QMainWindow* mainWindow = Application::getInstance()->getWindow();
if (!_chatWindow) { if (!_chatWindow) {
Application::getInstance()->getWindow()->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow());
}
} else { if (!_chatWindow->toggleViewAction()->isChecked()) {
if (!_chatWindow->toggleViewAction()->isChecked()) { int width = _chatWindow->width();
_chatWindow->toggleViewAction()->trigger(); 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);
} }
} }

View file

@ -122,6 +122,7 @@ public slots:
void importSettings(); void importSettings();
void exportSettings(); void exportSettings();
void goTo(); void goTo();
void goToUser(const QString& user);
void pasteToVoxel(); void pasteToVoxel();
void toggleLoginMenuItem(); void toggleLoginMenuItem();

View file

@ -246,7 +246,8 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
const float DISPLAYNAME_DISTANCE = 10.0f; const float DISPLAYNAME_DISTANCE = 10.0f;
setShowDisplayName(renderMode == NORMAL_RENDER_MODE && distanceToTarget < DISPLAYNAME_DISTANCE); 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; return;
} }
renderDisplayName(); renderDisplayName();
@ -312,9 +313,7 @@ glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
void Avatar::renderBody(RenderMode renderMode) { void Avatar::renderBody(RenderMode renderMode) {
if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) { if (_shouldRenderBillboard || !(_skeletonModel.isRenderable() && getHead()->getFaceModel().isRenderable())) {
// render the billboard until both models are loaded // render the billboard until both models are loaded
if (renderMode != SHADOW_RENDER_MODE) { renderBillboard();
renderBillboard();
}
return; return;
} }
_skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE); _skeletonModel.render(1.0f, renderMode == SHADOW_RENDER_MODE);
@ -762,25 +761,6 @@ bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const {
return false; 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 { float Avatar::getBoundingRadius() const {
// TODO: also use head model when computing the avatar's bounding radius // TODO: also use head model when computing the avatar's bounding radius
return _skeletonModel.getBoundingRadius(); return _skeletonModel.getBoundingRadius();

View file

@ -145,7 +145,7 @@ public:
/// \return true if we expect the avatar would move as a result of the collision /// \return true if we expect the avatar would move as a result of the collision
bool collisionWouldMoveAvatar(CollisionInfo& collision) const; 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 /// \return bounding radius of avatar
virtual float getBoundingRadius() const; virtual float getBoundingRadius() const;

View file

@ -50,9 +50,9 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
glm::mat3 axes = glm::mat3_cast(_rotation); glm::mat3 axes = glm::mat3_cast(_rotation);
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
joint.preTransform * glm::mat4_cast(joint.preRotation))); joint.preTransform * glm::mat4_cast(joint.preRotation)));
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalRoll(), glm::normalize(inverse * axes[2]))
* glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) * glm::angleAxis(RADIANS_PER_DEGREE * _owningHead->getFinalYaw(), glm::normalize(inverse * axes[1]))
* glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningHead->getFinalPitch(), glm::normalize(inverse * axes[0]))
* joint.rotation; * joint.rotation;
} }
@ -60,7 +60,7 @@ void FaceModel::maybeUpdateEyeRotation(const JointState& parentState, const FBXJ
// likewise with the eye joints // likewise with the eye joints
glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) * glm::mat4 inverse = glm::inverse(parentState.transform * glm::translate(state.translation) *
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)); 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() + glm::vec3 lookAt = glm::vec3(inverse * glm::vec4(_owningHead->getLookAtPosition() +
_owningHead->getSaccade() - _translation, 1.0f)); _owningHead->getSaccade() - _translation, 1.0f));
glm::quat between = rotationBetween(front, lookAt); glm::quat between = rotationBetween(front, lookAt);

View file

@ -156,7 +156,8 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
//palm.addToPenetration(averagePenetration); //palm.addToPenetration(averagePenetration);
} else { } else {
// someone else's hand against MyAvatar // 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); avatar->applyCollision(averageContactPoint, totalPenetration);
} }
} }

View file

@ -36,9 +36,11 @@ Head::Head(Avatar* owningAvatar) :
_leftEyeBlinkVelocity(0.0f), _leftEyeBlinkVelocity(0.0f),
_rightEyeBlinkVelocity(0.0f), _rightEyeBlinkVelocity(0.0f),
_timeWithoutTalking(0.0f), _timeWithoutTalking(0.0f),
_pitchTweak(0.f), _deltaPitch(0.f),
_yawTweak(0.f), _deltaYaw(0.f),
_rollTweak(0.f), _deltaRoll(0.f),
_deltaLeanSideways(0.f),
_deltaLeanForward(0.f),
_isCameraMoving(false), _isCameraMoving(false),
_faceModel(this) _faceModel(this)
{ {
@ -50,13 +52,12 @@ void Head::init() {
} }
void Head::reset() { void Head::reset() {
_yaw = _pitch = _roll = 0.0f; _baseYaw = _basePitch = _baseRoll = 0.0f;
_leanForward = _leanSideways = 0.0f; _leanForward = _leanSideways = 0.0f;
_faceModel.reset(); _faceModel.reset();
} }
void Head::simulate(float deltaTime, bool isMine, bool billboard) { void Head::simulate(float deltaTime, bool isMine, bool billboard) {
// Update audio trailing average for rendering facial animations // Update audio trailing average for rendering facial animations
Faceshift* faceshift = Application::getInstance()->getFaceshift(); Faceshift* faceshift = Application::getInstance()->getFaceshift();
Visage* visage = Application::getInstance()->getVisage(); Visage* visage = Application::getInstance()->getVisage();
@ -165,6 +166,19 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) {
_eyePosition = calculateAverageEyePosition(); _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) { void Head::render(float alpha, bool forShadowMap) {
if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) { if (_faceModel.render(alpha, forShadowMap) && _renderLookatVectors) {
renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition);
@ -178,14 +192,14 @@ void Head::setScale (float scale) {
_scale = scale; _scale = scale;
} }
glm::quat Head::getTweakedOrientation() const { glm::quat Head::getFinalOrientation() const {
return _owningAvatar->getOrientation() * glm::quat(glm::radians( return _owningAvatar->getOrientation() * glm::quat(glm::radians(
glm::vec3(getTweakedPitch(), getTweakedYaw(), getTweakedRoll() ))); glm::vec3(getFinalPitch(), getFinalYaw(), getFinalRoll() )));
} }
glm::quat Head::getCameraOrientation () const { glm::quat Head::getCameraOrientation () const {
Avatar* owningAvatar = static_cast<Avatar*>(_owningAvatar); Avatar* owningAvatar = static_cast<Avatar*>(_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 { glm::quat Head::getEyeRotation(const glm::vec3& eyePosition) const {
@ -197,16 +211,21 @@ glm::vec3 Head::getScalePivot() const {
return _faceModel.isActive() ? _faceModel.getTranslation() : _position; return _faceModel.isActive() ? _faceModel.getTranslation() : _position;
} }
float Head::getTweakedYaw() const { float Head::getFinalYaw() const {
return glm::clamp(_yaw + _yawTweak, MIN_HEAD_YAW, MAX_HEAD_YAW); return glm::clamp(_baseYaw + _deltaYaw, MIN_HEAD_YAW, MAX_HEAD_YAW);
} }
float Head::getTweakedPitch() const { float Head::getFinalPitch() const {
return glm::clamp(_pitch + _pitchTweak, MIN_HEAD_PITCH, MAX_HEAD_PITCH); return glm::clamp(_basePitch + _deltaPitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH);
} }
float Head::getTweakedRoll() const { float Head::getFinalRoll() const {
return glm::clamp(_roll + _rollTweak, MIN_HEAD_ROLL, MAX_HEAD_ROLL); 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) { void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {

View file

@ -44,9 +44,15 @@ public:
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; } void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; } void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; } 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; glm::quat getCameraOrientation () const;
const glm::vec3& getAngularVelocity() const { return _angularVelocity; } const glm::vec3& getAngularVelocity() const { return _angularVelocity; }
void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; } void setAngularVelocity(glm::vec3 angularVelocity) { _angularVelocity = angularVelocity; }
@ -57,6 +63,10 @@ public:
glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; } glm::vec3 getUpDirection() const { return getOrientation() * IDENTITY_UP; }
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } 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; glm::quat getEyeRotation(const glm::vec3& eyePosition) const;
@ -67,21 +77,24 @@ public:
float getAverageLoudness() const { return _averageLoudness; } float getAverageLoudness() const { return _averageLoudness; }
glm::vec3 calculateAverageEyePosition() { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * ONE_HALF; } 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; glm::vec3 getScalePivot() const;
void setPitchTweak(float pitch) { _pitchTweak = pitch; } void setDeltaPitch(float pitch) { _deltaPitch = pitch; }
float getPitchTweak() const { return _pitchTweak; } float getDeltaPitch() const { return _deltaPitch; }
void setYawTweak(float yaw) { _yawTweak = yaw; } void setDeltaYaw(float yaw) { _deltaYaw = yaw; }
float getYawTweak() const { return _yawTweak; } float getDeltaYaw() const { return _deltaYaw; }
void setRollTweak(float roll) { _rollTweak = roll; } void setDeltaRoll(float roll) { _deltaRoll = roll; }
float getRollTweak() const { return _rollTweak; } float getDeltaRoll() const { return _deltaRoll; }
virtual float getTweakedPitch() const; virtual float getFinalPitch() const;
virtual float getTweakedYaw() const; virtual float getFinalYaw() const;
virtual float getTweakedRoll() const; virtual float getFinalRoll() const;
void relaxLean(float deltaTime);
void addLeanDeltas(float sideways, float forward);
private: private:
// disallow copies of the Head, copy of owning Avatar is disallowed too // disallow copies of the Head, copy of owning Avatar is disallowed too
@ -106,10 +119,14 @@ private:
float _rightEyeBlinkVelocity; float _rightEyeBlinkVelocity;
float _timeWithoutTalking; float _timeWithoutTalking;
// tweaked angles affect the rendered head, but not the camera // delta angles for local head rotation (driven by hardware input)
float _pitchTweak; float _deltaPitch;
float _yawTweak; float _deltaYaw;
float _rollTweak; float _deltaRoll;
// delta lean angles for lean perturbations (driven by collisions)
float _deltaLeanSideways;
float _deltaLeanForward;
bool _isCameraMoving; bool _isCameraMoving;
FaceModel _faceModel; FaceModel _faceModel;

View file

@ -94,7 +94,13 @@ void MyAvatar::setMoveTarget(const glm::vec3 moveTarget) {
} }
void MyAvatar::update(float deltaTime) { void MyAvatar::update(float deltaTime) {
Head* head = getHead();
head->relaxLean(deltaTime);
updateFromGyros(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 // Update head mouse from faceshift if active
Faceshift* faceshift = Application::getInstance()->getFaceshift(); Faceshift* faceshift = Application::getInstance()->getFaceshift();
@ -112,15 +118,14 @@ void MyAvatar::update(float deltaTime) {
//_headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height()); //_headMouseY = glm::clamp(_headMouseY, 0, _glWidget->height());
} }
Head* head = getHead();
if (OculusManager::isConnected()) { if (OculusManager::isConnected()) {
float yaw, pitch, roll; // these angles will be in radians float yaw, pitch, roll; // these angles will be in radians
OculusManager::getEulerAngles(yaw, pitch, roll); OculusManager::getEulerAngles(yaw, pitch, roll);
// but these euler angles are stored in degrees // but these euler angles are stored in degrees
head->setYaw(yaw * DEGREES_PER_RADIAN); head->setBaseYaw(yaw * DEGREES_PER_RADIAN);
head->setPitch(pitch * DEGREES_PER_RADIAN); head->setBasePitch(pitch * DEGREES_PER_RADIAN);
head->setRoll(roll * DEGREES_PER_RADIAN); head->setBaseRoll(roll * DEGREES_PER_RADIAN);
} }
// Get audio loudness data from audio input device // Get audio loudness data from audio input device
@ -230,7 +235,7 @@ void MyAvatar::simulate(float deltaTime) {
if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() && if (!Application::getInstance()->getFaceshift()->isActive() && OculusManager::isConnected() &&
fabsf(forwardAcceleration) > OCULUS_ACCELERATION_PULL_THRESHOLD && 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 // if we're wearing the oculus
// and this acceleration is above the pull threshold // and this acceleration is above the pull threshold
@ -240,7 +245,7 @@ void MyAvatar::simulate(float deltaTime) {
_bodyYaw = getAbsoluteHeadYaw(); _bodyYaw = getAbsoluteHeadYaw();
// set the head yaw to zero for this draw // set the head yaw to zero for this draw
getHead()->setYaw(0); getHead()->setBaseYaw(0);
// correct the oculus yaw offset // correct the oculus yaw offset
OculusManager::updateYawOffset(); 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) // 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. // to be scaled. Pitch is greater to emphasize nodding behavior / synchrony.
const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f; const float AVATAR_HEAD_PITCH_MAGNIFY = 1.0f;
const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f; const float AVATAR_HEAD_YAW_MAGNIFY = 1.0f;
const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f; const float AVATAR_HEAD_ROLL_MAGNIFY = 1.0f;
head->setPitchTweak(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY); head->setDeltaPitch(estimatedRotation.x * AVATAR_HEAD_PITCH_MAGNIFY);
head->setYawTweak(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY); head->setDeltaYaw(estimatedRotation.y * AVATAR_HEAD_YAW_MAGNIFY);
head->setRollTweak(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); head->setDeltaRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY);
// Update torso lean distance based on accelerometer data // Update torso lean distance based on accelerometer data
const float TORSO_LENGTH = 0.5f; const float TORSO_LENGTH = 0.5f;
@ -390,13 +385,11 @@ void MyAvatar::updateFromGyros(float deltaTime) {
-MAX_LEAN, MAX_LEAN)); -MAX_LEAN, MAX_LEAN));
head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)), head->setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)),
-MAX_LEAN, MAX_LEAN)); -MAX_LEAN, MAX_LEAN));
}
// if Faceshift drive is enabled, set the avatar drive based on the head position void MyAvatar::moveWithLean() {
if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) {
return;
}
// Move with Lean by applying thrust proportional to leaning // Move with Lean by applying thrust proportional to leaning
Head* head = getHead();
glm::quat orientation = head->getCameraOrientation(); glm::quat orientation = head->getCameraOrientation();
glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 front = orientation * IDENTITY_FRONT;
glm::vec3 right = orientation * IDENTITY_RIGHT; glm::vec3 right = orientation * IDENTITY_RIGHT;
@ -506,7 +499,7 @@ void MyAvatar::saveData(QSettings* settings) {
settings->setValue("bodyPitch", _bodyPitch); settings->setValue("bodyPitch", _bodyPitch);
settings->setValue("bodyRoll", _bodyRoll); settings->setValue("bodyRoll", _bodyRoll);
settings->setValue("headPitch", getHead()->getPitch()); settings->setValue("headPitch", getHead()->getBasePitch());
settings->setValue("position_x", _position.x); settings->setValue("position_x", _position.x);
settings->setValue("position_y", _position.y); settings->setValue("position_y", _position.y);
@ -532,7 +525,7 @@ void MyAvatar::loadData(QSettings* settings) {
_bodyPitch = loadSetting(settings, "bodyPitch", 0.0f); _bodyPitch = loadSetting(settings, "bodyPitch", 0.0f);
_bodyRoll = loadSetting(settings, "bodyRoll", 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.x = loadSetting(settings, "position_x", 0.0f);
_position.y = loadSetting(settings, "position_y", 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); setOrientation(orientation);
// then vertically // then vertically
float oldPitch = getHead()->getPitch(); float oldPitch = getHead()->getBasePitch();
getHead()->setPitch(oldPitch - deltaY * ANGULAR_SCALE); getHead()->setBasePitch(oldPitch - deltaY * ANGULAR_SCALE);
rotation = glm::angleAxis(glm::radians((getHead()->getPitch() - oldPitch)), orientation * IDENTITY_RIGHT); rotation = glm::angleAxis(glm::radians((getHead()->getBasePitch() - oldPitch)), orientation * IDENTITY_RIGHT);
setPosition(position + rotation * (getPosition() - position)); setPosition(position + rotation * (getPosition() - position));
} }
@ -683,7 +676,7 @@ void MyAvatar::updateThrust(float deltaTime) {
_thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up; _thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;
_bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime; _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_SPEED * deltaTime;
_bodyYawDelta += _driveKeys[ROT_LEFT] * 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 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]) { 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);
}
}

View file

@ -34,6 +34,7 @@ public:
void update(float deltaTime); void update(float deltaTime);
void simulate(float deltaTime); void simulate(float deltaTime);
void updateFromGyros(float deltaTime); void updateFromGyros(float deltaTime);
void moveWithLean();
void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE); void render(const glm::vec3& cameraPosition, RenderMode renderMode = NORMAL_RENDER_MODE);
void renderBody(RenderMode renderMode); void renderBody(RenderMode renderMode);
@ -87,6 +88,9 @@ public:
virtual void clearJointData(int index); virtual void clearJointData(int index);
virtual void setFaceModelURL(const QUrl& faceModelURL); virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL); virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
void applyCollision(const glm::vec3& contactPoint, const glm::vec3& penetration);
public slots: public slots:
void goHome(); void goHome();
void increaseSize(); void increaseSize();

View file

@ -72,11 +72,15 @@ void SkeletonModel::getHandShapes(int jointIndex, QVector<const Shape*>& shapes)
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
for (int i = 0; i < _jointStates.size(); i++) { for (int i = 0; i < _jointStates.size(); i++) {
const FBXJoint& joint = geometry.joints[i]; const FBXJoint& joint = geometry.joints[i];
int parentIndex = joint.parentIndex;
if (i == jointIndex) { if (i == jointIndex) {
// this shape is the hand // this shape is the hand
shapes.push_back(_shapes[i]); shapes.push_back(_shapes[i]);
if (parentIndex != -1) {
// also add the forearm
shapes.push_back(_shapes[parentIndex]);
}
} else { } else {
int parentIndex = joint.parentIndex;
while (parentIndex != -1) { while (parentIndex != -1) {
if (parentIndex == jointIndex) { if (parentIndex == jointIndex) {
// this shape is a child of the hand // this shape is a child of the hand
@ -146,7 +150,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector<int>& fingerJoin
direction += fingerVector / length; direction += fingerVector / length;
} }
fingerVector = glm::inverse(palmRotation) * fingerVector * -sign; 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); fingerIndices.append(indexValue);
} }
qSort(fingerIndices.begin(), fingerIndices.end()); 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 axes = glm::mat3_cast(_rotation);
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) * glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation))); joint.preTransform * glm::mat4_cast(joint.preRotation * joint.rotation)));
state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanSideways(), state.rotation = glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanSideways(),
glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getLeanForward(), glm::normalize(inverse * axes[2])) * glm::angleAxis(- RADIANS_PER_DEGREE * _owningAvatar->getHead()->getFinalLeanForward(),
glm::normalize(inverse * axes[0])) * joint.rotation; glm::normalize(inverse * axes[0])) * joint.rotation;
} }

View file

@ -1594,7 +1594,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
int numVertices = extracted.mesh.vertices.size(); int numVertices = extracted.mesh.vertices.size();
jointShapeInfo.numVertices = numVertices; jointShapeInfo.numVertices = numVertices;
if (numVertices > 0) { if (numVertices > 0) {
averageVertex /= float(jointShapeInfo.numVertices); averageVertex /= (float)jointShapeInfo.numVertices;
float averageRadius = 0.f; float averageRadius = 0.f;
foreach (const glm::vec3& vertex, extracted.mesh.vertices) { foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
averageRadius += glm::distance(vertex, averageVertex); averageRadius += glm::distance(vertex, averageVertex);
@ -1625,7 +1625,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
} else { } else {
// collide the joint like a sphere // collide the joint like a sphere
if (jointShapeInfo.numVertices > 0) { if (jointShapeInfo.numVertices > 0) {
jointShapeInfo.averageVertex /= float(jointShapeInfo.numVertices); jointShapeInfo.averageVertex /= (float)jointShapeInfo.numVertices;
joint.shapePosition = jointShapeInfo.averageVertex; joint.shapePosition = jointShapeInfo.averageVertex;
} else { } else {
joint.shapePosition = glm::vec3(0.f); joint.shapePosition = glm::vec3(0.f);
@ -1635,7 +1635,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
&& jointShapeInfo.numVertices > 0) { && jointShapeInfo.numVertices > 0) {
// the bone projection algorithm was not able to compute the joint radius // the bone projection algorithm was not able to compute the joint radius
// so we use an alternative measure // so we use an alternative measure
jointShapeInfo.averageRadius /= float(jointShapeInfo.numVertices); jointShapeInfo.averageRadius /= (float)jointShapeInfo.numVertices;
joint.boneRadius = jointShapeInfo.averageRadius; joint.boneRadius = jointShapeInfo.averageRadius;
} }
} }

View file

@ -31,11 +31,11 @@ void GeometryCache::renderHemisphere(int slices, int stacks) {
GLfloat* vertexData = new GLfloat[vertices * 3]; GLfloat* vertexData = new GLfloat[vertices * 3];
GLfloat* vertex = vertexData; GLfloat* vertex = vertexData;
for (int i = 0; i < stacks - 1; i++) { 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); float z = sinf(phi), radius = cosf(phi);
for (int j = 0; j < slices; j++) { 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++) = sinf(theta) * radius;
*(vertex++) = cosf(theta) * radius; *(vertex++) = cosf(theta) * radius;
@ -181,7 +181,7 @@ void GeometryCache::renderHalfCylinder(int slices, int stacks) {
float y = (float)i / (stacks - 1); float y = (float)i / (stacks - 1);
for (int j = 0; j <= slices; j++) { 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 //normals
*(vertex++) = sinf(theta); *(vertex++) = sinf(theta);

View file

@ -160,7 +160,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
// Center of coordinate system -> upper left of bar // Center of coordinate system -> upper left of bar
glPushMatrix(); glPushMatrix();
glTranslatef(float(barX), float(y), 0.0f); glTranslatef((float)barX, (float)y, 0.0f);
// Render captions // Render captions
setColorRGBA(COLOR_TEXT); setColorRGBA(COLOR_TEXT);
@ -202,7 +202,7 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
// Render scale indicators // Render scale indicators
setColorRGBA(COLOR_INDICATOR); setColorRGBA(COLOR_INDICATOR);
for (int j = NUMBER_OF_MARKERS; --j > 0;) { 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 // Render bars
@ -210,8 +210,8 @@ void BandwidthMeter::render(int screenWidth, int screenHeight) {
for (size_t i = 0; i < N_CHANNELS; ++i) { for (size_t i = 0; i < N_CHANNELS; ++i) {
ChannelIndex chIdx = ChannelIndex(i); ChannelIndex chIdx = ChannelIndex(i);
int wIn = int(barWidth * inputStream(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); int wOut = (int)(barWidth * outputStream(chIdx).getValue() * UNIT_SCALE / scaleMax);
setColorRGBA(channelInfo(chIdx).colorRGBA); setColorRGBA(channelInfo(chIdx).colorRGBA);

View file

@ -6,13 +6,12 @@
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved. // Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
// //
#include <QFormLayout> #include <QGridLayout>
#include <QFrame> #include <QFrame>
#include <QLayoutItem> #include <QLayoutItem>
#include <QPalette> #include <QPalette>
#include <QScrollBar> #include <QScrollBar>
#include <QSizePolicy> #include <QSizePolicy>
#include <QTextDocument>
#include <QTimer> #include <QTimer>
#include "Application.h" #include "Application.h"
@ -31,17 +30,18 @@ ChatWindow::ChatWindow() :
ui(new Ui::ChatWindow), ui(new Ui::ChatWindow),
numMessagesAfterLastTimeStamp(0) numMessagesAfterLastTimeStamp(0)
{ {
QWidget* widget = new QWidget(); ui->setupUi(this);
setWidget(widget);
// remove the title bar (see the Qt docs on setTitleBarWidget)
ui->setupUi(widget); setTitleBarWidget(new QWidget());
FlowLayout* flowLayout = new FlowLayout(0, 4, 4); FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
ui->usersWidget->setLayout(flowLayout); 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 #ifdef HAVE_QXMPP
const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient();
@ -76,41 +76,48 @@ ChatWindow::~ChatWindow() {
} }
void ChatWindow::keyPressEvent(QKeyEvent* event) { void ChatWindow::keyPressEvent(QKeyEvent* event) {
QWidget::keyPressEvent(event); QDockWidget::keyPressEvent(event);
if (event->key() == Qt::Key_Escape) { if (event->key() == Qt::Key_Escape) {
hide(); hide();
} }
} }
void ChatWindow::showEvent(QShowEvent* event) { void ChatWindow::showEvent(QShowEvent* event) {
QWidget::showEvent(event); QDockWidget::showEvent(event);
if (!event->spontaneous()) { if (!event->spontaneous()) {
activateWindow();
ui->messagePlainTextEdit->setFocus(); ui->messagePlainTextEdit->setFocus();
} }
} }
bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { bool ChatWindow::eventFilter(QObject* sender, QEvent* event) {
Q_UNUSED(sender); if (sender == ui->messagePlainTextEdit) {
if (event->type() != QEvent::KeyPress) {
if (event->type() != QEvent::KeyPress) { return false;
return false;
}
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(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; QKeyEvent* keyEvent = static_cast<QKeyEvent*>(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; return false;
} }
@ -138,8 +145,9 @@ void ChatWindow::addTimeStamp() {
timeLabel->setStyleSheet("color: palette(shadow);" timeLabel->setStyleSheet("color: palette(shadow);"
"background-color: palette(highlight);" "background-color: palette(highlight);"
"padding: 4px;"); "padding: 4px;");
timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
timeLabel->setAlignment(Qt::AlignHCenter); timeLabel->setAlignment(Qt::AlignHCenter);
ui->messagesFormLayout->addRow(timeLabel); ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2);
numMessagesAfterLastTimeStamp = 0; numMessagesAfterLastTimeStamp = 0;
} }
} }
@ -187,13 +195,21 @@ void ChatWindow::participantsChanged() {
delete item; delete item;
} }
foreach (const QString& participant, participants) { 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);" userLabel->setStyleSheet("background-color: palette(light);"
"border-radius: 5px;" "border-radius: 5px;"
"color: #267077;" "color: #267077;"
"padding: 2px;" "padding-top: 3px;"
"padding-right: 2px;"
"padding-bottom: 2px;"
"padding-left: 2px;"
"border: 1px solid palette(shadow);" "border: 1px solid palette(shadow);"
"font-weight: bold"); "font-weight: bold");
userLabel->setProperty("user", participantName);
userLabel->setCursor(Qt::PointingHandCursor);
userLabel->installEventFilter(this);
ui->usersWidget->layout()->addWidget(userLabel); ui->usersWidget->layout()->addWidget(userLabel);
} }
} }
@ -204,19 +220,25 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
} }
QLabel* userLabel = new QLabel(getParticipantName(message.from())); 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->setStyleSheet("padding: 2px; font-weight: bold");
userLabel->setAlignment(Qt::AlignTop); userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight);
QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>")); QLabel* messageLabel = new QLabel(message.body().replace(regexLinks, "<a href=\"\\1\">\\1</a>"));
messageLabel->setWordWrap(true); messageLabel->setWordWrap(true);
messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); messageLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
messageLabel->setOpenExternalLinks(true); messageLabel->setOpenExternalLinks(true);
messageLabel->setStyleSheet("padding: 2px; margin-right: 20px"); messageLabel->setStyleSheet("padding-bottom: 2px; padding-left: 2px; padding-top: 2px; padding-right: 20px");
messageLabel->setAlignment(Qt::AlignTop); messageLabel->setAlignment(Qt::AlignTop | Qt::AlignLeft);
ui->messagesFormLayout->addRow(userLabel, messageLabel); if (getParticipantName(message.from()) == AccountManager::getInstance().getUsername()) {
ui->messagesFormLayout->parentWidget()->updateGeometry(); 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(); Application::processEvents();
QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar();
verticalScrollBar->setSliderPosition(verticalScrollBar->maximum()); verticalScrollBar->setSliderPosition(verticalScrollBar->maximum());

View file

@ -127,7 +127,7 @@ void Oscilloscope::render(int x, int y) {
} }
// fetch low pass factor (and convert to fix point) / downsample factor // fetch low pass factor (and convert to fix point) / downsample factor
int lowPassFixPt = -int(std::numeric_limits<short>::min()) * _lowPassCoeff; int lowPassFixPt = -(int)(std::numeric_limits<short>::min()) * _lowPassCoeff;
unsigned downsample = _downsampleRatio; unsigned downsample = _downsampleRatio;
// keep half of the buffer for writing and ensure an even vertex count // keep half of the buffer for writing and ensure an even vertex count
unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u; 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 const* inPtr = _samples + _writePos[ch];
short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch; short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
int sample = 0, x = usedWidth; int sample = 0, x = usedWidth;
for (int i = int(usedSamples); --i >= 0 ;) { for (int i = (int)usedSamples; --i >= 0 ;) {
if (inPtr == basePtr) { if (inPtr == basePtr) {
// handle boundary, reading the circular sample buffer // handle boundary, reading the circular sample buffer
inPtr = endPtr; inPtr = endPtr;

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>ChatWindow</class> <class>ChatWindow</class>
<widget class="QWidget" name="ChatWindow"> <widget class="QDockWidget" name="ChatWindow">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
@ -13,180 +13,188 @@
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>400</width> <width>400</width>
<height>0</height> <height>238</height>
</size> </size>
</property> </property>
<property name="windowTitle">
<string>Chat</string>
</property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string> <string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout"> <property name="features">
<property name="spacing"> <set>QDockWidget::NoDockWidgetFeatures</set>
<number>0</number> </property>
</property> <property name="allowedAreas">
<property name="leftMargin"> <set>Qt::NoDockWidgetArea</set>
<number>8</number> </property>
</property> <property name="windowTitle">
<property name="topMargin"> <string>Chat</string>
<number>8</number> </property>
</property> <widget class="QWidget" name="dockWidgetContents">
<property name="rightMargin"> <layout class="QVBoxLayout" name="verticalLayout">
<number>8</number> <property name="spacing">
</property> <number>0</number>
<property name="bottomMargin"> </property>
<number>8</number> <property name="leftMargin">
</property> <number>8</number>
<item> </property>
<widget class="QLabel" name="connectingToXMPPLabel"> <property name="topMargin">
<property name="sizePolicy"> <number>8</number>
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> </property>
<horstretch>0</horstretch> <property name="rightMargin">
<verstretch>0</verstretch> <number>8</number>
</sizepolicy> </property>
</property> <property name="bottomMargin">
<property name="text"> <number>8</number>
<string>Connecting to XMPP...</string> </property>
</property> <item>
<property name="alignment"> <widget class="QLabel" name="connectingToXMPPLabel">
<set>Qt::AlignCenter</set> <property name="sizePolicy">
</property> <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
</widget> <horstretch>0</horstretch>
</item> <verstretch>0</verstretch>
<item> </sizepolicy>
<layout class="QHBoxLayout" name="horizontalLayout"> </property>
<item> <property name="text">
<widget class="QLabel" name="numOnlineLabel"> <string>Connecting to XMPP...</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="numOnlineLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="styleSheet">
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string>
</property>
<property name="text">
<string> online now:</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/resources.qrc">
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="usersWidget" native="true"/>
</item>
<item>
<widget class="QScrollArea" name="messagesScrollArea">
<property name="styleSheet">
<string notr="true">margin-top: 12px;</string>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>16</height>
</rect>
</property>
<property name="sizePolicy"> <property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> <sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch> <horstretch>0</horstretch>
<verstretch>0</verstretch> <verstretch>0</verstretch>
</sizepolicy> </sizepolicy>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">font-weight: bold; color: palette(shadow); margin-bottom: 4px;</string> <string notr="true">margin-top: 0px;</string>
</property>
<property name="text">
<string> online now:</string>
</property> </property>
<layout class="QGridLayout" name="messagesGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<property name="spacing">
<number>0</number>
</property>
</layout>
</widget> </widget>
</item> </widget>
<item> </item>
<widget class="QPushButton" name="closeButton"> <item>
<property name="sizePolicy"> <widget class="QPlainTextEdit" name="messagePlainTextEdit">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed"> <property name="sizePolicy">
<horstretch>0</horstretch> <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<verstretch>0</verstretch> <horstretch>0</horstretch>
</sizepolicy> <verstretch>0</verstretch>
</property> </sizepolicy>
<property name="maximumSize"> </property>
<size> <property name="minimumSize">
<width>16</width> <size>
<height>16</height> <width>0</width>
</size> <height>60</height>
</property> </size>
<property name="focusPolicy">
<enum>Qt::NoFocus</enum>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset resource="../resources/resources.qrc">
<normaloff>:/images/close.svg</normaloff>:/images/close.svg</iconset>
</property>
<property name="flat">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="usersWidget" native="true"/>
</item>
<item>
<widget class="QScrollArea" name="messagesScrollArea">
<property name="styleSheet">
<string notr="true">margin-top: 12px;</string>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>358</width>
<height>464</height>
</rect>
</property> </property>
<property name="styleSheet"> <property name="styleSheet">
<string notr="true">margin-top: 0px;</string> <string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property> </property>
<layout class="QFormLayout" name="messagesFormLayout">
<property name="fieldGrowthPolicy">
<enum>QFormLayout::AllNonFixedFieldsGrow</enum>
</property>
<property name="horizontalSpacing">
<number>0</number>
</property>
<property name="verticalSpacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>4</number>
</property>
<property name="topMargin">
<number>4</number>
</property>
<property name="rightMargin">
<number>4</number>
</property>
<property name="bottomMargin">
<number>4</number>
</property>
</layout>
</widget> </widget>
</widget> </item>
</item> </layout>
<item> </widget>
<widget class="QPlainTextEdit" name="messagePlainTextEdit">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>60</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px;</string>
</property>
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustToContents</enum>
</property>
<property name="tabChangesFocus">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget> </widget>
<tabstops> <tabstops>
<tabstop>messagePlainTextEdit</tabstop> <tabstop>messagePlainTextEdit</tabstop>

View file

@ -93,9 +93,9 @@ QByteArray AvatarData::toByteArray() {
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale); destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _targetScale);
// Head rotation (NOTE: This needs to become a quaternion to save two bytes) // Head rotation (NOTE: This needs to become a quaternion to save two bytes)
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedYaw()); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalYaw());
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedPitch()); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalPitch());
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getTweakedRoll()); destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->getFinalRoll());
// Head lean X,Z (head lateral and fwd/back motion relative to torso) // Head lean X,Z (head lateral and fwd/back motion relative to torso)
memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways)); memcpy(destinationBuffer, &_headData->_leanSideways, sizeof(_headData->_leanSideways));
@ -288,9 +288,9 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) {
} }
return maxAvailableSize; return maxAvailableSize;
} }
_headData->setYaw(headYaw); _headData->setBaseYaw(headYaw);
_headData->setPitch(headPitch); _headData->setBasePitch(headPitch);
_headData->setRoll(headRoll); _headData->setBaseRoll(headRoll);
} // 6 bytes } // 6 bytes
// Head lean (relative to pelvis) // Head lean (relative to pelvis)

View file

@ -128,8 +128,8 @@ public:
void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); } void setHeadOrientation(const glm::quat& orientation) { _headData->setOrientation(orientation); }
// access to Head().set/getMousePitch (degrees) // access to Head().set/getMousePitch (degrees)
float getHeadPitch() const { return _headData->getPitch(); } float getHeadPitch() const { return _headData->getBasePitch(); }
void setHeadPitch(float value) { _headData->setPitch(value); }; void setHeadPitch(float value) { _headData->setBasePitch(value); };
// access to Head().set/getAverageLoudness // access to Head().set/getAverageLoudness
float getAudioLoudness() const { return _headData->getAudioLoudness(); } float getAudioLoudness() const { return _headData->getAudioLoudness(); }

View file

@ -14,9 +14,9 @@
#include "HeadData.h" #include "HeadData.h"
HeadData::HeadData(AvatarData* owningAvatar) : HeadData::HeadData(AvatarData* owningAvatar) :
_yaw(0.0f), _baseYaw(0.0f),
_pitch(0.0f), _basePitch(0.0f),
_roll(0.0f), _baseRoll(0.0f),
_leanSideways(0.0f), _leanSideways(0.0f),
_leanForward(0.0f), _leanForward(0.0f),
_lookAtPosition(0.0f, 0.0f, 0.0f), _lookAtPosition(0.0f, 0.0f, 0.0f),
@ -32,7 +32,7 @@ HeadData::HeadData(AvatarData* owningAvatar) :
} }
glm::quat HeadData::getOrientation() const { 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) { void HeadData::setOrientation(const glm::quat& orientation) {
@ -44,27 +44,20 @@ void HeadData::setOrientation(const glm::quat& orientation) {
// the rest goes to the head // the rest goes to the head
glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation)); glm::vec3 eulers = glm::degrees(safeEulerAngles(glm::inverse(bodyOrientation) * orientation));
_pitch = eulers.x; _basePitch = eulers.x;
_yaw = eulers.y; _baseYaw = eulers.y;
_roll = eulers.z; _baseRoll = eulers.z;
} }
void HeadData::addYaw(float yaw) { void HeadData::addYaw(float yaw) {
setYaw(_yaw + yaw); setBaseYaw(_baseYaw + yaw);
} }
void HeadData::addPitch(float pitch) { void HeadData::addPitch(float pitch) {
setPitch(_pitch + pitch); setBasePitch(_basePitch + pitch);
} }
void HeadData::addRoll(float roll) { void HeadData::addRoll(float roll) {
setRoll(_roll + roll); setBaseRoll(_baseRoll + roll);
}
void HeadData::addLean(float sideways, float forwards) {
// Add lean as impulse
_leanSideways += sideways;
_leanForward += forwards;
} }

View file

@ -32,19 +32,15 @@ public:
virtual ~HeadData() { }; virtual ~HeadData() { };
// degrees // degrees
float getLeanSideways() const { return _leanSideways; } float getBaseYaw() const { return _baseYaw; }
void setLeanSideways(float leanSideways) { _leanSideways = leanSideways; } void setBaseYaw(float yaw) { _baseYaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); }
float getLeanForward() const { return _leanForward; } float getBasePitch() const { return _basePitch; }
void setLeanForward(float leanForward) { _leanForward = leanForward; } void setBasePitch(float pitch) { _basePitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); }
float getYaw() const { return _yaw; } float getBaseRoll() const { return _baseRoll; }
void setYaw(float yaw) { _yaw = glm::clamp(yaw, MIN_HEAD_YAW, MAX_HEAD_YAW); } void setBaseRoll(float roll) { _baseRoll = glm::clamp(roll, MIN_HEAD_ROLL, MAX_HEAD_ROLL); }
float getPitch() const { return _pitch; } virtual float getFinalYaw() const { return _baseYaw; }
void setPitch(float pitch) { _pitch = glm::clamp(pitch, MIN_HEAD_PITCH, MAX_HEAD_PITCH); } virtual float getFinalPitch() const { return _basePitch; }
float getRoll() const { return _roll; } virtual float getFinalRoll() const { return _baseRoll; }
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; }
glm::quat getOrientation() const; glm::quat getOrientation() const;
void setOrientation(const glm::quat& orientation); void setOrientation(const glm::quat& orientation);
@ -64,7 +60,6 @@ public:
void addYaw(float yaw); void addYaw(float yaw);
void addPitch(float pitch); void addPitch(float pitch);
void addRoll(float roll); void addRoll(float roll);
void addLean(float sideways, float forwards);
const glm::vec3& getLookAtPosition() const { return _lookAtPosition; } const glm::vec3& getLookAtPosition() const { return _lookAtPosition; }
void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; } void setLookAtPosition(const glm::vec3& lookAtPosition) { _lookAtPosition = lookAtPosition; }
@ -73,9 +68,9 @@ public:
protected: protected:
// degrees // degrees
float _yaw; float _baseYaw;
float _pitch; float _basePitch;
float _roll; float _baseRoll;
float _leanSideways; float _leanSideways;
float _leanForward; float _leanForward;

View file

@ -1096,7 +1096,7 @@ QScriptValue ScriptedMetavoxelGuide::visit(QScriptContext* context, QScriptEngin
QScriptValue minimum = infoValue.property(guide->_minimumHandle); QScriptValue minimum = infoValue.property(guide->_minimumHandle);
MetavoxelInfo info = { MetavoxelInfo info = {
glm::vec3(minimum.property(0).toNumber(), minimum.property(1).toNumber(), minimum.property(2).toNumber()), 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() }; guide->_visitation->info.outputValues, infoValue.property(guide->_isLeafHandle).toBool() };
// extract and convert the values provided by the script // extract and convert the values provided by the script

View file

@ -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) { void ThreadedAssignment::setFinished(bool isFinished) {
_isFinished = isFinished; _isFinished = isFinished;
if (_isFinished) { if (_isFinished) {
aboutToFinish(); aboutToFinish();
emit finished(); emit finished();
// move the NodeList back to the QCoreApplication instance's thread
NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread());
} }
} }

View file

@ -9,6 +9,8 @@
#ifndef __hifi__ThreadedAssignment__ #ifndef __hifi__ThreadedAssignment__
#define __hifi__ThreadedAssignment__ #define __hifi__ThreadedAssignment__
#include <QtCore/QSharedPointer>
#include "Assignment.h" #include "Assignment.h"
class ThreadedAssignment : public Assignment { class ThreadedAssignment : public Assignment {
@ -22,7 +24,6 @@ public:
public slots: public slots:
/// threaded run of assignment /// threaded run of assignment
virtual void run() = 0; virtual void run() = 0;
virtual void deleteLater();
virtual void readPendingDatagrams() = 0; virtual void readPendingDatagrams() = 0;
virtual void sendStatsPacket(); virtual void sendStatsPacket();
@ -36,5 +37,6 @@ signals:
void finished(); void finished();
}; };
typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer;
#endif /* defined(__hifi__ThreadedAssignment__) */ #endif /* defined(__hifi__ThreadedAssignment__) */

View file

@ -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."); 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; qreal fractionalMonth = months - fullMonths;
QDateTime endDate = d->reference; 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."); 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; qreal fractionalYear = years - fullYears;
QDateTime endDate = d->reference; QDateTime endDate = d->reference;

View file

@ -192,7 +192,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1); float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
for (int i = 0; i < numberOfSteps; ++i) { for (int i = 0; i < numberOfSteps; ++i) {
// translate sphereA into world-frame // 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.setPosition(rotation * localPosition + translation);
// sphereA agains capsuleB // sphereA agains capsuleB