From dd02bae5b32bb6de15f6b7c92a8abf11ebabce00 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 15 Apr 2014 16:11:00 -0700 Subject: [PATCH 01/68] First cut at improved undo --- libraries/voxels/src/VoxelTreeCommands.cpp | 84 +++++++++++++++++----- libraries/voxels/src/VoxelTreeCommands.h | 4 ++ 2 files changed, 70 insertions(+), 18 deletions(-) diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index f0f092fd04..75b38667ec 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -17,8 +17,37 @@ AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditP QUndoCommand("Add Voxel", parent), _tree(tree), _packetSender(packetSender), - _voxel(voxel) + _voxel(voxel), + _oldTree(NULL) { + VoxelTreeElement* element = _tree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + if (element) { + if (element->hasContent() && element->isLeaf()) { + // Do nothing, everything is in order + } else { + _oldTree = new VoxelTree(); + _tree->copySubTreeIntoNewTree(element, _oldTree, true); + } + } else { + glm::vec3 point(_voxel.x + _voxel.s / 2.0f, + _voxel.y + _voxel.s / 2.0f, + _voxel.z + _voxel.s / 2.0f); + OctreeElement* element = _tree->getElementEnclosingPoint(point, Octree::Lock); + if (element) { + VoxelTreeElement* node = static_cast(element); + _voxel.x = node->getCorner().x; + _voxel.y = node->getCorner().y; + _voxel.z = node->getCorner().z; + _voxel.s = node->getScale(); + _voxel.red = node->getColor()[0]; + _voxel.green = node->getColor()[1]; + _voxel.blue = node->getColor()[2]; + } + } +} + +AddVoxelCommand::~AddVoxelCommand() { + delete _oldTree; } void AddVoxelCommand::redo() { @@ -31,11 +60,17 @@ void AddVoxelCommand::redo() { } void AddVoxelCommand::undo() { - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + if (_oldTree) { + OctreeElement* element = _tree->getOrCreateChildElementAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + qDebug() << _voxel.x << " " << _voxel.y << " " << _voxel.z << " " << _voxel.s; + _tree->copyFromTreeIntoSubTree(_oldTree, element); + } else { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } } } @@ -43,24 +78,37 @@ DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, Voxe QUndoCommand("Delete Voxel", parent), _tree(tree), _packetSender(packetSender), - _voxel(voxel) + _voxel(voxel), + _oldTree(NULL) { } +DeleteVoxelCommand::~DeleteVoxelCommand() { + delete _oldTree; +} + void DeleteVoxelCommand::redo() { - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + if (_oldTree) { + + } else { + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); + } } } void DeleteVoxelCommand::undo() { - if (_tree) { - _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + if (_oldTree) { + + } else { + if (_tree) { + _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); + } } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); - } -} +} \ No newline at end of file diff --git a/libraries/voxels/src/VoxelTreeCommands.h b/libraries/voxels/src/VoxelTreeCommands.h index 4f2610577e..c3b23e7201 100644 --- a/libraries/voxels/src/VoxelTreeCommands.h +++ b/libraries/voxels/src/VoxelTreeCommands.h @@ -23,6 +23,7 @@ class VoxelTree; class AddVoxelCommand : public QUndoCommand { public: AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + ~AddVoxelCommand(); virtual void redo(); virtual void undo(); @@ -31,11 +32,13 @@ private: VoxelTree* _tree; VoxelEditPacketSender* _packetSender; VoxelDetail _voxel; + VoxelTree* _oldTree; }; class DeleteVoxelCommand : public QUndoCommand { public: DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); + ~DeleteVoxelCommand(); virtual void redo(); virtual void undo(); @@ -44,6 +47,7 @@ private: VoxelTree* _tree; VoxelEditPacketSender* _packetSender; VoxelDetail _voxel; + VoxelTree* _oldTree; }; #endif // hifi_VoxelTreeCommands_h From 4afea2d2289a237c9d8bb647f3c571bf7c0a0da2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 09:55:12 -0700 Subject: [PATCH 02/68] Remove chat window docking --- interface/resources/images/pin.svg | 98 ------------------------ interface/resources/images/pinned.svg | 106 -------------------------- interface/src/ui/ChatWindow.cpp | 13 ---- interface/src/ui/ChatWindow.h | 1 - interface/ui/chatWindow.ui | 16 ---- 5 files changed, 234 deletions(-) delete mode 100644 interface/resources/images/pin.svg delete mode 100644 interface/resources/images/pinned.svg diff --git a/interface/resources/images/pin.svg b/interface/resources/images/pin.svg deleted file mode 100644 index ec968a1ec1..0000000000 --- a/interface/resources/images/pin.svg +++ /dev/null @@ -1,98 +0,0 @@ - - - - - - image/svg+xml - - Slice 1 - - - - - Slice 1 - Created with Sketch (http://www.bohemiancoding.com/sketch) - - - - - - - - diff --git a/interface/resources/images/pinned.svg b/interface/resources/images/pinned.svg deleted file mode 100644 index bda6f0e747..0000000000 --- a/interface/resources/images/pinned.svg +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - image/svg+xml - - Slice 1 - - - - - Slice 1 - Created with Sketch (http://www.bohemiancoding.com/sketch) - - - - - - - - - diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 635f1f3d10..c190169c43 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -323,16 +323,3 @@ void ChatWindow::scrollToBottom() { QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); verticalScrollBar->setSliderPosition(verticalScrollBar->maximum()); } - -void ChatWindow::togglePinned() { - QMainWindow* mainWindow = Application::getInstance()->getWindow(); - mainWindow->removeDockWidget(this); - if (ui->togglePinnedButton->isChecked()) { - mainWindow->addDockWidget(ui->togglePinnedButton->isChecked() ? Qt::RightDockWidgetArea : Qt::NoDockWidgetArea, this); - } - if (!this->toggleViewAction()->isChecked()) { - this->toggleViewAction()->trigger(); - } - this->setFloating(!ui->togglePinnedButton->isChecked()); - setTitleBarWidget(ui->togglePinnedButton->isChecked()?new QWidget():titleBar); -} diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 6a807f9b81..536ac17799 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -65,7 +65,6 @@ private: private slots: void connected(); void timeout(); - void togglePinned(); #ifdef HAVE_QXMPP void error(QXmppClient::Error error); void participantsChanged(); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 0372e00c09..1d06a1e99b 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -251,22 +251,6 @@ QPushButton:pressed { - - togglePinnedButton - clicked() - ChatWindow - togglePinned() - - - 390 - 42 - - - 550 - 42 - - - closeButton clicked() From cb1408d26d4048c712522de54cdb776fb02fd0a3 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 10:01:35 -0700 Subject: [PATCH 03/68] Update chat window to use new Frameless Dialog The new dialog class needed to be updated to handle windows in different positions and windows that don't delete on close. --- interface/src/Menu.cpp | 19 +- interface/src/ui/ChatWindow.cpp | 38 +-- interface/src/ui/ChatWindow.h | 16 +- interface/src/ui/FramelessDialog.cpp | 72 +++-- interface/src/ui/FramelessDialog.h | 10 +- interface/src/ui/PreferencesDialog.cpp | 2 +- interface/ui/chatWindow.ui | 387 ++++++++++++------------- 7 files changed, 267 insertions(+), 277 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 272dc39eb3..508eaf61c3 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -1060,23 +1060,22 @@ void Menu::showMetavoxelEditor() { void Menu::showChat() { QMainWindow* mainWindow = Application::getInstance()->getWindow(); if (!_chatWindow) { - mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow()); + _chatWindow = new ChatWindow(mainWindow); } - if (!_chatWindow->toggleViewAction()->isChecked()) { - const QRect& windowGeometry = mainWindow->geometry(); - _chatWindow->move(windowGeometry.topRight().x() - _chatWindow->width(), - windowGeometry.topRight().y() + (windowGeometry.height() / 2) - (_chatWindow->height() / 2)); - - _chatWindow->resize(0, _chatWindow->height()); - _chatWindow->toggleViewAction()->trigger(); + if (_chatWindow->isHidden()) { + _chatWindow->show(); } } void Menu::toggleChat() { #ifdef HAVE_QXMPP _chatAction->setEnabled(XmppClient::getInstance().getXMPPClient().isConnected()); - if (!_chatAction->isEnabled() && _chatWindow && _chatWindow->toggleViewAction()->isChecked()) { - _chatWindow->toggleViewAction()->trigger(); + if (!_chatAction->isEnabled() && _chatWindow) { + if (_chatWindow->isHidden()) { + _chatWindow->show(); + } else { + _chatWindow->hide(); + } } #endif } diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index c190169c43..1f0f884f30 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -12,12 +12,10 @@ #include #include #include -#include #include #include #include #include -#include #include "Application.h" #include "FlowLayout.h" @@ -32,18 +30,16 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); -ChatWindow::ChatWindow() : +ChatWindow::ChatWindow(QWidget* parent) : + FramelessDialog(parent, 0, POSITION_RIGHT), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0), _mousePressed(false), _mouseStartPosition() { - ui->setupUi(this); + setAttribute(Qt::WA_DeleteOnClose, false); - // remove the title bar (see the Qt docs on setTitleBarWidget), but we keep it for undocking - // - titleBar = titleBarWidget(); - setTitleBarWidget(new QWidget()); + ui->setupUi(this); FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); @@ -89,41 +85,23 @@ ChatWindow::~ChatWindow() { delete ui; } -void ChatWindow::mousePressEvent(QMouseEvent *e) { - if (e->button() == Qt::LeftButton && isFloating()) { - _mousePressed = true; - _mouseStartPosition = e->pos(); - } -} - -void ChatWindow::mouseMoveEvent(QMouseEvent *e) { - if (_mousePressed) { - move(mapToParent(e->pos() - _mouseStartPosition)); - } -} - -void ChatWindow::mouseReleaseEvent( QMouseEvent *e ) { - if ( e->button() == Qt::LeftButton ) { - _mousePressed = false; - } -} - void ChatWindow::keyPressEvent(QKeyEvent* event) { - QDockWidget::keyPressEvent(event); if (event->key() == Qt::Key_Escape) { hide(); + } else { + FramelessDialog::keyPressEvent(event); } } void ChatWindow::showEvent(QShowEvent* event) { - QDockWidget::showEvent(event); + FramelessDialog::showEvent(event); if (!event->spontaneous()) { - activateWindow(); ui->messagePlainTextEdit->setFocus(); } } bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { + FramelessDialog::eventFilter(sender, event); if (sender == ui->messagePlainTextEdit) { if (event->type() != QEvent::KeyPress) { return false; diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 536ac17799..399c9e917c 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -17,6 +17,7 @@ #include #include +#include "FramelessDialog.h" #ifdef HAVE_QXMPP @@ -29,23 +30,19 @@ namespace Ui { class ChatWindow; } -class ChatWindow : public QDockWidget { +class ChatWindow : public FramelessDialog { Q_OBJECT public: - ChatWindow(); + ChatWindow(QWidget* parent); ~ChatWindow(); - virtual void keyPressEvent(QKeyEvent *event); - virtual void showEvent(QShowEvent* event); - - virtual void mousePressEvent(QMouseEvent *e); - virtual void mouseMoveEvent(QMouseEvent *e); - virtual void mouseReleaseEvent(QMouseEvent *e); - protected: bool eventFilter(QObject* sender, QEvent* event); + virtual void keyPressEvent(QKeyEvent *event); + virtual void showEvent(QShowEvent* event); + private: #ifdef HAVE_QXMPP QString getParticipantName(const QString& participant); @@ -56,7 +53,6 @@ private: void scrollToBottom(); Ui::ChatWindow* ui; - QWidget* titleBar; int numMessagesAfterLastTimeStamp; QDateTime lastMessageStamp; bool _mousePressed; diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp index 18e3bca89a..816c45b38a 100644 --- a/interface/src/ui/FramelessDialog.cpp +++ b/interface/src/ui/FramelessDialog.cpp @@ -14,8 +14,13 @@ const int RESIZE_HANDLE_WIDTH = 7; -FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) : -QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) { +FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) : + QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint), + _position(position), + _selfHidden(false), + _isResizing(false), + _resizeInitialWidth(0) { + setAttribute(Qt::WA_DeleteOnClose); // handle rezize and move events @@ -29,29 +34,37 @@ bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) { switch (event->type()) { case QEvent::Move: if (sender == parentWidget()) { - // move to upper left corner on app move - move(parentWidget()->geometry().topLeft()); + resizeAndPosition(false); } break; case QEvent::Resize: if (sender == parentWidget()) { - // keep full app height on resizing the app - setFixedHeight(parentWidget()->size().height()); + resizeAndPosition(false); } break; case QEvent::WindowStateChange: if (parentWidget()->isMinimized()) { - setHidden(true); - } else { + if (isVisible()) { + _selfHidden = true; + setHidden(true); + } + } else if (_selfHidden) { + _selfHidden = false; setHidden(false); } break; case QEvent::ApplicationDeactivate: // hide on minimize and focus lost - setHidden(true); + if (isVisible()) { + _selfHidden = true; + setHidden(true); + } break; case QEvent::ApplicationActivate: - setHidden(false); + if (_selfHidden) { + _selfHidden = false; + setHidden(false); + } break; default: break; @@ -70,21 +83,38 @@ void FramelessDialog::setStyleSheetFile(const QString& fileName) { } void FramelessDialog::showEvent(QShowEvent* event) { - // move to upper left corner - move(parentWidget()->geometry().topLeft()); + resizeAndPosition(); +} +void FramelessDialog::resizeAndPosition(bool resizeParent) { // keep full app height setFixedHeight(parentWidget()->size().height()); // resize parrent if width is smaller than this dialog - if (parentWidget()->size().width() < size().width()) { + if (resizeParent && parentWidget()->size().width() < size().width()) { parentWidget()->resize(size().width(), parentWidget()->size().height()); } + + if (_position == POSITION_LEFT) { + // move to upper left corner + move(parentWidget()->geometry().topLeft()); + } else if (_position == POSITION_RIGHT) { + // move to upper right corner + QPoint pos = parentWidget()->geometry().topRight(); + pos.setX(pos.x() - size().width()); + move(pos); + } } + void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) { - if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) { - _isResizing = true; - QApplication::setOverrideCursor(Qt::SizeHorCursor); + if (mouseEvent->button() == Qt::LeftButton) { + bool hitLeft = _position == POSITION_LEFT && abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH; + bool hitRight = _position == POSITION_RIGHT && mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH; + if (hitLeft || hitRight) { + _isResizing = true; + _resizeInitialWidth = size().width(); + QApplication::setOverrideCursor(Qt::SizeHorCursor); + } } } @@ -95,6 +125,14 @@ void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) { void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) { if (_isResizing) { - resize(mouseEvent->pos().x(), size().height()); + if (_position == POSITION_LEFT) { + resize(mouseEvent->pos().x(), size().height()); + } else if (_position == POSITION_RIGHT) { + setUpdatesEnabled(false); + resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height()); + resizeAndPosition(); + _resizeInitialWidth = size().width(); + setUpdatesEnabled(true); + } } } diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h index db9f6dfd6c..22666cca63 100644 --- a/interface/src/ui/FramelessDialog.h +++ b/interface/src/ui/FramelessDialog.h @@ -19,7 +19,10 @@ class FramelessDialog : public QDialog { Q_OBJECT public: - FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0); + enum Position { POSITION_LEFT, POSITION_RIGHT }; + + FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0, + Position position = POSITION_LEFT); void setStyleSheetFile(const QString& fileName); protected: @@ -31,7 +34,12 @@ protected: bool eventFilter(QObject* sender, QEvent* event); private: + void resizeAndPosition(bool resizeParent = true); + bool _isResizing; + int _resizeInitialWidth; + bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization) + Position _position; }; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index a14e80e62f..cb998e783a 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -19,7 +19,7 @@ const int SCROLL_PANEL_BOTTOM_MARGIN = 30; const int OK_BUTTON_RIGHT_MARGIN = 30; const int BUTTONS_TOP_MARGIN = 24; -PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags) { +PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags, POSITION_LEFT) { ui.setupUi(this); setStyleSheetFile("styles/preferences.qss"); diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 1d06a1e99b..78757ded38 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -1,13 +1,13 @@ ChatWindow - + 0 0 400 - 608 + 440 @@ -16,127 +16,95 @@ 238 - - font-family: Helvetica, Arial, sans-serif; - - - QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable - - - 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 - - - - - - - ../resources/images/pin.svg - ../resources/images/pinned.svg../resources/images/pin.svg - - - true - - - true - - - false - - - true - - - - - - - - 0 - 0 - - - - - 16 - 16 - - - - Qt::NoFocus - - - QPushButton { + + font-family: Helvetica, Arial, sans-serif; + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 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 + + + QPushButton { background-color: rgba( 0, 0, 0, 0% ); border: none; image: url(../resources/images/close.svg) @@ -148,102 +116,105 @@ QPushButton:pressed { border: none; image: url(../resources/images/close_down.svg) } - - - - - - true - - - - - - - - - - - - margin-top: 12px; - - - Qt::ScrollBarAlwaysOff - - - true - - - - - 0 - 0 - 382 - 16 - + + + + + + true + + + + + + + + + + + + margin-top: 12px; + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 382 + 16 + + + + + 0 + 0 + + + + margin-top: 0px; + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + - + 0 0 - - margin-top: 0px; + + + 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 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - - - - - 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 + dockWidgetContents messagePlainTextEdit From 8aee81ae7ca2b36dc40e6003311861ed1c0473a2 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 10:02:54 -0700 Subject: [PATCH 04/68] Update username in chat to use correct line height --- interface/src/ui/ChatMessageArea.cpp | 13 +++++++-- interface/src/ui/ChatMessageArea.h | 7 ++++- interface/src/ui/ChatWindow.cpp | 40 +++++++++++++++++++++++----- 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/ChatMessageArea.cpp b/interface/src/ui/ChatMessageArea.cpp index f15b788990..929ad85d87 100644 --- a/interface/src/ui/ChatMessageArea.cpp +++ b/interface/src/ui/ChatMessageArea.cpp @@ -9,11 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include "Application.h" #include "ChatMessageArea.h" #include #include -ChatMessageArea::ChatMessageArea() : QTextBrowser() { +ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixedHeight(useFixedHeight) { connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, this, &ChatMessageArea::updateLayout); } @@ -34,7 +35,15 @@ void ChatMessageArea::setHtml(const QString& html) { } void ChatMessageArea::updateLayout() { - setFixedHeight(document()->size().height()); + if (_useFixedHeight) { + setFixedHeight(document()->size().height()); + updateGeometry(); + emit sizeChanged(size()); + } +} + +void ChatMessageArea::setSize(const QSize& size) { + setFixedHeight(size.height()); updateGeometry(); } diff --git a/interface/src/ui/ChatMessageArea.h b/interface/src/ui/ChatMessageArea.h index 1c49c60b08..48cfc01aec 100644 --- a/interface/src/ui/ChatMessageArea.h +++ b/interface/src/ui/ChatMessageArea.h @@ -19,14 +19,19 @@ const int CHAT_MESSAGE_LINE_HEIGHT = 130; class ChatMessageArea : public QTextBrowser { Q_OBJECT public: - ChatMessageArea(); + ChatMessageArea(bool useFixedHeight = true); virtual void setHtml(const QString& html); public slots: void updateLayout(); + void setSize(const QSize& size); + +signals: + void sizeChanged(QSize newSize); protected: virtual void wheelEvent(QWheelEvent* event); + bool _useFixedHeight; }; diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 1f0f884f30..c194e35fc1 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -240,13 +240,32 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { return; } - QLabel* userLabel = new QLabel(getParticipantName(message.from())); - userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - userLabel->setStyleSheet("padding: 2px; font-weight: bold"); - userLabel->setAlignment(Qt::AlignTop | Qt::AlignRight); + // Create username label + ChatMessageArea* userLabel = new ChatMessageArea(false); + userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + userLabel->setWordWrapMode(QTextOption::NoWrap); + userLabel->setLineWrapMode(QTextEdit::NoWrap); + userLabel->setTextInteractionFlags(Qt::NoTextInteraction); + userLabel->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + userLabel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + userLabel->setReadOnly(true); + userLabel->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - ChatMessageArea* messageArea = new ChatMessageArea(); + userLabel->setStyleSheet("padding: 2px;" + "font-weight: bold;" + "background-color: rgba(0, 0, 0, 0%);" + "border: 0;"); + QTextBlockFormat format; + format.setLineHeight(130, QTextBlockFormat::ProportionalHeight); + QTextCursor cursor = userLabel->textCursor(); + cursor.setBlockFormat(format); + cursor.insertText(getParticipantName(message.from())); + + userLabel->setAlignment(Qt::AlignRight); + + // Create message area + ChatMessageArea* messageArea = new ChatMessageArea(true); messageArea->setOpenLinks(true); messageArea->setOpenExternalLinks(true); messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); @@ -262,10 +281,11 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { "background-color: rgba(0, 0, 0, 0%);" "border: 0;"); + // Update background if this is a message from the current user bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername(); if (fromSelf) { - userLabel->setStyleSheet(userLabel->styleSheet() + "; background-color: #e1e8ea"); - messageArea->setStyleSheet(messageArea->styleSheet() + "; background-color: #e1e8ea"); + userLabel->setStyleSheet(userLabel->styleSheet() + "background-color: #e1e8ea"); + messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea"); } messageArea->setHtml(message.body().replace(regexLinks, "\\1")); @@ -274,6 +294,12 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0); ui->messagesGridLayout->addWidget(messageArea, ui->messagesGridLayout->rowCount() - 1, 1); + // Force the height of the username area to match the height of the message area + connect(messageArea, &ChatMessageArea::sizeChanged, userLabel, &ChatMessageArea::setSize); + + // Force initial height to match message area + userLabel->setFixedHeight(messageArea->size().height()); + ui->messagesGridLayout->parentWidget()->updateGeometry(); Application::processEvents(); From bfb879d3e6a545f28cc66cd58f554464d828525e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 10:03:22 -0700 Subject: [PATCH 05/68] Update chat textbox to use correct line height --- interface/src/ui/ChatWindow.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index c194e35fc1..e26c0bcb94 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -48,11 +48,23 @@ ChatWindow::ChatWindow(QWidget* parent) : ui->messagesGridLayout->setColumnStretch(1, 3); ui->messagePlainTextEdit->installEventFilter(this); + ui->messagePlainTextEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); + + QTextCursor cursor(ui->messagePlainTextEdit->textCursor()); + + cursor.movePosition(QTextCursor::Start); + + QTextBlockFormat format = cursor.blockFormat(); + format.setLineHeight(130, QTextBlockFormat::ProportionalHeight); + + cursor.setBlockFormat(format); + + ui->messagePlainTextEdit->setTextCursor(cursor); if (!AccountManager::getInstance().isLoggedIn()) { ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others.")); } - + #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { From d34e6ff86483125a0ac9e554ad7f5a323688546c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Apr 2014 12:01:41 -0700 Subject: [PATCH 06/68] Removed gettimeofday in AudioInjector --- libraries/audio/src/AudioInjector.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 6370e51826..eed41ac849 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -71,8 +71,8 @@ void AudioInjector::injectAudio() { quint8 volume = MAX_INJECTOR_VOLUME * _options.getVolume(); packetStream << volume; - timeval startTime = {}; - gettimeofday(&startTime, NULL); + QElapsedTimer timer; + timer.start(); int nextFrame = 0; int currentSendPosition = 0; @@ -104,7 +104,7 @@ void AudioInjector::injectAudio() { if (currentSendPosition != bytesToCopy && currentSendPosition < soundByteArray.size()) { // not the first packet and not done // sleep for the appropriate time - int usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + int usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000; if (usecToSleep > 0) { usleep(usecToSleep); From 8cfc8faa019bf5a583fd8bcb93ea47627800f060 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Apr 2014 12:08:17 -0700 Subject: [PATCH 07/68] Removed gettimeofday in Audio --- interface/src/Audio.cpp | 13 +++++-------- interface/src/Audio.h | 3 ++- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 5dcd54050c..c7f7c2c354 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -616,12 +616,11 @@ void Audio::handleAudioInput() { void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { const int NUM_INITIAL_PACKETS_DISCARD = 3; const int STANDARD_DEVIATION_SAMPLE_COUNT = 500; - - timeval currentReceiveTime; - gettimeofday(¤tReceiveTime, NULL); + + _timeSinceLastRecieved.start(); _totalPacketsReceived++; - - double timeDiff = diffclock(&_lastReceiveTime, ¤tReceiveTime); + + double timeDiff = (double)_timeSinceLastRecieved.nsecsElapsed() / 1000000.0; // ns to ms // Discard first few received packets for computing jitter (often they pile up on start) if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) { @@ -646,8 +645,6 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { } Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::AUDIO).updateValue(audioByteArray.size()); - - _lastReceiveTime = currentReceiveTime; } bool Audio::mousePressEvent(int x, int y) { @@ -995,7 +992,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // setup a procedural audio output device _proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); - gettimeofday(&_lastReceiveTime, NULL); + _timeSinceLastRecieved.start(); supportedFormat = true; } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index b78bcc661e..3fa4175573 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -123,7 +124,7 @@ private: QString _outputAudioDeviceName; StDev _stdev; - timeval _lastReceiveTime; + QElapsedTimer _timeSinceLastRecieved; float _averagedLatency; float _measuredJitter; int16_t _jitterBufferSamples; From dd8a0e355055476af97f6f668d451b4182e4e5a4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 16 Apr 2014 12:16:49 -0700 Subject: [PATCH 08/68] Removed gettimeofday in AudioMixer --- assignment-client/src/audio/AudioMixer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 407a64d7a8..65d09f1b00 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -389,9 +389,8 @@ void AudioMixer::run() { nodeList->linkedDataCreateCallback = attachNewBufferToNode; int nextFrame = 0; - timeval startTime; - - gettimeofday(&startTime, NULL); + QElapsedTimer timer; + timer.start(); char* clientMixBuffer = new char[NETWORK_BUFFER_LENGTH_BYTES_STEREO + numBytesForPacketHeaderGivenPacketType(PacketTypeMixedAudio)]; @@ -490,7 +489,7 @@ void AudioMixer::run() { break; } - usecToSleep = usecTimestamp(&startTime) + (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - usecTimestampNow(); + usecToSleep = (++nextFrame * BUFFER_SEND_INTERVAL_USECS) - timer.nsecsElapsed() / 1000; // ns to us if (usecToSleep > 0) { usleep(usecToSleep); From e8b6b7ab4de72f6c09dcba9735c66548531f9979 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 13:22:22 -0700 Subject: [PATCH 09/68] Update style of chat message links --- interface/src/ui/ChatWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index e26c0bcb94..c943607d71 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -300,6 +300,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea"); } + messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}"); messageArea->setHtml(message.body().replace(regexLinks, "\\1")); bool atBottom = isAtBottom(); From 23d68d538c8bda8c7a82d95ecd9d1201800ab1ad Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 16 Apr 2014 14:05:38 -0700 Subject: [PATCH 10/68] Fix bug where multiple user/location popups appear --- interface/src/ui/ChatWindow.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index c943607d71..2849d0c748 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -113,7 +113,6 @@ void ChatWindow::showEvent(QShowEvent* event) { } bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { - FramelessDialog::eventFilter(sender, event); if (sender == ui->messagePlainTextEdit) { if (event->type() != QEvent::KeyPress) { return false; @@ -135,14 +134,14 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { } return true; } - } else { - if (event->type() != QEvent::MouseButtonRelease) { - return false; + } else if (event->type() == QEvent::MouseButtonRelease) { + QVariant userVar = sender->property("user"); + if (userVar.isValid()) { + Menu::getInstance()->goToUser("@" + userVar.toString()); + return true; } - QString user = sender->property("user").toString(); - Menu::getInstance()->goToUser(user); } - return false; + return FramelessDialog::eventFilter(sender, event); } #ifdef HAVE_QXMPP From 606a48d555642bb1aa3cdd1b2e7435d7376d56f7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 09:36:17 -0700 Subject: [PATCH 11/68] Fix issue with pref dialog disappearing With the frameless dialog being updated to support different types of window, the pref dialog was no longer able to rely on it to keep itself open in certain cases. The window flags were also updated to update after a "browse" call rather than in the slot so that it would still execute in the case of cancelled selection. --- interface/src/ui/PreferencesDialog.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 0f2216407f..550c616fc1 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -38,26 +38,34 @@ void PreferencesDialog::accept() { void PreferencesDialog::setHeadUrl(QString modelUrl) { ui.faceURLEdit->setText(modelUrl); - setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); } void PreferencesDialog::setSkeletonUrl(QString modelUrl) { ui.skeletonURLEdit->setText(modelUrl); - setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); } void PreferencesDialog::openHeadModelBrowser() { setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + show(); + ModelsBrowser modelBrowser(Head); connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl); modelBrowser.browse(); + + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + show(); } void PreferencesDialog::openBodyModelBrowser() { setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint); + show(); + ModelsBrowser modelBrowser(Skeleton); connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl); modelBrowser.browse(); + + setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); + show(); } void PreferencesDialog::openSnapshotLocationBrowser() { From c1fa6b41e45bb9d4442afc2eee10cdded63ef919 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 13:19:36 -0700 Subject: [PATCH 12/68] Update chat window to use vertical layout --- interface/src/ui/ChatWindow.cpp | 55 +++++++++------------------------ interface/ui/chatWindow.ui | 10 +++--- 2 files changed, 18 insertions(+), 47 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 2849d0c748..ae5dd0185c 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -44,9 +44,6 @@ ChatWindow::ChatWindow(QWidget* parent) : FlowLayout* flowLayout = new FlowLayout(0, 4, 4); ui->usersWidget->setLayout(flowLayout); - ui->messagesGridLayout->setColumnStretch(0, 1); - ui->messagesGridLayout->setColumnStretch(1, 3); - ui->messagePlainTextEdit->installEventFilter(this); ui->messagePlainTextEdit->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); @@ -172,8 +169,8 @@ void ChatWindow::addTimeStamp() { bool atBottom = isAtBottom(); - ui->messagesGridLayout->addWidget(timeLabel, ui->messagesGridLayout->rowCount(), 0, 1, 2); - ui->messagesGridLayout->parentWidget()->updateGeometry(); + ui->messagesVBoxLayout->addWidget(timeLabel); + ui->messagesVBoxLayout->parentWidget()->updateGeometry(); Application::processEvents(); numMessagesAfterLastTimeStamp = 0; @@ -251,29 +248,8 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { return; } - // Create username label - ChatMessageArea* userLabel = new ChatMessageArea(false); - userLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - userLabel->setWordWrapMode(QTextOption::NoWrap); - userLabel->setLineWrapMode(QTextEdit::NoWrap); - userLabel->setTextInteractionFlags(Qt::NoTextInteraction); - userLabel->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - userLabel->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - userLabel->setReadOnly(true); - userLabel->setSizeAdjustPolicy(QAbstractScrollArea::AdjustToContents); - - userLabel->setStyleSheet("padding: 2px;" - "font-weight: bold;" - "background-color: rgba(0, 0, 0, 0%);" - "border: 0;"); - - QTextBlockFormat format; - format.setLineHeight(130, QTextBlockFormat::ProportionalHeight); - QTextCursor cursor = userLabel->textCursor(); - cursor.setBlockFormat(format); - cursor.insertText(getParticipantName(message.from())); - - userLabel->setAlignment(Qt::AlignRight); + // Update background if this is a message from the current user + bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername(); // Create message area ChatMessageArea* messageArea = new ChatMessageArea(true); @@ -289,30 +265,27 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { "padding-left: 2px;" "padding-top: 2px;" "padding-right: 20px;" + "margin: 0px;" + "color: #333333;" + "font-size: 14pt;" "background-color: rgba(0, 0, 0, 0%);" "border: 0;"); - // Update background if this is a message from the current user - bool fromSelf = getParticipantName(message.from()) == AccountManager::getInstance().getUsername(); + QString userLabel = getParticipantName(message.from()); if (fromSelf) { - userLabel->setStyleSheet(userLabel->styleSheet() + "background-color: #e1e8ea"); + userLabel = "" + userLabel + ": "; messageArea->setStyleSheet(messageArea->styleSheet() + "background-color: #e1e8ea"); + } else { + userLabel = "" + userLabel + ": "; } messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}"); - messageArea->setHtml(message.body().replace(regexLinks, "\\1")); + messageArea->setHtml(userLabel + message.body().replace(regexLinks, "\\1")); bool atBottom = isAtBottom(); - ui->messagesGridLayout->addWidget(userLabel, ui->messagesGridLayout->rowCount(), 0); - ui->messagesGridLayout->addWidget(messageArea, ui->messagesGridLayout->rowCount() - 1, 1); - // Force the height of the username area to match the height of the message area - connect(messageArea, &ChatMessageArea::sizeChanged, userLabel, &ChatMessageArea::setSize); - - // Force initial height to match message area - userLabel->setFixedHeight(messageArea->size().height()); - - ui->messagesGridLayout->parentWidget()->updateGeometry(); + ui->messagesVBoxLayout->addWidget(messageArea); + ui->messagesVBoxLayout->parentWidget()->updateGeometry(); Application::processEvents(); if (atBottom || fromSelf) { diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 78757ded38..b516418f8c 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -159,7 +159,10 @@ QPushButton:pressed { margin-top: 0px; - + + + 0 + 0 @@ -172,9 +175,6 @@ QPushButton:pressed { 0 - - 0 - @@ -213,8 +213,6 @@ QPushButton:pressed { - messagePlainTextEdit - dockWidgetContents messagePlainTextEdit From 7a25d0661f5ff48818090e5ae004e6efffad3dba Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 13:20:00 -0700 Subject: [PATCH 13/68] Update style of chat messages --- interface/src/ui/ChatWindow.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index ae5dd0185c..78c667f41e 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -162,10 +162,10 @@ void ChatWindow::addTimeStamp() { if (!timeString.isEmpty()) { QLabel* timeLabel = new QLabel(timeString); timeLabel->setStyleSheet("color: palette(shadow);" - "background-color: palette(highlight);" + "background-color: white;" "padding: 4px;"); timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - timeLabel->setAlignment(Qt::AlignHCenter); + timeLabel->setAlignment(Qt::AlignLeft); bool atBottom = isAtBottom(); @@ -235,6 +235,7 @@ void ChatWindow::participantsChanged() { "padding-bottom: 2px;" "padding-left: 2px;" "border: 1px solid palette(shadow);" + "font-size: 14pt;" "font-weight: bold"); userLabel->setProperty("user", participantName); userLabel->setCursor(Qt::PointingHandCursor); From 3ee613b9d581bcb2e1aebd123aa13c97ddb32b4e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 13:20:17 -0700 Subject: [PATCH 14/68] Add right margin to user list area in chat --- interface/ui/chatWindow.ui | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index b516418f8c..34e6c6aeaf 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -128,7 +128,13 @@ QPushButton:pressed { - + + + #usersWidget { + margin-right: 20px; +} + + From 48a75616446a9b57cb280e806e15ba7593505679 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 13:38:13 -0700 Subject: [PATCH 15/68] Fix chat messages not being html escaped --- interface/src/ui/ChatWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 78c667f41e..5d3c5e5a75 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -281,7 +281,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { } messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}"); - messageArea->setHtml(userLabel + message.body().replace(regexLinks, "\\1")); + messageArea->setHtml(userLabel + message.body().toHtmlEscaped().replace(regexLinks, "\\1")); bool atBottom = isAtBottom(); From e2954f8614c018ddf594e08dd29122b4d18fcfb6 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 13:49:10 -0700 Subject: [PATCH 16/68] Fix color and size of font in timestamp chat messages --- interface/src/ui/ChatWindow.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 5d3c5e5a75..ad59222202 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -161,8 +161,9 @@ void ChatWindow::addTimeStamp() { timeString.chop(1); if (!timeString.isEmpty()) { QLabel* timeLabel = new QLabel(timeString); - timeLabel->setStyleSheet("color: palette(shadow);" + timeLabel->setStyleSheet("color: #333333;" "background-color: white;" + "font-size: 14pt;" "padding: 4px;"); timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); timeLabel->setAlignment(Qt::AlignLeft); From f2112c665abc15ed0038af79cda1b7ca2e62f509 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 14:02:21 -0700 Subject: [PATCH 17/68] Disallow rich text from being pasted into the chat area --- interface/ui/chatWindow.ui | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 34e6c6aeaf..d63542bf7b 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -214,6 +214,9 @@ QPushButton:pressed { true + + false + From e1e9c11189d57383a98fc5381d5ee8e708300511 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 15:18:40 -0700 Subject: [PATCH 18/68] Add Menu slot to open urls --- interface/src/Menu.cpp | 11 +++++++++++ interface/src/Menu.h | 1 + 2 files changed, 12 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9de6dfad3b..ad765c0e8e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -906,6 +906,17 @@ void Menu::goToUser(const QString& user) { connect(manager, &LocationManager::multipleDestinationsFound, this, &Menu::multipleDestinationsDecision); } +/// Open a url, shortcutting any "hifi" scheme URLs to the local application. +void Menu::openUrl(const QUrl& url) { + if (url.scheme() == "hifi") { + QString path = url.toString(QUrl::RemoveScheme); + path = path.remove(QRegExp("^:?/*")); + goTo(path); + } else { + QDesktopServices::openUrl(url); + } +} + void Menu::multipleDestinationsDecision(const QJsonObject& userData, const QJsonObject& placeData) { QMessageBox msgBox; msgBox.setText("Both user and location exists with same name"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 40ed8efdc7..ff27810df5 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -153,6 +153,7 @@ public slots: void goTo(); void goToUser(const QString& user); void pasteToVoxel(); + void openUrl(const QUrl& url); void toggleLoginMenuItem(); From 795ddbc7bf9d9b4cda49c89a2e37ff2dca56fb87 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 15:19:13 -0700 Subject: [PATCH 19/68] Update ChatMessageArea to open urls via Menu::openUrl --- interface/src/ui/ChatMessageArea.cpp | 4 ++++ interface/src/ui/ChatWindow.cpp | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ChatMessageArea.cpp b/interface/src/ui/ChatMessageArea.cpp index 929ad85d87..1e16a8a2db 100644 --- a/interface/src/ui/ChatMessageArea.cpp +++ b/interface/src/ui/ChatMessageArea.cpp @@ -15,8 +15,12 @@ #include ChatMessageArea::ChatMessageArea(bool useFixedHeight) : QTextBrowser(), _useFixedHeight(useFixedHeight) { + setOpenLinks(false); + connect(document()->documentLayout(), &QAbstractTextDocumentLayout::documentSizeChanged, this, &ChatMessageArea::updateLayout); + connect(this, &QTextBrowser::anchorClicked, + Menu::getInstance(), &Menu::openUrl); } void ChatMessageArea::setHtml(const QString& html) { diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index ad59222202..e1ee30b4b9 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -255,8 +255,6 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { // Create message area ChatMessageArea* messageArea = new ChatMessageArea(true); - messageArea->setOpenLinks(true); - messageArea->setOpenExternalLinks(true); messageArea->setWordWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere); messageArea->setTextInteractionFlags(Qt::TextBrowserInteraction); messageArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); From 4f236c6bf45cc58ca60bf7d4b7a4a288d28cf7b9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 15:20:12 -0700 Subject: [PATCH 20/68] Add hifi link handling in chat for usernames and locations --- interface/src/ui/ChatWindow.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index e1ee30b4b9..9679e73132 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -29,6 +29,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); +const QRegularExpression regexHifiLinks("\\s([#@]\\S+)"); ChatWindow::ChatWindow(QWidget* parent) : FramelessDialog(parent, 0, POSITION_RIGHT), @@ -280,7 +281,10 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { } messageArea->document()->setDefaultStyleSheet("a { text-decoration: none; font-weight: bold; color: #267077;}"); - messageArea->setHtml(userLabel + message.body().toHtmlEscaped().replace(regexLinks, "\\1")); + QString messageText = message.body().toHtmlEscaped(); + messageText = messageText.replace(regexLinks, "\\1"); + messageText = messageText.replace(regexHifiLinks, "\\1"); + messageArea->setHtml(userLabel + messageText); bool atBottom = isAtBottom(); From 6437f76ed2488e02341e56f43fd04bb496a099bd Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 15:50:40 -0700 Subject: [PATCH 21/68] Update username/location match in chat to be more lenient --- interface/src/ui/ChatWindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 9679e73132..c459a6d426 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -29,7 +29,7 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); -const QRegularExpression regexHifiLinks("\\s([#@]\\S+)"); +const QRegularExpression regexHifiLinks("([#@]\\S+)"); ChatWindow::ChatWindow(QWidget* parent) : FramelessDialog(parent, 0, POSITION_RIGHT), From 3c9b6264a8354f514324f6a97992a67b01ad924a Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 19:51:25 -0700 Subject: [PATCH 22/68] Add emoticons to chat --- interface/resources/images/cool.svg | 8 ++++++++ interface/resources/images/grin.svg | 8 ++++++++ interface/resources/images/happy.svg | 8 ++++++++ interface/resources/images/sad.svg | 8 ++++++++ interface/resources/images/smiley.svg | 8 ++++++++ interface/resources/images/tongue.svg | 8 ++++++++ interface/resources/images/wink.svg | 8 ++++++++ interface/src/ui/ChatWindow.cpp | 19 ++++++++++++++++++- interface/src/ui/ChatWindow.h | 1 + 9 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 interface/resources/images/cool.svg create mode 100644 interface/resources/images/grin.svg create mode 100644 interface/resources/images/happy.svg create mode 100644 interface/resources/images/sad.svg create mode 100644 interface/resources/images/smiley.svg create mode 100644 interface/resources/images/tongue.svg create mode 100644 interface/resources/images/wink.svg diff --git a/interface/resources/images/cool.svg b/interface/resources/images/cool.svg new file mode 100644 index 0000000000..2e8348108a --- /dev/null +++ b/interface/resources/images/cool.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/grin.svg b/interface/resources/images/grin.svg new file mode 100644 index 0000000000..8e36a16555 --- /dev/null +++ b/interface/resources/images/grin.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/happy.svg b/interface/resources/images/happy.svg new file mode 100644 index 0000000000..fe31d01991 --- /dev/null +++ b/interface/resources/images/happy.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/sad.svg b/interface/resources/images/sad.svg new file mode 100644 index 0000000000..0029bfded5 --- /dev/null +++ b/interface/resources/images/sad.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/smiley.svg b/interface/resources/images/smiley.svg new file mode 100644 index 0000000000..1b0e707bf6 --- /dev/null +++ b/interface/resources/images/smiley.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/tongue.svg b/interface/resources/images/tongue.svg new file mode 100644 index 0000000000..35361d2b2b --- /dev/null +++ b/interface/resources/images/tongue.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/resources/images/wink.svg b/interface/resources/images/wink.svg new file mode 100644 index 0000000000..b1aef4823d --- /dev/null +++ b/interface/resources/images/wink.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index c459a6d426..06608ef5e4 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -31,12 +31,14 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); const QRegularExpression regexHifiLinks("([#@]\\S+)"); + ChatWindow::ChatWindow(QWidget* parent) : FramelessDialog(parent, 0, POSITION_RIGHT), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0), _mousePressed(false), - _mouseStartPosition() + _mouseStartPosition(), + _emoticonMap() { setAttribute(Qt::WA_DeleteOnClose, false); @@ -63,6 +65,14 @@ ChatWindow::ChatWindow(QWidget* parent) : ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others.")); } + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":)")), new QString("../resources/images/smiley.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":D")), new QString("../resources/images/happy.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape("B)")), new QString("../resources/images/cool.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":O")), new QString("../resources/images/grin.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":(")), new QString("../resources/images/sad.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":P")), new QString("../resources/images/tongue.svg")); + _emoticonMap.insert(new QRegularExpression(QRegExp::escape(";)")), new QString("../resources/images/wink.svg")); + #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { @@ -284,6 +294,13 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { QString messageText = message.body().toHtmlEscaped(); messageText = messageText.replace(regexLinks, "\\1"); messageText = messageText.replace(regexHifiLinks, "\\1"); + + QMapIterator it(_emoticonMap); + while (it.hasNext()) { + it.next(); + messageText.replace(*it.key(), ""); + } + messageArea->setHtml(userLabel + messageText); bool atBottom = isAtBottom(); diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 399c9e917c..3dce35b1b2 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -57,6 +57,7 @@ private: QDateTime lastMessageStamp; bool _mousePressed; QPoint _mouseStartPosition; + QMap _emoticonMap; private slots: void connected(); From c0ae2fd7ae5b100af15a69f892205736271adc06 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 17 Apr 2014 19:53:59 -0700 Subject: [PATCH 23/68] Add QDesktopServices header to Menu.cpp --- interface/src/Menu.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index ad765c0e8e..5ff74f0ad9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include From 30248747d6475bed432318f8fee77a7741cd8d46 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 14:26:34 -0700 Subject: [PATCH 24/68] Provide a means of visualizing the joint constraints. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/MyAvatar.cpp | 3 ++ interface/src/avatar/SkeletonModel.cpp | 61 ++++++++++++++++++++++++++ interface/src/avatar/SkeletonModel.h | 4 ++ 5 files changed, 70 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index b05e5c91bc..bb20a469b4 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -330,6 +330,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index c17c9cc507..710cc5d78b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -348,6 +348,7 @@ namespace MenuOption { const QString SettingsImport = "Import Settings"; const QString Shadows = "Shadows"; const QString ShowCulledSharedFaces = "Show Culled Shared Voxel Faces"; + const QString ShowIKConstraints = "Show IK Constraints"; const QString Stars = "Stars"; const QString Stats = "Stats"; const QString StopAllScripts = "Stop All Scripts"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 8229611646..a8d6dfa242 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -460,6 +460,9 @@ void MyAvatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) { return; // exit early } Avatar::render(cameraPosition, renderMode); + if (Menu::getInstance()->isOptionChecked(MenuOption::ShowIKConstraints)) { + _skeletonModel.renderIKConstraints(); + } } void MyAvatar::renderHeadMouse() const { diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index b9ac280711..8d593a9c02 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -103,6 +103,11 @@ void SkeletonModel::getBodyShapes(QVector& shapes) const { shapes.push_back(&_boundingShape); } +void SkeletonModel::renderIKConstraints() { + renderJointConstraints(getRightHandJointIndex()); + renderJointConstraints(getLeftHandJointIndex()); +} + class IndexValue { public: int index; @@ -210,3 +215,59 @@ void SkeletonModel::maybeUpdateLeanRotation(const JointState& parentState, const glm::normalize(inverse * axes[0])) * joint.rotation; } +void SkeletonModel::renderJointConstraints(int jointIndex) { + if (jointIndex == -1) { + return; + } + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const float BASE_DIRECTION_SIZE = 300.0f; + float directionSize = BASE_DIRECTION_SIZE * extractUniformScale(_scale); + glLineWidth(3.0f); + do { + const FBXJoint& joint = geometry.joints.at(jointIndex); + const JointState& jointState = _jointStates.at(jointIndex); + glm::vec3 position = extractTranslation(jointState.transform) + _translation; + + glPushMatrix(); + glTranslatef(position.x, position.y, position.z); + glm::quat parentRotation = (joint.parentIndex == -1) ? _rotation : _jointStates.at(joint.parentIndex).combinedRotation; + glm::vec3 rotationAxis = glm::axis(parentRotation); + glRotatef(glm::degrees(glm::angle(parentRotation)), rotationAxis.x, rotationAxis.y, rotationAxis.z); + float fanScale = directionSize * 0.75f; + glScalef(fanScale, fanScale, fanScale); + const int AXIS_COUNT = 3; + for (int i = 0; i < AXIS_COUNT; i++) { + if (joint.rotationMin[i] <= -PI + EPSILON && joint.rotationMax[i] >= PI - EPSILON) { + continue; // unconstrained + } + glm::vec3 axis; + axis[i] = 1.0f; + + glm::vec3 otherAxis; + if (i == 0) { + otherAxis.y = 1.0f; + } else { + otherAxis.x = 1.0f; + } + glColor4f(otherAxis.r, otherAxis.g, otherAxis.b, 0.75f); + + glBegin(GL_TRIANGLE_FAN); + glVertex3f(0.0f, 0.0f, 0.0f); + const int FAN_SEGMENTS = 16; + for (int j = 0; j < FAN_SEGMENTS; j++) { + glm::vec3 rotated = glm::angleAxis(glm::mix(joint.rotationMin[i], joint.rotationMax[i], + (float)j / (FAN_SEGMENTS - 1)), axis) * otherAxis; + glVertex3f(rotated.x, rotated.y, rotated.z); + } + glEnd(); + } + glPopMatrix(); + + renderOrientationDirections(position, jointState.combinedRotation, directionSize); + jointIndex = joint.parentIndex; + + } while (jointIndex != -1 && geometry.joints.at(jointIndex).isFree); + + glLineWidth(1.0f); +} + diff --git a/interface/src/avatar/SkeletonModel.h b/interface/src/avatar/SkeletonModel.h index 2020ccf3b2..0a87fcf89d 100644 --- a/interface/src/avatar/SkeletonModel.h +++ b/interface/src/avatar/SkeletonModel.h @@ -33,6 +33,8 @@ public: /// \param shapes[out] list of shapes for body collisions void getBodyShapes(QVector& shapes) const; + void renderIKConstraints(); + protected: void applyHandPosition(int jointIndex, const glm::vec3& position); @@ -46,6 +48,8 @@ protected: virtual void maybeUpdateLeanRotation(const JointState& parentState, const FBXJoint& joint, JointState& state); private: + + void renderJointConstraints(int jointIndex); Avatar* _owningAvatar; }; From 6add0dfb4271360d1d3dff82fbf4f61a67041934 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 15:04:42 -0700 Subject: [PATCH 25/68] Tweaked Hydra "IK" to propagate delta rotations up the hierarchy while preserving joint constraints. --- interface/src/avatar/SkeletonModel.cpp | 7 ++++--- interface/src/renderer/Model.cpp | 13 ++++++++++--- interface/src/renderer/Model.h | 2 +- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 8d593a9c02..1c6a568754 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -138,7 +138,7 @@ void SkeletonModel::applyHandPosition(int jointIndex, const glm::vec3& position) // align hand with forearm float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector), false); + applyRotationDelta(jointIndex, rotationBetween(handRotation * glm::vec3(-sign, 0.0f, 0.0f), forearmVector)); } void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJointIndices, @@ -156,7 +156,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin // rotate forearm to align with palm direction glm::quat palmRotation; getJointRotation(parentJointIndex, palmRotation, true); - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), false); + applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), true, true); getJointRotation(parentJointIndex, palmRotation, true); // sort the finger indices by raw x, get the average direction @@ -178,7 +178,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float directionLength = glm::length(direction); const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), false); + applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), + true, true); getJointRotation(parentJointIndex, palmRotation, true); } diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index f8de7210ea..36088dec70 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -997,9 +997,10 @@ float Model::getLimbLength(int jointIndex) const { return length; } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, bool propagate) { JointState& state = _jointStates[jointIndex]; - const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; + const FBXGeometry& geometry = _geometry->getFBXGeometry(); + const FBXJoint& joint = geometry.joints[jointIndex]; if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && joint.rotationMax == glm::vec3(PI, PI, PI))) { // no constraints @@ -1007,10 +1008,16 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons state.combinedRotation = delta * state.combinedRotation; return; } + glm::quat targetRotation = delta * state.combinedRotation; glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * delta * state.combinedRotation), joint.rotationMin, joint.rotationMax)); + glm::inverse(state.combinedRotation) * targetRotation), joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; + + if (propagate && targetRotation != state.combinedRotation && + joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { + applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); + } } const int BALL_SUBDIVISIONS = 10; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 65b79fffdd..b472e17b20 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -256,7 +256,7 @@ protected: /// first free ancestor. float getLimbLength(int jointIndex) const; - void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true); + void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true, bool propagate = false); private: From 743034c986fffd65bd564176239b3de019836367 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 15:09:37 -0700 Subject: [PATCH 26/68] Need to transfer parent rotation to child. --- interface/src/renderer/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 36088dec70..17d3dd783c 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1017,6 +1017,7 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons if (propagate && targetRotation != state.combinedRotation && joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); + state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; } } From e2558bdac088908ed755fcdb3d3175932567d9a6 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 18 Apr 2014 17:16:20 -0700 Subject: [PATCH 27/68] Experimenting with tweaking the Euler angles so that z, rather than y, is in [-pi/2, pi/2]. --- interface/src/renderer/Model.cpp | 11 ++++++--- libraries/shared/src/SharedUtil.cpp | 38 ++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 17d3dd783c..2ff8a0fee9 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -892,6 +892,11 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last lastFreeIndex = freeLineage.last(); } + // now update the joint states from the top + for (int j = freeLineage.size() - 1; j >= 0; j--) { + updateJointState(freeLineage.at(j)); + } + // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; @@ -1009,13 +1014,13 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons return; } glm::quat targetRotation = delta * state.combinedRotation; - glm::quat newRotation = glm::quat(glm::clamp(safeEulerAngles(state.rotation * - glm::inverse(state.combinedRotation) * targetRotation), joint.rotationMin, joint.rotationMax)); + glm::vec3 eulers = safeEulerAngles(state.rotation * glm::inverse(state.combinedRotation) * targetRotation); + glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; if (propagate && targetRotation != state.combinedRotation && - joint.parentIndex != -1 && geometry.joints[joint.parentIndex].isFree) { + joint.parentIndex != -1 && geometry.joints.at(joint.parentIndex).isFree) { applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f4e4b28f93..69381a07ae 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -640,27 +640,59 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) glm::vec3 safeEulerAngles(const glm::quat& q) { float sy = 2.0f * (q.y * q.w - q.x * q.z); + glm::vec3 eulers; if (sy < 1.0f - EPSILON) { if (sy > -1.0f + EPSILON) { - return glm::vec3( + eulers = glm::vec3( atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), asinf(sy), atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); } else { // not a unique solution; x + z = atan2(-m21, m11) - return glm::vec3( + eulers = glm::vec3( 0.0f, - PI_OVER_TWO, atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } } else { // not a unique solution; x - z = atan2(-m21, m11) - return glm::vec3( + eulers = glm::vec3( 0.0f, PI_OVER_TWO, -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); } + + // adjust so that z, rather than y, is in [-pi/2, pi/2] + if (eulers.z < -PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z += PI; + + } else if (eulers.z > PI_OVER_TWO) { + if (eulers.x < 0.0f) { + eulers.x += PI; + } else { + eulers.x -= PI; + } + eulers.y = -eulers.y; + if (eulers.y < 0.0f) { + eulers.y += PI; + } else { + eulers.y -= PI; + } + eulers.z -= PI; + } + return eulers; } // Helper function returns the positive angle (in radians) between two 3D vectors From f7f30e118c4f1b36178a3e0d4f4bd603f4519221 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 21 Apr 2014 15:17:11 -0700 Subject: [PATCH 28/68] More gettimeofday cleanup --- interface/src/Application.cpp | 27 ++++----- interface/src/Application.h | 8 +-- interface/src/Util.cpp | 47 +++++---------- interface/src/Util.h | 2 - interface/src/main.cpp | 6 +- interface/src/starfield/Controller.cpp | 10 ++-- interface/src/starfield/Generator.cpp | 9 ++- interface/src/ui/BandwidthMeter.cpp | 13 ++--- interface/src/ui/BandwidthMeter.h | 4 +- libraries/script-engine/src/ScriptEngine.cpp | 6 +- libraries/shared/src/SharedUtil.cpp | 4 -- libraries/shared/src/SharedUtil.h | 1 - libraries/shared/src/Systime.cpp | 61 -------------------- libraries/shared/src/Systime.h | 27 --------- 14 files changed, 57 insertions(+), 168 deletions(-) delete mode 100644 libraries/shared/src/Systime.cpp delete mode 100644 libraries/shared/src/Systime.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cd07f21300..92c63dacf3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -134,7 +134,7 @@ QString& Application::resourcesPath() { return staticResourcePath; } -Application::Application(int& argc, char** argv, timeval &startup_time) : +Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : QApplication(argc, argv), _window(new QMainWindow(desktop())), _glWidget(new GLCanvas()), @@ -507,7 +507,7 @@ void Application::initializeGL() { _idleLoopStdev.reset(); if (_justStarted) { - float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime)) / 1000000.0; + float startupTime = _applicationStartupTime.elapsed() / 1000.0; _justStarted = false; qDebug("Startup time: %4.2f seconds.", startupTime); const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; @@ -1273,21 +1273,21 @@ void Application::sendPingPackets() { // Every second, check the frame rates and other stuff void Application::timer() { - gettimeofday(&_timerEnd, NULL); - if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) { sendPingPackets(); } + + float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0; - _fps = (float)_frameCount / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + _fps = (float)_frameCount / diffTime; - _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); - _bytesPerSecond = (float) _datagramProcessor.getByteCount() / ((float)diffclock(&_timerStart, &_timerEnd) / 1000.f); + _packetsPerSecond = (float) _datagramProcessor.getPacketCount() / diffTime; + _bytesPerSecond = (float) _datagramProcessor.getByteCount() / diffTime; _frameCount = 0; _datagramProcessor.resetCounters(); - gettimeofday(&_timerStart, NULL); + _timerStart.start(); // ask the node list to check in with the domain server NodeList::getInstance()->sendDomainServerCheckIn(); @@ -1300,13 +1300,11 @@ void Application::idle() { bool showWarnings = getLogger()->extraDebugging(); PerformanceWarning warn(showWarnings, "Application::idle()"); - timeval check; - gettimeofday(&check, NULL); - // Only run simulation code if more than IDLE_SIMULATE_MSECS have passed since last time we ran - double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); + double timeSinceLastUpdate = (double)_lastTimeUpdated.nsecsElapsed() / 1000000.0; if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { + _lastTimeUpdated.start(); { PerformanceWarning warn(showWarnings, "Application::idle()... update()"); const float BIGGEST_DELTA_TIME_SECS = 0.25f; @@ -1318,7 +1316,6 @@ void Application::idle() { } { PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); - _lastTimeUpdated = check; _idleLoopStdev.addValue(timeSinceLastUpdate); // Record standard deviation and reset counter if needed @@ -1634,8 +1631,8 @@ void Application::init() { Qt::QueuedConnection); } - gettimeofday(&_timerStart, NULL); - gettimeofday(&_lastTimeUpdated, NULL); + _timerStart.start(); + _lastTimeUpdated.start(); Menu::getInstance()->loadSettings(); if (Menu::getInstance()->getAudioJitterBufferSamples() != 0) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 9d609ad5f5..36758a26db 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -117,7 +117,7 @@ public: static Application* getInstance() { return static_cast(QCoreApplication::instance()); } static QString& resourcesPath(); - Application(int& argc, char** argv, timeval &startup_time); + Application(int& argc, char** argv, QElapsedTimer &startup_time); ~Application(); void restoreSizeAndPosition(); @@ -391,9 +391,9 @@ private: int _frameCount; float _fps; - timeval _applicationStartupTime; - timeval _timerStart, _timerEnd; - timeval _lastTimeUpdated; + QElapsedTimer _applicationStartupTime; + QElapsedTimer _timerStart; + QElapsedTimer _lastTimeUpdated; bool _justStarted; Stars _stars; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 1dae3a4fd6..9dfe9d8002 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -172,14 +172,6 @@ void renderWorldBox() { } -double diffclock(timeval *clock1,timeval *clock2) -{ - double diffms = (clock2->tv_sec - clock1->tv_sec) * 1000.0; - diffms += (clock2->tv_usec - clock1->tv_usec) / 1000.0; // us to ms - - return diffms; -} - // Return a random vector of average length 1 const glm::vec3 randVector() { return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.f; @@ -411,68 +403,61 @@ void runTimingTests() { int iResults[numTests]; float fTest = 1.0; float fResults[numTests]; - timeval startTime, endTime; + QElapsedTimer startTime; + startTime.start(); float elapsedMsecs; - gettimeofday(&startTime, NULL); - for (int i = 1; i < numTests; i++) { - gettimeofday(&endTime, NULL); - } - elapsedMsecs = diffclock(&startTime, &endTime); - qDebug("gettimeofday() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests); + + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("QElapsedTimer::nsecElapsed() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests); // Random number generation - gettimeofday(&startTime, NULL); + startTime.start(); for (int i = 1; i < numTests; i++) { iResults[i] = rand(); } - gettimeofday(&endTime, NULL); - elapsedMsecs = diffclock(&startTime, &endTime); + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; qDebug("rand() stored in array usecs: %f, first result:%d", 1000.0f * elapsedMsecs / (float) numTests, iResults[0]); // Random number generation using randFloat() - gettimeofday(&startTime, NULL); + startTime.start(); for (int i = 1; i < numTests; i++) { fResults[i] = randFloat(); } - gettimeofday(&endTime, NULL); - elapsedMsecs = diffclock(&startTime, &endTime); + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; qDebug("randFloat() stored in array usecs: %f, first result: %f", 1000.0f * elapsedMsecs / (float) numTests, fResults[0]); // PowF function fTest = 1145323.2342f; - gettimeofday(&startTime, NULL); + startTime.start(); for (int i = 1; i < numTests; i++) { fTest = powf(fTest, 0.5f); } - gettimeofday(&endTime, NULL); - elapsedMsecs = diffclock(&startTime, &endTime); + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedMsecs / (float) numTests); // Vector Math float distance; glm::vec3 pointA(randVector()), pointB(randVector()); - gettimeofday(&startTime, NULL); + startTime.start(); for (int i = 1; i < numTests; i++) { //glm::vec3 temp = pointA - pointB; //float distanceSquared = glm::dot(temp, temp); distance = glm::distance(pointA, pointB); } - gettimeofday(&endTime, NULL); - elapsedMsecs = diffclock(&startTime, &endTime); + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; qDebug("vector math usecs: %f [%f msecs total for %d tests], last result:%f", 1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests, distance); // Vec3 test glm::vec3 vecA(randVector()), vecB(randVector()); float result; - - gettimeofday(&startTime, NULL); + + startTime.start(); for (int i = 1; i < numTests; i++) { glm::vec3 temp = vecA-vecB; result = glm::dot(temp,temp); } - gettimeofday(&endTime, NULL); - elapsedMsecs = diffclock(&startTime, &endTime); + elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; qDebug("vec3 assign and dot() usecs: %f, last result:%f", 1000.0f * elapsedMsecs / (float) numTests, result); } diff --git a/interface/src/Util.h b/interface/src/Util.h index 4bd1ed604c..dee0f864b4 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -44,8 +44,6 @@ void drawVector(glm::vec3* vector); void printVector(glm::vec3 vec); -double diffclock(timeval *clock1,timeval *clock2); - void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0); void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size ); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 40e2a9ab27..2bb0633f24 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -16,8 +16,8 @@ #include int main(int argc, const char * argv[]) { - timeval startup_time; - gettimeofday(&startup_time, NULL); + QElapsedTimer startupTime; + startupTime.start(); // Debug option to demonstrate that the client's local time does not // need to be in sync with any other network node. This forces clock @@ -33,7 +33,7 @@ int main(int argc, const char * argv[]) { int exitCode; { QSettings::setDefaultFormat(QSettings::IniFormat); - Application app(argc, const_cast(argv), startup_time); + Application app(argc, const_cast(argv), startupTime); QTranslator translator; translator.load("interface_en"); diff --git a/interface/src/starfield/Controller.cpp b/interface/src/starfield/Controller.cpp index 771029c689..2476c33d45 100755 --- a/interface/src/starfield/Controller.cpp +++ b/interface/src/starfield/Controller.cpp @@ -13,20 +13,22 @@ #include #endif +#include + #include "starfield/Controller.h" using namespace starfield; bool Controller::computeStars(unsigned numStars, unsigned seed) { - timeval startTime; - gettimeofday(&startTime, NULL); + QElapsedTimer startTime; + startTime.start(); Generator::computeStarPositions(_inputSequence, numStars, seed); this->retile(numStars, _tileResolution); - qDebug() << "Total time to retile and generate stars: " - << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << "msec"; + double timeDiff = (double)startTime.nsecsElapsed() / 1000000.0; // ns to ms + qDebug() << "Total time to retile and generate stars: " << timeDiff << "msec"; return true; } diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp index b18e1834be..869abc90a5 100644 --- a/interface/src/starfield/Generator.cpp +++ b/interface/src/starfield/Generator.cpp @@ -13,6 +13,8 @@ #include #endif +#include + #include "starfield/Generator.h" using namespace starfield; @@ -24,8 +26,8 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit, InputVertices* vertices = & destination; //_limit = limit; - timeval startTime; - gettimeofday(&startTime, NULL); + QElapsedTimer startTime; + startTime.start(); srand(seed); @@ -70,7 +72,8 @@ void Generator::computeStarPositions(InputVertices& destination, unsigned limit, vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION))); } - qDebug() << "Total time to generate stars: " << ((usecTimestampNow() - usecTimestamp(&startTime)) / 1000) << " msec"; + double timeDiff = (double)startTime.nsecsElapsed() / 1000000.0; // ns to ms + qDebug() << "Total time to generate stars: " << timeDiff << " msec"; } // computeStarColor diff --git a/interface/src/ui/BandwidthMeter.cpp b/interface/src/ui/BandwidthMeter.cpp index 3ed66c53e1..0f41a1a5cf 100644 --- a/interface/src/ui/BandwidthMeter.cpp +++ b/interface/src/ui/BandwidthMeter.cpp @@ -62,26 +62,21 @@ BandwidthMeter::~BandwidthMeter() { free(_channels); } -BandwidthMeter::Stream::Stream(float msToAverage) : - _value(0.0f), - _msToAverage(msToAverage) { - - gettimeofday(& _prevTime, NULL); +BandwidthMeter::Stream::Stream(float msToAverage) : _value(0.0f), _msToAverage(msToAverage) { + _prevTime.start(); } void BandwidthMeter::Stream::updateValue(double amount) { // Determine elapsed time - timeval now; - gettimeofday(& now, NULL); - double dt = diffclock(& _prevTime, & now); + double dt = (double)_prevTime.nsecsElapsed() / 1000000.0; // ns to ms // Ignore this value when timer imprecision yields dt = 0 if (dt == 0.0) { return; } - memcpy(& _prevTime, & now, sizeof(timeval)); + _prevTime.start(); // Compute approximate average _value = glm::mix(_value, amount / dt, diff --git a/interface/src/ui/BandwidthMeter.h b/interface/src/ui/BandwidthMeter.h index 6838f28c70..6cf7e9ea63 100644 --- a/interface/src/ui/BandwidthMeter.h +++ b/interface/src/ui/BandwidthMeter.h @@ -16,6 +16,8 @@ #include #endif +#include + #include #include "ui/TextRenderer.h" @@ -59,7 +61,7 @@ public: private: double _value; // Current value. double _msToAverage; // Milliseconds to average. - timeval _prevTime; // Time of last feed. + QElapsedTimer _prevTime; // Time of last feed. }; // Data model accessors diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 684c55fbb0..dcf64dfe2c 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -273,8 +273,8 @@ void ScriptEngine::run() { qDebug() << "Uncaught exception at line" << line << ":" << result.toString(); } - timeval startTime; - gettimeofday(&startTime, NULL); + QElapsedTimer startTime; + startTime.start(); int thisFrame = 0; @@ -283,7 +283,7 @@ void ScriptEngine::run() { qint64 lastUpdate = usecTimestampNow(); while (!_isFinished) { - int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - usecTimestampNow(); + int usecToSleep = (thisFrame++ * SCRIPT_DATA_CALLBACK_USECS) - startTime.nsecsElapsed() / 1000; // nsec to usec if (usecToSleep > 0) { usleep(usecToSleep); } diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index f4e4b28f93..dca9426cb4 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -24,10 +24,6 @@ #include "OctalCode.h" #include "SharedUtil.h" -quint64 usecTimestamp(const timeval *time) { - return (time->tv_sec * 1000000 + time->tv_usec); -} - int usecTimestampNowAdjust = 0; void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index a8403d617c..87647a9e73 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -66,7 +66,6 @@ static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; const int BITS_IN_BYTE = 8; -quint64 usecTimestamp(const timeval *time); quint64 usecTimestampNow(); void usecTimestampNowForceClockSkew(int clockSkew); diff --git a/libraries/shared/src/Systime.cpp b/libraries/shared/src/Systime.cpp deleted file mode 100644 index ab32821a0f..0000000000 --- a/libraries/shared/src/Systime.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// -// Systime.cpp -// libraries/shared/src -// -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifdef WIN32 - -#include "Systime.h" - -/** - * gettimeofday - * Implementation according to: - * The Open Group Base Specifications Issue 6 - * IEEE Std 1003.1, 2004 Edition - */ - -/** - * THIS SOFTWARE IS NOT COPYRIGHTED - * - * This source code is offered for use in the public domain. You may - * use, modify or distribute it freely. - * - * This code is distributed in the hope that it will be useful but - * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY - * DISCLAIMED. This includes but is not limited to warranties of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Contributed by: - * Danny Smith - */ - -#define WIN32_LEAN_AND_MEAN -#include - -/** Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */ -#define _W32_FT_OFFSET (116444736000000000ULL) - -int gettimeofday(timeval* p_tv, timezone* p_tz) { - - union { - unsigned long long ns100; /**time since 1 Jan 1601 in 100ns units */ - FILETIME ft; - } _now; - - if (p_tv) { - GetSystemTimeAsFileTime (&_now.ft); - p_tv->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL ); - p_tv->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL); - } - - /** Always return 0 as per Open Group Base Specifications Issue 6. - Do not set errno on error. */ - return 0; -} - -#endif \ No newline at end of file diff --git a/libraries/shared/src/Systime.h b/libraries/shared/src/Systime.h deleted file mode 100644 index 3098f09ecd..0000000000 --- a/libraries/shared/src/Systime.h +++ /dev/null @@ -1,27 +0,0 @@ -// -// Systime.h -// libraries/shared/src -// -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_Systime_h -#define hifi_Systime_h - -#ifdef WIN32 - -#include - -struct timezone { - int tz_minuteswest; /* minutes west of Greenwich */ - int tz_dsttime; /* type of dst correction */ -}; - -int gettimeofday(struct timeval* p_tv, struct timezone* p_tz); - -#endif - -#endif // hifi_Systime_h \ No newline at end of file From 0479aaba4651594b760979f0ed460665234d7f1e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 21 Apr 2014 15:26:43 -0700 Subject: [PATCH 29/68] Some gettimeofday removal fixes --- interface/src/Application.cpp | 2 +- interface/src/Util.cpp | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 92c63dacf3..b13013cbe2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -507,7 +507,7 @@ void Application::initializeGL() { _idleLoopStdev.reset(); if (_justStarted) { - float startupTime = _applicationStartupTime.elapsed() / 1000.0; + float startupTime = (float)_applicationStartupTime.elapsed() / 1000.0; _justStarted = false; qDebug("Startup time: %4.2f seconds.", startupTime); const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 9dfe9d8002..7913ff2f47 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -405,26 +405,26 @@ void runTimingTests() { float fResults[numTests]; QElapsedTimer startTime; startTime.start(); - float elapsedMsecs; + float elapsedUsecs; - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("QElapsedTimer::nsecElapsed() usecs: %f", 1000.0f * elapsedMsecs / (float) numTests); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("QElapsedTimer::nsecElapsed() usecs: %f", 1000.0f * elapsedUsecs / (float) numTests); // Random number generation startTime.start(); for (int i = 1; i < numTests; i++) { iResults[i] = rand(); } - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("rand() stored in array usecs: %f, first result:%d", 1000.0f * elapsedMsecs / (float) numTests, iResults[0]); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("rand() stored in array usecs: %f, first result:%d", 1000.0f * elapsedUsecs / (float) numTests, iResults[0]); // Random number generation using randFloat() startTime.start(); for (int i = 1; i < numTests; i++) { fResults[i] = randFloat(); } - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("randFloat() stored in array usecs: %f, first result: %f", 1000.0f * elapsedMsecs / (float) numTests, fResults[0]); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("randFloat() stored in array usecs: %f, first result: %f", 1000.0f * elapsedUsecs / (float) numTests, fResults[0]); // PowF function fTest = 1145323.2342f; @@ -432,8 +432,8 @@ void runTimingTests() { for (int i = 1; i < numTests; i++) { fTest = powf(fTest, 0.5f); } - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedMsecs / (float) numTests); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedUsecs / (float) numTests); // Vector Math float distance; @@ -444,9 +444,9 @@ void runTimingTests() { //float distanceSquared = glm::dot(temp, temp); distance = glm::distance(pointA, pointB); } - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("vector math usecs: %f [%f msecs total for %d tests], last result:%f", - 1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests, distance); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("vector math usecs: %f [%f usecs total for %d tests], last result:%f", + 1000.0f * elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance); // Vec3 test glm::vec3 vecA(randVector()), vecB(randVector()); @@ -457,8 +457,8 @@ void runTimingTests() { glm::vec3 temp = vecA-vecB; result = glm::dot(temp,temp); } - elapsedMsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("vec3 assign and dot() usecs: %f, last result:%f", 1000.0f * elapsedMsecs / (float) numTests, result); + elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + qDebug("vec3 assign and dot() usecs: %f, last result:%f", 1000.0f * elapsedUsecs / (float) numTests, result); } float loadSetting(QSettings* settings, const char* name, float defaultValue) { From be2db49e08be2fa49faed4d0f62b3106b226d4cd Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 21 Apr 2014 16:44:21 -0700 Subject: [PATCH 30/68] Last touch to removing gettimeofday --- libraries/shared/src/SharedUtil.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index dca9426cb4..a13772d862 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -20,6 +20,7 @@ #endif #include +#include #include "OctalCode.h" #include "SharedUtil.h" @@ -30,9 +31,8 @@ void usecTimestampNowForceClockSkew(int clockSkew) { } quint64 usecTimestampNow() { - timeval now; - gettimeofday(&now, NULL); - return (now.tv_sec * 1000000 + now.tv_usec) + ::usecTimestampNowAdjust; + qint64 msecSinceEpoch = QDateTime::currentMSecsSinceEpoch(); + return msecSinceEpoch * 1000 + ::usecTimestampNowAdjust; } float randFloat() { From fd20686f0f854a33d897c5973535fd57c2e1fd60 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 21 Apr 2014 17:23:06 -0700 Subject: [PATCH 31/68] Removed Systime.h includes --- assignment-client/src/audio/AudioMixer.cpp | 2 -- interface/src/Application.cpp | 4 ---- interface/src/Audio.h | 4 ---- interface/src/Util.h | 6 ------ interface/src/devices/OculusManager.cpp | 4 ---- interface/src/devices/TV3DManager.cpp | 5 ----- interface/src/starfield/Controller.cpp | 4 ---- interface/src/starfield/Generator.cpp | 4 ---- interface/src/ui/BandwidthMeter.h | 4 ---- libraries/networking/src/Assignment.h | 6 ------ libraries/shared/src/PerfStat.h | 6 ------ libraries/shared/src/SharedUtil.h | 6 ------ 12 files changed, 55 deletions(-) diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index 65d09f1b00..5fd9efedd7 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -21,12 +21,10 @@ #include #ifdef _WIN32 -#include "Systime.h" #include #else #include #include -#include #include #endif //_WIN32 diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b13013cbe2..1e3d3a2259 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -9,10 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef WIN32 -#include -#endif - #include #include diff --git a/interface/src/Audio.h b/interface/src/Audio.h index f8315b1aab..7ad1ddd926 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -12,10 +12,6 @@ #ifndef hifi_Audio_h #define hifi_Audio_h -#ifdef _WIN32 -#include -#endif - #include #include diff --git a/interface/src/Util.h b/interface/src/Util.h index dee0f864b4..02cfd99f9a 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -12,12 +12,6 @@ #ifndef hifi_Util_h #define hifi_Util_h -#ifdef _WIN32 -#include "Systime.h" -#else -#include -#endif - #include #include #include diff --git a/interface/src/devices/OculusManager.cpp b/interface/src/devices/OculusManager.cpp index d3da8fe7c3..854b19236d 100644 --- a/interface/src/devices/OculusManager.cpp +++ b/interface/src/devices/OculusManager.cpp @@ -11,10 +11,6 @@ #include "InterfaceConfig.h" -#ifdef WIN32 -#include -#endif - #include #include diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index fcbef0385c..b5cc28b07f 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -15,11 +15,6 @@ #include - -#ifdef WIN32 -#include -#endif - #include "Application.h" #include "TV3DManager.h" diff --git a/interface/src/starfield/Controller.cpp b/interface/src/starfield/Controller.cpp index 2476c33d45..e68243752c 100755 --- a/interface/src/starfield/Controller.cpp +++ b/interface/src/starfield/Controller.cpp @@ -9,10 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef _WIN32 -#include -#endif - #include #include "starfield/Controller.h" diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp index 869abc90a5..d9773e4452 100644 --- a/interface/src/starfield/Generator.cpp +++ b/interface/src/starfield/Generator.cpp @@ -9,10 +9,6 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#ifdef _WIN32 -#include -#endif - #include #include "starfield/Generator.h" diff --git a/interface/src/ui/BandwidthMeter.h b/interface/src/ui/BandwidthMeter.h index 6cf7e9ea63..c6a28a21c3 100644 --- a/interface/src/ui/BandwidthMeter.h +++ b/interface/src/ui/BandwidthMeter.h @@ -12,10 +12,6 @@ #ifndef hifi_BandwidthMeter_h #define hifi_BandwidthMeter_h -#ifdef _WIN32 -#include -#endif - #include #include diff --git a/libraries/networking/src/Assignment.h b/libraries/networking/src/Assignment.h index 041121f760..f0f7e8db1a 100644 --- a/libraries/networking/src/Assignment.h +++ b/libraries/networking/src/Assignment.h @@ -12,12 +12,6 @@ #ifndef hifi_Assignment_h #define hifi_Assignment_h -#ifdef _WIN32 -#include "Systime.h" -#else -#include -#endif - #include #include "NodeList.h" diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index 478c9afead..22cf14f207 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -18,12 +18,6 @@ #include #include "SharedUtil.h" -#ifdef _WIN32 -#include "Systime.h" -#else -#include -#endif - #include #include #include diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 87647a9e73..4a3fe2a129 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -24,12 +24,6 @@ #include -#ifdef _WIN32 -#include "Systime.h" -#else -#include -#endif - const int BYTES_PER_COLOR = 3; const int BYTES_PER_FLAGS = 1; typedef unsigned char rgbColor[BYTES_PER_COLOR]; From 3eeb3a539dda788907121e1f32a5e9dc6883e242 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 22 Apr 2014 11:48:43 -0700 Subject: [PATCH 32/68] Fixed lack of resolution in usecTimestampNow() --- assignment-client/src/main.cpp | 1 + domain-server/src/main.cpp | 2 ++ interface/src/main.cpp | 1 + libraries/shared/src/SharedUtil.cpp | 22 +++++++++++++++++++--- libraries/shared/src/SharedUtil.h | 1 + 5 files changed, 24 insertions(+), 3 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 24d19ddef6..7132b5c38a 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -17,6 +17,7 @@ #include "AssignmentClientMonitor.h" int main(int argc, char* argv[]) { + initialiseUsecTimestampNow(); #ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index bdb10cb56f..871c16a215 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -18,10 +18,12 @@ #include #include +#include #include "DomainServer.h" int main(int argc, char* argv[]) { + initialiseUsecTimestampNow(); #ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 2bb0633f24..6f9dc5e3bd 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -16,6 +16,7 @@ #include int main(int argc, const char * argv[]) { + initialiseUsecTimestampNow(); QElapsedTimer startupTime; startupTime.start(); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index a13772d862..78ef997c35 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -21,18 +21,34 @@ #include #include +#include #include "OctalCode.h" #include "SharedUtil.h" -int usecTimestampNowAdjust = 0; + +static qint64 TIME_REFERENCE = 0; // in usec +static QElapsedTimer timestampTimer; +static int usecTimestampNowAdjust = 0; // in usec + +void initialiseUsecTimestampNow() { + static bool initialised = false; + if (initialised) { + qDebug() << "[WARNING] Double initialisation of usecTimestampNow()."; + return; + } + + TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec + initialised = true; +} + void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; } quint64 usecTimestampNow() { - qint64 msecSinceEpoch = QDateTime::currentMSecsSinceEpoch(); - return msecSinceEpoch * 1000 + ::usecTimestampNowAdjust; + // usec nsec to usec usec + return TIME_REFERENCE + timestampTimer.nsecsElapsed() / 1000 + ::usecTimestampNowAdjust; } float randFloat() { diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 4a3fe2a129..54d599070d 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -60,6 +60,7 @@ static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; const int BITS_IN_BYTE = 8; +void initialiseUsecTimestampNow(); quint64 usecTimestampNow(); void usecTimestampNowForceClockSkew(int clockSkew); From fea0a262a67f6316de8e32f418e413eaa0a54675 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 22 Apr 2014 12:35:50 -0700 Subject: [PATCH 33/68] Put back missing windows header --- libraries/shared/src/SharedUtil.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 78ef997c35..b865d9c717 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -15,6 +15,10 @@ #include #include +#ifdef _WIN32 +#include +#endif + #ifdef __APPLE__ #include #endif From 378afdf117fb2617232b636311b34dcd27a3e2d9 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Apr 2014 10:35:24 -0700 Subject: [PATCH 34/68] More undo work --- libraries/voxels/src/VoxelTree.cpp | 2 +- libraries/voxels/src/VoxelTreeCommands.cpp | 26 ++++------------------ 2 files changed, 5 insertions(+), 23 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index bb9de72e9d..3a77382a84 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -42,7 +42,7 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s) { } VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) const { - return (VoxelTreeElement*)getOctreeElementAt(x, y, z, s); + return static_cast(getOctreeElementAt(x, y, z, s)); } void VoxelTree::createVoxel(float x, float y, float z, float s, diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index 75b38667ec..46837aa23e 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -22,27 +22,8 @@ AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditP { VoxelTreeElement* element = _tree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); if (element) { - if (element->hasContent() && element->isLeaf()) { - // Do nothing, everything is in order - } else { - _oldTree = new VoxelTree(); - _tree->copySubTreeIntoNewTree(element, _oldTree, true); - } - } else { - glm::vec3 point(_voxel.x + _voxel.s / 2.0f, - _voxel.y + _voxel.s / 2.0f, - _voxel.z + _voxel.s / 2.0f); - OctreeElement* element = _tree->getElementEnclosingPoint(point, Octree::Lock); - if (element) { - VoxelTreeElement* node = static_cast(element); - _voxel.x = node->getCorner().x; - _voxel.y = node->getCorner().y; - _voxel.z = node->getCorner().z; - _voxel.s = node->getScale(); - _voxel.red = node->getColor()[0]; - _voxel.green = node->getColor()[1]; - _voxel.blue = node->getColor()[2]; - } + _oldTree = new VoxelTree(); + _tree->copySubTreeIntoNewTree(element, _oldTree, true); } } @@ -62,8 +43,9 @@ void AddVoxelCommand::redo() { void AddVoxelCommand::undo() { if (_oldTree) { OctreeElement* element = _tree->getOrCreateChildElementAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - qDebug() << _voxel.x << " " << _voxel.y << " " << _voxel.z << " " << _voxel.s; + qDebug() << "undo(): " << _voxel.x << " " << _voxel.y << " " << _voxel.z << " " << _voxel.s; _tree->copyFromTreeIntoSubTree(_oldTree, element); + qDebug() << "done"; } else { if (_tree) { _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); From f7bc1ae62c310de94375629d63bce7cbad257561 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 10:47:24 -0700 Subject: [PATCH 35/68] Working on integrating rotation into IK. --- interface/src/avatar/SkeletonModel.cpp | 25 +++++------------- interface/src/renderer/Model.cpp | 36 +++++++++++++++++--------- interface/src/renderer/Model.h | 5 ++-- 3 files changed, 34 insertions(+), 32 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 1c6a568754..6581bc1841 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -148,17 +148,12 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; - int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; - if (parentJointIndex == -1) { - return; - } - // rotate forearm to align with palm direction + // rotate palm to align with palm direction glm::quat palmRotation; - getJointRotation(parentJointIndex, palmRotation, true); - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()), true, true); - getJointRotation(parentJointIndex, palmRotation, true); - + getJointRotation(jointIndex, palmRotation, true); + palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; + // sort the finger indices by raw x, get the average direction QVector fingerIndices; glm::vec3 direction; @@ -178,18 +173,12 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin float directionLength = glm::length(direction); const unsigned int MIN_ROTATION_FINGERS = 3; if (directionLength > EPSILON && palm.getNumFingers() >= MIN_ROTATION_FINGERS) { - applyRotationDelta(parentJointIndex, rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction), - true, true); - getJointRotation(parentJointIndex, palmRotation, true); + palmRotation = rotationBetween(palmRotation * glm::vec3(-sign, 0.0f, 0.0f), direction) * palmRotation; } - // let wrist inherit forearm rotation - _jointStates[jointIndex].rotation = glm::quat(); - - // set elbow position from wrist position + // set hand position, rotation glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); + setJointPosition(jointIndex, palm.getPosition(), palmRotation); } void SkeletonModel::updateJointState(int index) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index b373ffa545..9aa5bd8227 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -882,12 +882,12 @@ bool Model::getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind) return true; } -bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex, - bool allIntermediatesFree, const glm::vec3& alignment) { +bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation, bool useRotation, + int lastFreeIndex, bool allIntermediatesFree, const glm::vec3& alignment) { if (jointIndex == -1 || _jointStates.isEmpty()) { return false; } - glm::vec3 relativePosition = position - _translation; + glm::vec3 relativePosition = translation - _translation; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const QVector& freeLineage = geometry.joints.at(jointIndex).freeLineage; if (freeLineage.isEmpty()) { @@ -897,17 +897,20 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last lastFreeIndex = freeLineage.last(); } - // now update the joint states from the top - for (int j = freeLineage.size() - 1; j >= 0; j--) { - updateJointState(freeLineage.at(j)); - } - // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; glm::vec3 worldAlignment = _rotation * alignment; for (int i = 0; i < ITERATION_COUNT; i++) { - // first, we go from the joint upwards, rotating the end as close as possible to the target + // first, try to rotate the end effector as close as possible to the target rotation, if any + glm::quat endRotation; + if (useRotation) { + getJointRotation(jointIndex, endRotation, true); + applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); + getJointRotation(jointIndex, endRotation, true); + } + + // then, we go from the joint upwards, rotating the end as close as possible to the target glm::vec3 endPosition = extractTranslation(_jointStates[jointIndex].transform); for (int j = 1; freeLineage.at(j - 1) != lastFreeIndex; j++) { int index = freeLineage.at(j); @@ -919,8 +922,17 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& position, int last glm::vec3 jointPosition = extractTranslation(state.transform); glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; - applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); - endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + if (useRotation) { + applyRotationDelta(index, safeMix(rotationBetween(jointVector, relativePosition - jointPosition), + rotation * glm::inverse(endRotation), 0.5f)); + glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); + endRotation = actualDelta * endRotation; + endPosition = actualDelta * jointVector + jointPosition; + + } else { + applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); + endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + } if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -1154,7 +1166,7 @@ void Model::applyCollision(CollisionInfo& collision) { getJointPosition(jointIndex, end); glm::vec3 newEnd = start + glm::angleAxis(angle, axis) * (end - start); // try to move it - setJointPosition(jointIndex, newEnd, -1, true); + setJointPosition(jointIndex, newEnd, glm::quat(), false, -1, true); } } } diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index b472e17b20..10e9e2a66a 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -240,8 +240,9 @@ protected: bool getJointPosition(int jointIndex, glm::vec3& position) const; bool getJointRotation(int jointIndex, glm::quat& rotation, bool fromBind = false) const; - bool setJointPosition(int jointIndex, const glm::vec3& position, int lastFreeIndex = -1, - bool allIntermediatesFree = false, const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); + bool setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat& rotation = glm::quat(), + bool useRotation = false, int lastFreeIndex = -1, bool allIntermediatesFree = false, + const glm::vec3& alignment = glm::vec3(0.0f, -1.0f, 0.0f)); bool setJointRotation(int jointIndex, const glm::quat& rotation, bool fromBind = false); void setJointTranslation(int jointIndex, const glm::vec3& translation); From 9bea70ac54d3a11fd76bf7e77a30556993f86973 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 10:49:22 -0700 Subject: [PATCH 36/68] Revert "Add emoticons to chat" This reverts commit 3c9b6264a8354f514324f6a97992a67b01ad924a. --- interface/resources/images/cool.svg | 8 -------- interface/resources/images/grin.svg | 8 -------- interface/resources/images/happy.svg | 8 -------- interface/resources/images/sad.svg | 8 -------- interface/resources/images/smiley.svg | 8 -------- interface/resources/images/tongue.svg | 8 -------- interface/resources/images/wink.svg | 8 -------- interface/src/ui/ChatWindow.cpp | 19 +------------------ interface/src/ui/ChatWindow.h | 1 - 9 files changed, 1 insertion(+), 75 deletions(-) delete mode 100644 interface/resources/images/cool.svg delete mode 100644 interface/resources/images/grin.svg delete mode 100644 interface/resources/images/happy.svg delete mode 100644 interface/resources/images/sad.svg delete mode 100644 interface/resources/images/smiley.svg delete mode 100644 interface/resources/images/tongue.svg delete mode 100644 interface/resources/images/wink.svg diff --git a/interface/resources/images/cool.svg b/interface/resources/images/cool.svg deleted file mode 100644 index 2e8348108a..0000000000 --- a/interface/resources/images/cool.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/grin.svg b/interface/resources/images/grin.svg deleted file mode 100644 index 8e36a16555..0000000000 --- a/interface/resources/images/grin.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/happy.svg b/interface/resources/images/happy.svg deleted file mode 100644 index fe31d01991..0000000000 --- a/interface/resources/images/happy.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/sad.svg b/interface/resources/images/sad.svg deleted file mode 100644 index 0029bfded5..0000000000 --- a/interface/resources/images/sad.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/smiley.svg b/interface/resources/images/smiley.svg deleted file mode 100644 index 1b0e707bf6..0000000000 --- a/interface/resources/images/smiley.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/tongue.svg b/interface/resources/images/tongue.svg deleted file mode 100644 index 35361d2b2b..0000000000 --- a/interface/resources/images/tongue.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/resources/images/wink.svg b/interface/resources/images/wink.svg deleted file mode 100644 index b1aef4823d..0000000000 --- a/interface/resources/images/wink.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index 06608ef5e4..c459a6d426 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -31,14 +31,12 @@ const int NUM_MESSAGES_TO_TIME_STAMP = 20; const QRegularExpression regexLinks("((?:(?:ftp)|(?:https?))://\\S+)"); const QRegularExpression regexHifiLinks("([#@]\\S+)"); - ChatWindow::ChatWindow(QWidget* parent) : FramelessDialog(parent, 0, POSITION_RIGHT), ui(new Ui::ChatWindow), numMessagesAfterLastTimeStamp(0), _mousePressed(false), - _mouseStartPosition(), - _emoticonMap() + _mouseStartPosition() { setAttribute(Qt::WA_DeleteOnClose, false); @@ -65,14 +63,6 @@ ChatWindow::ChatWindow(QWidget* parent) : ui->connectingToXMPPLabel->setText(tr("You must be logged in to chat with others.")); } - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":)")), new QString("../resources/images/smiley.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":D")), new QString("../resources/images/happy.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape("B)")), new QString("../resources/images/cool.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":O")), new QString("../resources/images/grin.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":(")), new QString("../resources/images/sad.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(":P")), new QString("../resources/images/tongue.svg")); - _emoticonMap.insert(new QRegularExpression(QRegExp::escape(";)")), new QString("../resources/images/wink.svg")); - #ifdef HAVE_QXMPP const QXmppClient& xmppClient = XmppClient::getInstance().getXMPPClient(); if (xmppClient.isConnected()) { @@ -294,13 +284,6 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { QString messageText = message.body().toHtmlEscaped(); messageText = messageText.replace(regexLinks, "\\1"); messageText = messageText.replace(regexHifiLinks, "\\1"); - - QMapIterator it(_emoticonMap); - while (it.hasNext()) { - it.next(); - messageText.replace(*it.key(), ""); - } - messageArea->setHtml(userLabel + messageText); bool atBottom = isAtBottom(); diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 3dce35b1b2..399c9e917c 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -57,7 +57,6 @@ private: QDateTime lastMessageStamp; bool _mousePressed; QPoint _mouseStartPosition; - QMap _emoticonMap; private slots: void connected(); From ceb5208102f6d5ea8c2a5a5909c966b2c8ac5a77 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Apr 2014 11:00:44 -0700 Subject: [PATCH 37/68] CR --- interface/src/Application.cpp | 5 ++--- interface/src/Util.cpp | 25 +++++++++++++------------ interface/src/starfield/Controller.cpp | 3 ++- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index bfbc88a666..265ff2e7a1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1218,8 +1218,7 @@ void Application::touchEndEvent(QTouchEvent* event) { if (_controllerScriptingInterface.isTouchCaptured()) { return; } - - // put any application specific touch behavior below here.. +s // put any application specific touch behavior below here.. _touchDragStartedAvgX = _touchAvgX; _touchDragStartedAvgY = _touchAvgY; _isTouchPressed = false; @@ -1276,7 +1275,7 @@ void Application::timer() { sendPingPackets(); } - float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0; + float diffTime = (float)_timerStart.nsecsElapsed() / 1000000000.0f; _fps = (float)_frameCount / diffTime; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 16dd35f316..79a2e31d80 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -407,24 +407,25 @@ void runTimingTests() { startTime.start(); float elapsedUsecs; - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("QElapsedTimer::nsecElapsed() usecs: %f", 1000.0f * elapsedUsecs / (float) numTests); + float NSEC_TO_USEC = 1.0f / 1000.0f; + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("QElapsedTimer::nsecElapsed() usecs: %f", elapsedUsecs / (float) numTests); // Random number generation startTime.start(); for (int i = 1; i < numTests; i++) { iResults[i] = rand(); } - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("rand() stored in array usecs: %f, first result:%d", 1000.0f * elapsedUsecs / (float) numTests, iResults[0]); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("rand() stored in array usecs: %f, first result:%d", elapsedUsecs / (float) numTests, iResults[0]); // Random number generation using randFloat() startTime.start(); for (int i = 1; i < numTests; i++) { fResults[i] = randFloat(); } - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("randFloat() stored in array usecs: %f, first result: %f", 1000.0f * elapsedUsecs / (float) numTests, fResults[0]); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("randFloat() stored in array usecs: %f, first result: %f", elapsedUsecs / (float) numTests, fResults[0]); // PowF function fTest = 1145323.2342f; @@ -432,8 +433,8 @@ void runTimingTests() { for (int i = 1; i < numTests; i++) { fTest = powf(fTest, 0.5f); } - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("powf(f, 0.5) usecs: %f", 1000.0f * elapsedUsecs / (float) numTests); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("powf(f, 0.5) usecs: %f", elapsedUsecs / (float) numTests); // Vector Math float distance; @@ -444,9 +445,9 @@ void runTimingTests() { //float distanceSquared = glm::dot(temp, temp); distance = glm::distance(pointA, pointB); } - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; qDebug("vector math usecs: %f [%f usecs total for %d tests], last result:%f", - 1000.0f * elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance); + elapsedUsecs / (float) numTests, elapsedUsecs, numTests, distance); // Vec3 test glm::vec3 vecA(randVector()), vecB(randVector()); @@ -457,8 +458,8 @@ void runTimingTests() { glm::vec3 temp = vecA-vecB; result = glm::dot(temp,temp); } - elapsedUsecs = (float)startTime.nsecsElapsed() / 1000.0; - qDebug("vec3 assign and dot() usecs: %f, last result:%f", 1000.0f * elapsedUsecs / (float) numTests, result); + elapsedUsecs = (float)startTime.nsecsElapsed() * NSEC_TO_USEC; + qDebug("vec3 assign and dot() usecs: %f, last result:%f", elapsedUsecs / (float) numTests, result); } float loadSetting(QSettings* settings, const char* name, float defaultValue) { diff --git a/interface/src/starfield/Controller.cpp b/interface/src/starfield/Controller.cpp index e68243752c..2279a68422 100755 --- a/interface/src/starfield/Controller.cpp +++ b/interface/src/starfield/Controller.cpp @@ -23,7 +23,8 @@ bool Controller::computeStars(unsigned numStars, unsigned seed) { this->retile(numStars, _tileResolution); - double timeDiff = (double)startTime.nsecsElapsed() / 1000000.0; // ns to ms + double NSEC_TO_MSEC = 1.0 / 1000000.0; + double timeDiff = (double)startTime.nsecsElapsed() * NSEC_TO_MSEC; qDebug() << "Total time to retile and generate stars: " << timeDiff << "msec"; return true; From f68d2d16a83449fb6a61c6cb19bf3453ffb8bdc3 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 23 Apr 2014 11:05:16 -0700 Subject: [PATCH 38/68] Inserted a char by mistake --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 265ff2e7a1..4adb2f772a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1218,7 +1218,7 @@ void Application::touchEndEvent(QTouchEvent* event) { if (_controllerScriptingInterface.isTouchCaptured()) { return; } -s // put any application specific touch behavior below here.. + // put any application specific touch behavior below here.. _touchDragStartedAvgX = _touchAvgX; _touchDragStartedAvgY = _touchAvgY; _isTouchPressed = false; From 511fc8367f425eb0c6c9f4f55221cf0747555d7b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:34:34 -0700 Subject: [PATCH 39/68] More work on IK. --- interface/src/avatar/SkeletonModel.cpp | 3 +-- interface/src/renderer/Model.cpp | 26 +++++++++++++++----------- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 6581bc1841..f52858b4ff 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -177,8 +177,7 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } // set hand position, rotation - glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); - setJointPosition(jointIndex, palm.getPosition(), palmRotation); + setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); } void SkeletonModel::updateJointState(int index) { diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9aa5bd8227..77d9743cd5 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -896,6 +896,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } + float baseWeight = 1.0f / (freeLineage.indexOf(lastFreeIndex) + (useRotation ? 1 : 0)); // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d @@ -906,7 +907,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat endRotation; if (useRotation) { getJointRotation(jointIndex, endRotation, true); - applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); + applyRotationDelta(jointIndex, safeMix(glm::quat(), rotation * glm::inverse(endRotation), baseWeight)); getJointRotation(jointIndex, endRotation, true); } @@ -922,17 +923,13 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 jointPosition = extractTranslation(state.transform); glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; + glm::quat combinedDelta; + float combinedWeight = 0.0f; if (useRotation) { - applyRotationDelta(index, safeMix(rotationBetween(jointVector, relativePosition - jointPosition), - rotation * glm::inverse(endRotation), 0.5f)); - glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); - endRotation = actualDelta * endRotation; - endPosition = actualDelta * jointVector + jointPosition; - - } else { - applyRotationDelta(index, rotationBetween(jointVector, relativePosition - jointPosition)); - endPosition = state.combinedRotation * glm::inverse(oldCombinedRotation) * jointVector + jointPosition; + combinedDelta = safeMix(combinedDelta, rotation * glm::inverse(endRotation), baseWeight / (combinedWeight += 1.0f)); } + combinedDelta = safeMix(combinedDelta, rotationBetween(jointVector, relativePosition - jointPosition), + baseWeight / (combinedWeight += 1.0f)); if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -946,9 +943,16 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 projectedAlignment = glm::cross(jointVector, glm::cross(worldAlignment, jointVector)); const float LENGTH_EPSILON = 0.001f; if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { - applyRotationDelta(index, rotationBetween(projectedCenterOfMass, projectedAlignment)); + combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), + baseWeight / (combinedWeight += 1.0f)); } } + applyRotationDelta(index, combinedDelta); + glm::quat actualDelta = state.combinedRotation * glm::inverse(oldCombinedRotation); + endPosition = actualDelta * jointVector + jointPosition; + if (useRotation) { + endRotation = actualDelta * endRotation; + } } } From 523498ee5b918b4cbc5a0930522fddd09dc51274 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:52:22 -0700 Subject: [PATCH 40/68] Revert to using weight that doesn't depend on number of free joints. --- interface/src/renderer/Model.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 77d9743cd5..143b6a8109 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -896,8 +896,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const if (lastFreeIndex == -1) { lastFreeIndex = freeLineage.last(); } - float baseWeight = 1.0f / (freeLineage.indexOf(lastFreeIndex) + (useRotation ? 1 : 0)); - + // this is a cyclic coordinate descent algorithm: see // http://www.ryanjuckett.com/programming/animation/21-cyclic-coordinate-descent-in-2d const int ITERATION_COUNT = 1; @@ -907,7 +906,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat endRotation; if (useRotation) { getJointRotation(jointIndex, endRotation, true); - applyRotationDelta(jointIndex, safeMix(glm::quat(), rotation * glm::inverse(endRotation), baseWeight)); + applyRotationDelta(jointIndex, rotation * glm::inverse(endRotation)); getJointRotation(jointIndex, endRotation, true); } @@ -924,12 +923,15 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::vec3 jointVector = endPosition - jointPosition; glm::quat oldCombinedRotation = state.combinedRotation; glm::quat combinedDelta; - float combinedWeight = 0.0f; + float combinedWeight; if (useRotation) { - combinedDelta = safeMix(combinedDelta, rotation * glm::inverse(endRotation), baseWeight / (combinedWeight += 1.0f)); + combinedDelta = rotation * glm::inverse(endRotation); + combinedWeight = 1.0f; + } else { + combinedDelta = safeMix(rotation * glm::inverse(endRotation), + rotationBetween(jointVector, relativePosition - jointPosition), 0.5f); + combinedWeight = 2.0f; } - combinedDelta = safeMix(combinedDelta, rotationBetween(jointVector, relativePosition - jointPosition), - baseWeight / (combinedWeight += 1.0f)); if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; glm::vec3 positionSum; @@ -944,7 +946,7 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const const float LENGTH_EPSILON = 0.001f; if (glm::length(projectedCenterOfMass) > LENGTH_EPSILON && glm::length(projectedAlignment) > LENGTH_EPSILON) { combinedDelta = safeMix(combinedDelta, rotationBetween(projectedCenterOfMass, projectedAlignment), - baseWeight / (combinedWeight += 1.0f)); + 1.0f / (combinedWeight + 1.0f)); } } applyRotationDelta(index, combinedDelta); From 09bb51261a14b471804611403c9228a56880de7d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 11:55:16 -0700 Subject: [PATCH 41/68] Got that backwards. --- interface/src/renderer/Model.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 143b6a8109..26e59635bb 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -925,12 +925,13 @@ bool Model::setJointPosition(int jointIndex, const glm::vec3& translation, const glm::quat combinedDelta; float combinedWeight; if (useRotation) { - combinedDelta = rotation * glm::inverse(endRotation); - combinedWeight = 1.0f; - } else { combinedDelta = safeMix(rotation * glm::inverse(endRotation), rotationBetween(jointVector, relativePosition - jointPosition), 0.5f); combinedWeight = 2.0f; + + } else { + combinedDelta = rotationBetween(jointVector, relativePosition - jointPosition); + combinedWeight = 1.0f; } if (alignment != glm::vec3() && j > 1) { jointVector = endPosition - jointPosition; From 951d5004e121947b4379ccd951368a5b85046d48 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 11:57:43 -0700 Subject: [PATCH 42/68] Add ChatInputArea with custom paste --- interface/src/ui/ChatMessageArea.h | 4 ++++ interface/ui/chatWindow.ui | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ChatMessageArea.h b/interface/src/ui/ChatMessageArea.h index 48cfc01aec..b726a31d76 100644 --- a/interface/src/ui/ChatMessageArea.h +++ b/interface/src/ui/ChatMessageArea.h @@ -33,6 +33,10 @@ protected: virtual void wheelEvent(QWheelEvent* event); bool _useFixedHeight; + void insertFromMimeData(const QMimeData* source) { + insertPlainText(source->text()); + }; + }; #endif // hifi_ChatMessageArea_h diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index d63542bf7b..28aa6a2390 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -186,7 +186,7 @@ QPushButton:pressed { - + 0 @@ -223,6 +223,13 @@ QPushButton:pressed { + + + ChatInputArea + QTextEdit +
ui/ChatInputArea.h
+
+
messagePlainTextEdit messagesScrollArea From 0386dec2a67e0f8d450d7f49c8643bb82c9427ba Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:09:54 -0700 Subject: [PATCH 43/68] Provide option to align wrists with forearms. --- interface/src/Menu.cpp | 1 + interface/src/Menu.h | 1 + interface/src/avatar/SkeletonModel.cpp | 20 ++++++++++++++++++-- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0a0bd599eb..a7012d838d 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -336,6 +336,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false); addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false); + addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true); addDisabledActionAndSeparator(developerMenu, "Testing"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index f9f97be379..09b5fabfc8 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -256,6 +256,7 @@ private: namespace MenuOption { const QString AboutApp = "About Interface"; + const QString AlignForearmsWithWrists = "Align Forearms with Wrists"; const QString AmbientOcclusion = "Ambient Occlusion"; const QString Atmosphere = "Atmosphere"; const QString AudioNoiseReduction = "Audio Noise Reduction"; diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index f52858b4ff..4bb7814300 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -148,10 +148,18 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } const FBXGeometry& geometry = _geometry->getFBXGeometry(); float sign = (jointIndex == geometry.rightHandJointIndex) ? 1.0f : -1.0f; + int parentJointIndex = geometry.joints.at(jointIndex).parentIndex; + if (parentJointIndex == -1) { + return; + } // rotate palm to align with palm direction glm::quat palmRotation; - getJointRotation(jointIndex, palmRotation, true); + if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + getJointRotation(parentJointIndex, palmRotation, true); + } else { + getJointRotation(jointIndex, palmRotation, true); + } palmRotation = rotationBetween(palmRotation * geometry.palmDirection, palm.getNormal()) * palmRotation; // sort the finger indices by raw x, get the average direction @@ -177,7 +185,15 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin } // set hand position, rotation - setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); + if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { + glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); + setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), palmRotation, true); + _jointStates[jointIndex].rotation = glm::quat(); + + } else { + setJointPosition(jointIndex, palm.getPosition(), palmRotation, true); + } } void SkeletonModel::updateJointState(int index) { From 141250d51c0a2153461a3f3ce1156c11123ce21e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:22:24 -0700 Subject: [PATCH 44/68] Don't constrain elbow when rotating forearm with wrist. --- interface/src/avatar/SkeletonModel.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/interface/src/avatar/SkeletonModel.cpp b/interface/src/avatar/SkeletonModel.cpp index 4bb7814300..f8ebba676f 100644 --- a/interface/src/avatar/SkeletonModel.cpp +++ b/interface/src/avatar/SkeletonModel.cpp @@ -188,7 +188,8 @@ void SkeletonModel::applyPalmData(int jointIndex, const QVector& fingerJoin if (Menu::getInstance()->isOptionChecked(MenuOption::AlignForearmsWithWrists)) { glm::vec3 forearmVector = palmRotation * glm::vec3(sign, 0.0f, 0.0f); setJointPosition(parentJointIndex, palm.getPosition() + forearmVector * - geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale), palmRotation, true); + geometry.joints.at(jointIndex).distanceToParent * extractUniformScale(_scale)); + setJointRotation(parentJointIndex, palmRotation, true); _jointStates[jointIndex].rotation = glm::quat(); } else { From 5fd585aab1c7206c749b7fd44b66e65e663c477d Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 12:26:59 -0700 Subject: [PATCH 45/68] Fix error with cursor format getting reset when sending chat message --- interface/src/ui/ChatWindow.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index c459a6d426..d967e2305d 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -128,7 +128,9 @@ bool ChatWindow::eventFilter(QObject* sender, QEvent* event) { message.setBody(messageText); XmppClient::getInstance().getXMPPClient().sendPacket(message); #endif - ui->messagePlainTextEdit->document()->clear(); + QTextCursor cursor = ui->messagePlainTextEdit->textCursor(); + cursor.select(QTextCursor::Document); + cursor.removeSelectedText(); } return true; } From c8c3cf3664ced00de93a0a23d059b7cbbe0c697d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:29:01 -0700 Subject: [PATCH 46/68] Remove unused propagate option for applyRotationDelta. --- interface/src/renderer/Model.cpp | 8 +------- interface/src/renderer/Model.h | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 26e59635bb..9c7dc9a6a1 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1026,7 +1026,7 @@ float Model::getLimbLength(int jointIndex) const { return length; } -void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain, bool propagate) { +void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { JointState& state = _jointStates[jointIndex]; const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXJoint& joint = geometry.joints[jointIndex]; @@ -1042,12 +1042,6 @@ void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool cons glm::quat newRotation = glm::quat(glm::clamp(eulers, joint.rotationMin, joint.rotationMax)); state.combinedRotation = state.combinedRotation * glm::inverse(state.rotation) * newRotation; state.rotation = newRotation; - - if (propagate && targetRotation != state.combinedRotation && - joint.parentIndex != -1 && geometry.joints.at(joint.parentIndex).isFree) { - applyRotationDelta(joint.parentIndex, targetRotation * glm::inverse(state.combinedRotation), true, true); - state.combinedRotation = _jointStates.at(joint.parentIndex).combinedRotation * state.rotation; - } } const int BALL_SUBDIVISIONS = 10; diff --git a/interface/src/renderer/Model.h b/interface/src/renderer/Model.h index 10e9e2a66a..335071d669 100644 --- a/interface/src/renderer/Model.h +++ b/interface/src/renderer/Model.h @@ -257,7 +257,7 @@ protected: /// first free ancestor. float getLimbLength(int jointIndex) const; - void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true, bool propagate = false); + void applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain = true); private: From 2bac8024079ce096462acaf8538c67aaf3bc9815 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 23 Apr 2014 12:30:39 -0700 Subject: [PATCH 47/68] One more unused variable. --- interface/src/renderer/Model.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/renderer/Model.cpp b/interface/src/renderer/Model.cpp index 9c7dc9a6a1..3484ac5fc8 100644 --- a/interface/src/renderer/Model.cpp +++ b/interface/src/renderer/Model.cpp @@ -1028,8 +1028,7 @@ float Model::getLimbLength(int jointIndex) const { void Model::applyRotationDelta(int jointIndex, const glm::quat& delta, bool constrain) { JointState& state = _jointStates[jointIndex]; - const FBXGeometry& geometry = _geometry->getFBXGeometry(); - const FBXJoint& joint = geometry.joints[jointIndex]; + const FBXJoint& joint = _geometry->getFBXGeometry().joints[jointIndex]; if (!constrain || (joint.rotationMin == glm::vec3(-PI, -PI, -PI) && joint.rotationMax == glm::vec3(PI, PI, PI))) { // no constraints From 95357a7c35063b8a44171ac9fd6e301aeb9e83da Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 12:30:40 -0700 Subject: [PATCH 48/68] Update chat input area to use a 14pt font --- interface/ui/chatWindow.ui | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index 28aa6a2390..b1448091c4 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -199,6 +199,12 @@ QPushButton:pressed { 60 + + + Helvetica,Arial,sans-serif + 14 + + border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; From d56a4e169e726ea67f55b890fa57dfba9c1928d9 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 15:24:21 -0700 Subject: [PATCH 49/68] Add ChatInputArea --- interface/src/ui/ChatInputArea.h | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 interface/src/ui/ChatInputArea.h diff --git a/interface/src/ui/ChatInputArea.h b/interface/src/ui/ChatInputArea.h new file mode 100644 index 0000000000..264a9932c6 --- /dev/null +++ b/interface/src/ui/ChatInputArea.h @@ -0,0 +1,28 @@ +// +// ChatInputArea.h +// interface/src/ui +// +// Created by Ryan Huffman on 4/11/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_ChatInputArea_h +#define hifi_ChatInputArea_h + +#include + +class ChatInputArea : public QTextEdit { + Q_OBJECT +public: + ChatInputArea(QWidget* parent) : QTextEdit(parent) { }; + +protected: + void insertFromMimeData(const QMimeData* source) { + insertPlainText(source->text()); + }; +}; + +#endif // hifi_ChatInputArea_h From 1774f6c9bdcddf9219afacd478a9ed8bc1856e96 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 15:37:28 -0700 Subject: [PATCH 50/68] Add threshold to auto scroll --- interface/src/ui/ChatWindow.cpp | 10 +++++----- interface/src/ui/ChatWindow.h | 8 +++++++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/interface/src/ui/ChatWindow.cpp b/interface/src/ui/ChatWindow.cpp index d967e2305d..e0802c6bc5 100644 --- a/interface/src/ui/ChatWindow.cpp +++ b/interface/src/ui/ChatWindow.cpp @@ -171,7 +171,7 @@ void ChatWindow::addTimeStamp() { timeLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); timeLabel->setAlignment(Qt::AlignLeft); - bool atBottom = isAtBottom(); + bool atBottom = isNearBottom(); ui->messagesVBoxLayout->addWidget(timeLabel); ui->messagesVBoxLayout->parentWidget()->updateGeometry(); @@ -288,7 +288,7 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { messageText = messageText.replace(regexHifiLinks, "\\1"); messageArea->setHtml(userLabel + messageText); - bool atBottom = isAtBottom(); + bool atBottom = isNearBottom(); ui->messagesVBoxLayout->addWidget(messageArea); ui->messagesVBoxLayout->parentWidget()->updateGeometry(); @@ -308,13 +308,13 @@ void ChatWindow::messageReceived(const QXmppMessage& message) { #endif -bool ChatWindow::isAtBottom() { +bool ChatWindow::isNearBottom() { QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); - return verticalScrollBar->sliderPosition() == verticalScrollBar->maximum(); + return verticalScrollBar->value() >= verticalScrollBar->maximum() - Ui::AUTO_SCROLL_THRESHOLD; } // Scroll chat message area to bottom. void ChatWindow::scrollToBottom() { QScrollBar* verticalScrollBar = ui->messagesScrollArea->verticalScrollBar(); - verticalScrollBar->setSliderPosition(verticalScrollBar->maximum()); + verticalScrollBar->setValue(verticalScrollBar->maximum()); } diff --git a/interface/src/ui/ChatWindow.h b/interface/src/ui/ChatWindow.h index 399c9e917c..104fbe1746 100644 --- a/interface/src/ui/ChatWindow.h +++ b/interface/src/ui/ChatWindow.h @@ -27,6 +27,12 @@ #endif namespace Ui { + + +// Maximum amount the chat can be scrolled up in order to auto scroll. +const int AUTO_SCROLL_THRESHOLD = 20; + + class ChatWindow; } @@ -49,7 +55,7 @@ private: #endif void startTimerForTimeStamps(); void addTimeStamp(); - bool isAtBottom(); + bool isNearBottom(); void scrollToBottom(); Ui::ChatWindow* ui; From 0cba95e7ad1f8550eec37743af415ba2b03f80a7 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 15:37:49 -0700 Subject: [PATCH 51/68] Reorder property initialization in FramelessDialog --- interface/src/ui/FramelessDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/FramelessDialog.cpp b/interface/src/ui/FramelessDialog.cpp index 816c45b38a..4919e99db6 100644 --- a/interface/src/ui/FramelessDialog.cpp +++ b/interface/src/ui/FramelessDialog.cpp @@ -16,10 +16,10 @@ const int RESIZE_HANDLE_WIDTH = 7; FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) : QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint), - _position(position), - _selfHidden(false), _isResizing(false), - _resizeInitialWidth(0) { + _resizeInitialWidth(0), + _selfHidden(false), + _position(position) { setAttribute(Qt::WA_DeleteOnClose); From b0e1eab7ed19b1967d9514d8d35495024b3ea863 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Wed, 23 Apr 2014 16:15:51 -0700 Subject: [PATCH 52/68] Fix chat input textbox to use native scrollbar The border around the textedit was causing QT to use a non-native scrollbar. Moving the box into a frame that contains the border styling fixes this. --- interface/ui/chatWindow.ui | 85 ++++++++++++++++++++++++++++---------- 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/interface/ui/chatWindow.ui b/interface/ui/chatWindow.ui index b1448091c4..4d223b2665 100644 --- a/interface/ui/chatWindow.ui +++ b/interface/ui/chatWindow.ui @@ -186,9 +186,9 @@ QPushButton:pressed { - + - + 0 0 @@ -196,33 +196,77 @@ QPushButton:pressed { 0 - 60 + 78 - - - Helvetica,Arial,sans-serif - 14 - - - border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; + #chatFrame { +border-color: palette(dark); border-style: solid; border-left-width: 1px; border-right-width: 1px; border-bottom-width: 1px; +} QFrame::NoFrame - - Qt::ScrollBarAlwaysOff + + QFrame::Raised - - QAbstractScrollArea::AdjustToContents - - - true - - - false + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 60 + + + + + Helvetica,Arial,sans-serif + 14 + + + + + + + QFrame::NoFrame + + + Qt::ScrollBarAlwaysOff + + + QAbstractScrollArea::AdjustToContents + + + true + + + false + + + + @@ -237,7 +281,6 @@ QPushButton:pressed { - messagePlainTextEdit messagesScrollArea From 9bdcfe6d041fcf192b1e20597e118f6f130a5c79 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 24 Apr 2014 11:01:12 -0700 Subject: [PATCH 53/68] Undo now fully support local subtrees --- examples/editVoxels.js | 2 - libraries/voxels/src/VoxelTree.cpp | 7 + libraries/voxels/src/VoxelTree.h | 1 + libraries/voxels/src/VoxelTreeCommands.cpp | 130 +++++++++++++----- libraries/voxels/src/VoxelTreeCommands.h | 2 - .../voxels/src/VoxelsScriptingInterface.cpp | 36 ++--- 6 files changed, 115 insertions(+), 63 deletions(-) diff --git a/examples/editVoxels.js b/examples/editVoxels.js index 12c571b09c..453ac28649 100644 --- a/examples/editVoxels.js +++ b/examples/editVoxels.js @@ -1088,7 +1088,6 @@ function keyPressEvent(event) { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; - Voxels.eraseVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s); Voxels.setVoxel(newVoxel.x, newVoxel.y, newVoxel.z, newVoxel.s, newVoxel.red, newVoxel.green, newVoxel.blue); setAudioPosition(); initialVoxelSound.playRandom(); @@ -1394,7 +1393,6 @@ function checkControllers() { if (Vec3.length(Vec3.subtract(fingerTipPosition,lastFingerAddVoxel)) > (FINGERTIP_VOXEL_SIZE / 2)) { newColor = { red: colors[whichColor].red, green: colors[whichColor].green, blue: colors[whichColor].blue }; - Voxels.eraseVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE); Voxels.setVoxel(fingerTipPosition.x, fingerTipPosition.y, fingerTipPosition.z, FINGERTIP_VOXEL_SIZE, newColor.red, newColor.green, newColor.blue); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 3a77382a84..aeb877ef78 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -45,6 +45,13 @@ VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) cons return static_cast(getOctreeElementAt(x, y, z, s)); } +VoxelTreeElement* VoxelTree::getEnclosingVoxelAt(float x, float y, float z, float s) const { + unsigned char* octalCode = pointToOctalCode(x,y,z,s); + OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL); + + return static_cast(node); +} + void VoxelTree::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive) { diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index e0bc1d9a47..2992815787 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -30,6 +30,7 @@ public: void deleteVoxelAt(float x, float y, float z, float s); VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const; + VoxelTreeElement* getEnclosingVoxelAt(float x, float y, float z, float s) const; void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive = false); diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index 46837aa23e..d1dc0f3560 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -13,22 +13,56 @@ #include "VoxelTreeCommands.h" + + +struct SendVoxelsOperationArgs { + const unsigned char* newBaseOctCode; + VoxelEditPacketSender* packetSender; +}; + +bool sendVoxelsOperation(OctreeElement* element, void* extraData) { + VoxelTreeElement* voxel = (VoxelTreeElement*)element; + SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; + if (voxel->isColored()) { + const unsigned char* nodeOctalCode = voxel->getOctalCode(); + unsigned char* codeColorBuffer = NULL; + int codeLength = 0; + int bytesInCode = 0; + int codeAndColorLength; + + // If the newBase is NULL, then don't rebase + if (args->newBaseOctCode) { + codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); + codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + } else { + codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + codeColorBuffer = new unsigned char[codeAndColorLength]; + memcpy(codeColorBuffer, nodeOctalCode, bytesInCode); + } + + // copy the colors over + codeColorBuffer[bytesInCode + RED_INDEX] = voxel->getColor()[RED_INDEX]; + codeColorBuffer[bytesInCode + GREEN_INDEX] = voxel->getColor()[GREEN_INDEX]; + codeColorBuffer[bytesInCode + BLUE_INDEX] = voxel->getColor()[BLUE_INDEX]; + args->packetSender->queueVoxelEditMessage(PacketTypeVoxelSetDestructive, + codeColorBuffer, codeAndColorLength); + + delete[] codeColorBuffer; + } + return true; // keep going +} + + AddVoxelCommand::AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender, QUndoCommand* parent) : QUndoCommand("Add Voxel", parent), _tree(tree), _packetSender(packetSender), - _voxel(voxel), - _oldTree(NULL) + _voxel(voxel) { - VoxelTreeElement* element = _tree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - if (element) { - _oldTree = new VoxelTree(); - _tree->copySubTreeIntoNewTree(element, _oldTree, true); - } -} - -AddVoxelCommand::~AddVoxelCommand() { - delete _oldTree; } void AddVoxelCommand::redo() { @@ -41,18 +75,11 @@ void AddVoxelCommand::redo() { } void AddVoxelCommand::undo() { - if (_oldTree) { - OctreeElement* element = _tree->getOrCreateChildElementAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - qDebug() << "undo(): " << _voxel.x << " " << _voxel.y << " " << _voxel.z << " " << _voxel.s; - _tree->copyFromTreeIntoSubTree(_oldTree, element); - qDebug() << "done"; - } else { - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); - } + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); } } @@ -63,6 +90,26 @@ DeleteVoxelCommand::DeleteVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, Voxe _voxel(voxel), _oldTree(NULL) { + _tree->lockForRead(); + VoxelTreeElement* element = _tree->getEnclosingVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + if (element->getScale() == _voxel.s) { + if (!element->hasContent() && !element->isLeaf()) { + _oldTree = new VoxelTree(); + _tree->copySubTreeIntoNewTree(element, _oldTree, false); + } else { + _voxel.red = element->getColor()[0]; + _voxel.green = element->getColor()[1]; + _voxel.blue = element->getColor()[2]; + } + } else if (element->hasContent() && element->isLeaf()) { + _voxel.red = element->getColor()[0]; + _voxel.green = element->getColor()[1]; + _voxel.blue = element->getColor()[2]; + } else { + _voxel.s = 0.0f; + qDebug() << "No element for delete."; + } + _tree->unlock(); } DeleteVoxelCommand::~DeleteVoxelCommand() { @@ -70,21 +117,38 @@ DeleteVoxelCommand::~DeleteVoxelCommand() { } void DeleteVoxelCommand::redo() { - if (_oldTree) { - - } else { - if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); - } - if (_packetSender) { - _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); - } + if (_voxel.s == 0) { + return; + } + + if (_tree) { + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); } + if (_packetSender) { + _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); } } void DeleteVoxelCommand::undo() { + if (_voxel.s == 0) { + return; + } + if (_oldTree) { - + VoxelTreeElement* element = _oldTree->getVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + if (element) { + if (_tree) { + _tree->lockForWrite(); + _oldTree->copySubTreeIntoNewTree(element, _tree, false); + _tree->unlock(); + } + if (_packetSender) { + SendVoxelsOperationArgs args; + args.newBaseOctCode = NULL; + args.packetSender = _packetSender; + _oldTree->recurseTreeWithOperation(sendVoxelsOperation, &args); + _packetSender->releaseQueuedMessages(); + } + } } else { if (_tree) { _tree->createVoxel(_voxel.x, _voxel.y, _voxel.z, _voxel.s, _voxel.red, _voxel.green, _voxel.blue); diff --git a/libraries/voxels/src/VoxelTreeCommands.h b/libraries/voxels/src/VoxelTreeCommands.h index c3b23e7201..8df1f0dc14 100644 --- a/libraries/voxels/src/VoxelTreeCommands.h +++ b/libraries/voxels/src/VoxelTreeCommands.h @@ -23,7 +23,6 @@ class VoxelTree; class AddVoxelCommand : public QUndoCommand { public: AddVoxelCommand(VoxelTree* tree, VoxelDetail& voxel, VoxelEditPacketSender* packetSender = NULL, QUndoCommand* parent = NULL); - ~AddVoxelCommand(); virtual void redo(); virtual void undo(); @@ -32,7 +31,6 @@ private: VoxelTree* _tree; VoxelEditPacketSender* _packetSender; VoxelDetail _voxel; - VoxelTree* _oldTree; }; class DeleteVoxelCommand : public QUndoCommand { diff --git a/libraries/voxels/src/VoxelsScriptingInterface.cpp b/libraries/voxels/src/VoxelsScriptingInterface.cpp index 08dcfd3f47..15503db454 100644 --- a/libraries/voxels/src/VoxelsScriptingInterface.cpp +++ b/libraries/voxels/src/VoxelsScriptingInterface.cpp @@ -76,32 +76,16 @@ void VoxelsScriptingInterface::setVoxel(float x, float y, float z, float scale, if (_tree) { if (_undoStack) { AddVoxelCommand* addCommand = new AddVoxelCommand(_tree, - addVoxelDetail, - getVoxelPacketSender()); - - VoxelTreeElement* deleteVoxelElement = _tree->getVoxelAt(addVoxelDetail.x, addVoxelDetail.y, addVoxelDetail.z, addVoxelDetail.s); - if (deleteVoxelElement) { - nodeColor color; - memcpy(&color, &deleteVoxelElement->getColor(), sizeof(nodeColor)); - VoxelDetail deleteVoxelDetail = {addVoxelDetail.x, - addVoxelDetail.y, - addVoxelDetail.z, - addVoxelDetail.s, - color[0], - color[1], - color[2]}; - DeleteVoxelCommand* delCommand = new DeleteVoxelCommand(_tree, - deleteVoxelDetail, - getVoxelPacketSender()); - _undoStack->beginMacro(addCommand->text()); - // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. - _undoStack->push(delCommand); - _undoStack->push(addCommand); - _undoStack->endMacro(); - } else { - // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. - _undoStack->push(addCommand); - } + addVoxelDetail, + getVoxelPacketSender()); + DeleteVoxelCommand* deleteCommand = new DeleteVoxelCommand(_tree, + addVoxelDetail, + getVoxelPacketSender()); + _undoStack->beginMacro(addCommand->text()); + // As QUndoStack automatically executes redo() on push, we don't need to execute the command ourselves. + _undoStack->push(deleteCommand); + _undoStack->push(addCommand); + _undoStack->endMacro(); } else { // queue the destructive add queueVoxelAdd(PacketTypeVoxelSetDestructive, addVoxelDetail); From 1844eb2c9e7302ba8835fd2ae091617894ab6f7a Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 24 Apr 2014 11:12:01 -0700 Subject: [PATCH 54/68] Pre CR tweaks --- libraries/voxels/src/VoxelTreeCommands.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index d1dc0f3560..a35096b5c7 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -21,7 +21,7 @@ struct SendVoxelsOperationArgs { }; bool sendVoxelsOperation(OctreeElement* element, void* extraData) { - VoxelTreeElement* voxel = (VoxelTreeElement*)element; + VoxelTreeElement* voxel = static_cast(element); SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; if (voxel->isColored()) { const unsigned char* nodeOctalCode = voxel->getOctalCode(); @@ -117,19 +117,20 @@ DeleteVoxelCommand::~DeleteVoxelCommand() { } void DeleteVoxelCommand::redo() { - if (_voxel.s == 0) { + if (_voxel.s == 0.0f) { return; } if (_tree) { - _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); } + _tree->deleteVoxelAt(_voxel.x, _voxel.y, _voxel.z, _voxel.s); + } if (_packetSender) { _packetSender->queueVoxelEditMessages(PacketTypeVoxelErase, 1, &_voxel); } } void DeleteVoxelCommand::undo() { - if (_voxel.s == 0) { + if (_voxel.s == 0.0f) { return; } @@ -157,4 +158,4 @@ void DeleteVoxelCommand::undo() { _packetSender->queueVoxelEditMessages(PacketTypeVoxelSet, 1, &_voxel); } } -} \ No newline at end of file +} From ad0f0118bcb879f7f2534ef597d9d306b0b9b6f4 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 24 Apr 2014 15:01:37 -0600 Subject: [PATCH 55/68] fixes for new versioning: --- interface/src/Application.cpp | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4adb2f772a..4d9c70aeda 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3520,10 +3520,9 @@ void Application::parseVersionXml() { QString operatingSystem("ubuntu"); #endif - QString releaseDate; - QString releaseNotes; QString latestVersion; QUrl downloadUrl; + QString releaseNotes("Unavailable"); QObject* sender = QObject::sender(); QXmlStreamReader xml(qobject_cast(sender)); @@ -3531,21 +3530,15 @@ void Application::parseVersionXml() { QXmlStreamReader::TokenType token = xml.readNext(); if (token == QXmlStreamReader::StartElement) { - if (xml.name() == "ReleaseDate") { - xml.readNext(); - releaseDate = xml.text().toString(); - } - if (xml.name() == "ReleaseNotes") { - xml.readNext(); - releaseNotes = xml.text().toString(); - } - if (xml.name() == "Version") { - xml.readNext(); - latestVersion = xml.text().toString(); - } + xml.readNext(); if (xml.name() == operatingSystem) { xml.readNext(); - downloadUrl = QUrl(xml.text().toString()); + if (xml.name() == "version") { + latestVersion = xml.text().toString(); + } + if (xml.name() == "url") { + downloadUrl = xml.text().toString(); + } } } } From 27002a94069b5ec13fecd49c12aada8c83ce7318 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 24 Apr 2014 15:10:37 -0600 Subject: [PATCH 56/68] Casting to QUrl --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4d9c70aeda..20cab975a4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3537,7 +3537,7 @@ void Application::parseVersionXml() { latestVersion = xml.text().toString(); } if (xml.name() == "url") { - downloadUrl = xml.text().toString(); + downloadUrl = QUrl(xml.text().toString()); } } } From ccad0aed9e68e993360cbadfb404c6f20bf01001 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 24 Apr 2014 14:54:01 -0700 Subject: [PATCH 57/68] Move ChatInputArea code in header to .cpp --- interface/src/ui/ChatInputArea.cpp | 19 +++++++++++++++++++ interface/src/ui/ChatInputArea.h | 7 +++---- 2 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 interface/src/ui/ChatInputArea.cpp diff --git a/interface/src/ui/ChatInputArea.cpp b/interface/src/ui/ChatInputArea.cpp new file mode 100644 index 0000000000..3e8fc84fe2 --- /dev/null +++ b/interface/src/ui/ChatInputArea.cpp @@ -0,0 +1,19 @@ +// +// ChatInputArea.cpp +// interface/src/ui +// +// Created by Ryan Huffman on 4/24/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "ChatInputArea.h" + +ChatInputArea::ChatInputArea(QWidget* parent) : QTextEdit(parent) { +}; + +void ChatInputArea::insertFromMimeData(const QMimeData* source) { + insertPlainText(source->text()); +}; diff --git a/interface/src/ui/ChatInputArea.h b/interface/src/ui/ChatInputArea.h index 264a9932c6..31d1584df7 100644 --- a/interface/src/ui/ChatInputArea.h +++ b/interface/src/ui/ChatInputArea.h @@ -13,16 +13,15 @@ #define hifi_ChatInputArea_h #include +#include class ChatInputArea : public QTextEdit { Q_OBJECT public: - ChatInputArea(QWidget* parent) : QTextEdit(parent) { }; + ChatInputArea(QWidget* parent); protected: - void insertFromMimeData(const QMimeData* source) { - insertPlainText(source->text()); - }; + void insertFromMimeData(const QMimeData* source); }; #endif // hifi_ChatInputArea_h From 7b0981202848064059ccbcf691d077612a625aa8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 24 Apr 2014 14:54:26 -0700 Subject: [PATCH 58/68] Remove insertFromMimeData override in ChatMessageArea --- interface/src/ui/ChatMessageArea.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/interface/src/ui/ChatMessageArea.h b/interface/src/ui/ChatMessageArea.h index b726a31d76..57199538fd 100644 --- a/interface/src/ui/ChatMessageArea.h +++ b/interface/src/ui/ChatMessageArea.h @@ -32,11 +32,6 @@ signals: protected: virtual void wheelEvent(QWheelEvent* event); bool _useFixedHeight; - - void insertFromMimeData(const QMimeData* source) { - insertPlainText(source->text()); - }; - }; #endif // hifi_ChatMessageArea_h From b69fa73dfae82a38ab52327f9a763698e84b0df8 Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 24 Apr 2014 14:54:57 -0700 Subject: [PATCH 59/68] Unsplit a line in FramelessDialog --- interface/src/ui/FramelessDialog.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/interface/src/ui/FramelessDialog.h b/interface/src/ui/FramelessDialog.h index 22666cca63..828602a5db 100644 --- a/interface/src/ui/FramelessDialog.h +++ b/interface/src/ui/FramelessDialog.h @@ -21,8 +21,7 @@ class FramelessDialog : public QDialog { public: enum Position { POSITION_LEFT, POSITION_RIGHT }; - FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0, - Position position = POSITION_LEFT); + FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT); void setStyleSheetFile(const QString& fileName); protected: From f4c98a8fa4597832a1419107de1487d0e1edf14e Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 24 Apr 2014 16:21:49 -0600 Subject: [PATCH 60/68] Fixing xml parsing --- interface/src/Application.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 20cab975a4..8fdd41ca47 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3526,22 +3526,24 @@ void Application::parseVersionXml() { QObject* sender = QObject::sender(); QXmlStreamReader xml(qobject_cast(sender)); - while (!xml.atEnd() && !xml.hasError()) { - QXmlStreamReader::TokenType token = xml.readNext(); - - if (token == QXmlStreamReader::StartElement) { - xml.readNext(); - if (xml.name() == operatingSystem) { - xml.readNext(); - if (xml.name() == "version") { + + while(!xml.atEnd() && !xml.hasError()) { + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) { + while(!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) { + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") { + xml.readNext(); latestVersion = xml.text().toString(); } - if (xml.name() == "url") { + if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "url") { + xml.readNext(); downloadUrl = QUrl(xml.text().toString()); } + xml.readNext(); } } + xml.readNext(); } + if (!shouldSkipVersion(latestVersion) && applicationVersion() != latestVersion) { new UpdateDialog(_glWidget, releaseNotes, latestVersion, downloadUrl); } From a21991c5c24e36cfcd5089f7247020a43902444d Mon Sep 17 00:00:00 2001 From: Leonardo Murillo Date: Thu, 24 Apr 2014 16:22:34 -0600 Subject: [PATCH 61/68] Fixing xml parsing --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8fdd41ca47..ab505ede93 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3527,9 +3527,9 @@ void Application::parseVersionXml() { QXmlStreamReader xml(qobject_cast(sender)); - while(!xml.atEnd() && !xml.hasError()) { + while (!xml.atEnd() && !xml.hasError()) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name() == operatingSystem) { - while(!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) { + while (!(xml.tokenType() == QXmlStreamReader::EndElement && xml.name() == operatingSystem)) { if (xml.tokenType() == QXmlStreamReader::StartElement && xml.name().toString() == "version") { xml.readNext(); latestVersion = xml.text().toString(); From d88897ccc707be1e2624c951ae41adcc2d48bd4e Mon Sep 17 00:00:00 2001 From: Ryan Huffman Date: Thu, 24 Apr 2014 15:55:34 -0700 Subject: [PATCH 62/68] Add error box when going to user/location that doesn't exist --- interface/src/Application.h | 1 + interface/src/avatar/MyAvatar.cpp | 3 +++ interface/src/location/LocationManager.cpp | 4 ++++ 3 files changed, 8 insertions(+) diff --git a/interface/src/Application.h b/interface/src/Application.h index fb48acb721..6bb2bf4c81 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -16,6 +16,7 @@ #include #include +#include #include #include #include diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 317f408aa7..b8a45aacd5 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -1178,6 +1179,8 @@ void MyAvatar::goToLocationFromResponse(const QJsonObject& jsonObject) { coordinateItems[2].toFloat()) - newOrientation * IDENTITY_FRONT * DISTANCE_TO_USER; setPosition(newPosition); emit transformChanged(); + } else { + QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found."); } } diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 8009551b6c..f80c331df4 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + #include "Application.h" #include "LocationManager.h" @@ -118,6 +120,8 @@ void LocationManager::checkForMultipleDestinations() { Application::getInstance()->getAvatar()->goToLocationFromResponse(_placeData); return; } + + QMessageBox::warning(Application::getInstance()->getWindow(), "", "That user or location could not be found."); } } From 01637e80377b43f84ce08d5faf714d7715fe0ba0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 24 Apr 2014 17:37:48 -0700 Subject: [PATCH 63/68] Fix error introduced with gettimeofday removing + spelling mistake --- interface/src/Audio.cpp | 6 +++--- interface/src/Audio.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index c182f6e842..68e38615bf 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -644,10 +644,10 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) { const int NUM_INITIAL_PACKETS_DISCARD = 3; const int STANDARD_DEVIATION_SAMPLE_COUNT = 500; - _timeSinceLastRecieved.start(); _totalPacketsReceived++; - double timeDiff = (double)_timeSinceLastRecieved.nsecsElapsed() / 1000000.0; // ns to ms + double timeDiff = (double)_timeSinceLastReceived.nsecsElapsed() / 1000000.0; // ns to ms + _timeSinceLastReceived.start(); // Discard first few received packets for computing jitter (often they pile up on start) if (_totalPacketsReceived > NUM_INITIAL_PACKETS_DISCARD) { @@ -1265,7 +1265,7 @@ bool Audio::switchOutputToAudioDevice(const QAudioDeviceInfo& outputDeviceInfo) // setup a procedural audio output device _proceduralAudioOutput = new QAudioOutput(outputDeviceInfo, _outputFormat, this); - _timeSinceLastRecieved.start(); + _timeSinceLastReceived.start(); // setup spatial audio ringbuffer int numFrameSamples = _outputFormat.sampleRate() * _desiredOutputFormat.channelCount(); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index e1b8a7dddc..277c606d4b 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -129,7 +129,7 @@ private: QString _outputAudioDeviceName; StDev _stdev; - QElapsedTimer _timeSinceLastRecieved; + QElapsedTimer _timeSinceLastReceived; float _averagedLatency; float _measuredJitter; int16_t _jitterBufferSamples; From cf7fe2306bafa1c2710ba7942c1fff19c4931277 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 24 Apr 2014 18:10:51 -0700 Subject: [PATCH 64/68] Fix audio jitter --- interface/src/ui/PreferencesDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index 550c616fc1..7a70b743bd 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -184,6 +184,7 @@ void PreferencesDialog::savePreferences() { Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value()); Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value()); + Application::getInstance()->getAudio()->setJitterBufferSamples(ui.audioJitterSpin->value()); Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(), Application::getInstance()->getGLWidget()->height()); From 6acdf9cd6cd98c728a89e249f9bc3743c6845412 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 25 Apr 2014 11:21:02 -0700 Subject: [PATCH 65/68] fix issues with bad timestamps --- libraries/octree/src/OctreeSceneStats.cpp | 39 +++++++++++++++++++---- libraries/shared/src/SharedUtil.cpp | 4 ++- 2 files changed, 36 insertions(+), 7 deletions(-) diff --git a/libraries/octree/src/OctreeSceneStats.cpp b/libraries/octree/src/OctreeSceneStats.cpp index ad8702adc2..e7d34680a7 100644 --- a/libraries/octree/src/OctreeSceneStats.cpp +++ b/libraries/octree/src/OctreeSceneStats.cpp @@ -820,11 +820,7 @@ const char* OctreeSceneStats::getItemValue(Item item) { void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, bool wasStatsPacket, int nodeClockSkewUsec) { - _incomingPacket++; - _incomingBytes += packet.size(); - if (!wasStatsPacket) { - _incomingWastedBytes += (MAX_PACKET_SIZE - packet.size()); - } + const bool wantExtraDebugging = false; int numBytesPacketHeader = numBytesForPacketHeader(packet); const unsigned char* dataAt = reinterpret_cast(packet.data()) + numBytesPacketHeader; @@ -842,12 +838,43 @@ void OctreeSceneStats::trackIncomingOctreePacket(const QByteArray& packet, OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); int flightTime = arrivedAt - sentAt + nodeClockSkewUsec; + + if (wantExtraDebugging) { + qDebug() << "sentAt:" << sentAt << " usecs"; + qDebug() << "arrivedAt:" << arrivedAt << " usecs"; + qDebug() << "nodeClockSkewUsec:" << nodeClockSkewUsec << " usecs"; + qDebug() << "flightTime:" << flightTime << " usecs"; + } + + // Guard against possible corrupted packets... with bad timestamps + const int MAX_RESONABLE_FLIGHT_TIME = 200 * USECS_PER_SECOND; // 200 seconds is more than enough time for a packet to arrive + const int MIN_RESONABLE_FLIGHT_TIME = 0; + if (flightTime > MAX_RESONABLE_FLIGHT_TIME || flightTime < MIN_RESONABLE_FLIGHT_TIME) { + qDebug() << "ignoring unreasonable packet... flightTime:" << flightTime; + return; // ignore any packets that are unreasonable + } + + // Guard against possible corrupted packets... with bad sequence numbers + const int MAX_RESONABLE_SEQUENCE_OFFSET = 2000; + const int MIN_RESONABLE_SEQUENCE_OFFSET = -2000; + int sequenceOffset = (sequence - _incomingLastSequence); + if (sequenceOffset > MAX_RESONABLE_SEQUENCE_OFFSET || sequenceOffset < MIN_RESONABLE_SEQUENCE_OFFSET) { + qDebug() << "ignoring unreasonable packet... sequence:" << sequence << "_incomingLastSequence:" << _incomingLastSequence; + return; // ignore any packets that are unreasonable + } + + // track packets here... + _incomingPacket++; + _incomingBytes += packet.size(); + if (!wasStatsPacket) { + _incomingWastedBytes += (MAX_PACKET_SIZE - packet.size()); + } + const int USECS_PER_MSEC = 1000; float flightTimeMsecs = flightTime / USECS_PER_MSEC; _incomingFlightTimeAverage.updateAverage(flightTimeMsecs); // track out of order and possibly lost packets... - const bool wantExtraDebugging = false; if (sequence == _incomingLastSequence) { if (wantExtraDebugging) { qDebug() << "last packet duplicate got:" << sequence << "_incomingLastSequence:" << _incomingLastSequence; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index bbb73cae4c..0a9f8df3f7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -40,10 +40,12 @@ void initialiseUsecTimestampNow() { if (initialised) { qDebug() << "[WARNING] Double initialisation of usecTimestampNow()."; return; - } + } TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec + timestampTimer.start(); initialised = true; + qDebug() << "[INFO] usecTimestampNow() initialized."; } void usecTimestampNowForceClockSkew(int clockSkew) { From 8b4a91004020c8fa2ff0bb38a89ff0f884b2fda2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 25 Apr 2014 12:19:18 -0700 Subject: [PATCH 66/68] Fix timestamp timer not fired --- assignment-client/src/main.cpp | 2 -- domain-server/src/main.cpp | 2 -- interface/src/main.cpp | 1 - libraries/shared/src/SharedUtil.cpp | 25 ++++++++++--------------- libraries/shared/src/SharedUtil.h | 1 - 5 files changed, 10 insertions(+), 21 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 7132b5c38a..5e103cf767 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -17,8 +17,6 @@ #include "AssignmentClientMonitor.h" int main(int argc, char* argv[]) { - initialiseUsecTimestampNow(); - #ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); #endif diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 871c16a215..1d9e837f0a 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -23,8 +23,6 @@ #include "DomainServer.h" int main(int argc, char* argv[]) { - initialiseUsecTimestampNow(); - #ifndef WIN32 setvbuf(stdout, NULL, _IOLBF, 0); #endif diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 6f9dc5e3bd..2bb0633f24 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -16,7 +16,6 @@ #include int main(int argc, const char * argv[]) { - initialiseUsecTimestampNow(); QElapsedTimer startupTime; startupTime.start(); diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index bbb73cae4c..c65b7505ee 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -30,27 +30,22 @@ #include "OctalCode.h" #include "SharedUtil.h" - -static qint64 TIME_REFERENCE = 0; // in usec -static QElapsedTimer timestampTimer; static int usecTimestampNowAdjust = 0; // in usec - -void initialiseUsecTimestampNow() { - static bool initialised = false; - if (initialised) { - qDebug() << "[WARNING] Double initialisation of usecTimestampNow()."; - return; - } - - TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec - initialised = true; -} - void usecTimestampNowForceClockSkew(int clockSkew) { ::usecTimestampNowAdjust = clockSkew; } quint64 usecTimestampNow() { + static bool usecTimestampNowIsInitialized = false; + static qint64 TIME_REFERENCE = 0; // in usec + static QElapsedTimer timestampTimer; + + if (!usecTimestampNowIsInitialized) { + TIME_REFERENCE = QDateTime::currentMSecsSinceEpoch() * 1000; // ms to usec + timestampTimer.start(); + usecTimestampNowIsInitialized = true; + } + // usec nsec to usec usec return TIME_REFERENCE + timestampTimer.nsecsElapsed() / 1000 + ::usecTimestampNowAdjust; } diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 54d599070d..4a3fe2a129 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -60,7 +60,6 @@ static const quint64 USECS_PER_SECOND = USECS_PER_MSEC * MSECS_PER_SECOND; const int BITS_IN_BYTE = 8; -void initialiseUsecTimestampNow(); quint64 usecTimestampNow(); void usecTimestampNowForceClockSkew(int clockSkew); From 8e12c0d8e5ca45bd32f24a3392f6521ab5dbb8c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 25 Apr 2014 13:22:18 -0700 Subject: [PATCH 67/68] pass the owner scope to auth requests --- libraries/networking/src/AccountManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index d1e4edf2ea..278923026d 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -282,10 +282,13 @@ void AccountManager::requestAccessToken(const QString& login, const QString& pas QUrl grantURL = _authURL; grantURL.setPath("/oauth/token"); + const QString ACCOUNT_MANAGER_REQUESTED_SCOPE = "owner"; + QByteArray postData; postData.append("grant_type=password&"); postData.append("username=" + login + "&"); - postData.append("password=" + password); + postData.append("password=" + password + "&"); + postData.append("scope=" + ACCOUNT_MANAGER_REQUESTED_SCOPE); request.setUrl(grantURL); request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded"); From 3143e10bd85029d0adc0136b7251c5fcb8fe09b6 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 25 Apr 2014 13:33:59 -0700 Subject: [PATCH 68/68] CR --- libraries/octree/src/Octree.cpp | 13 +++++++++++++ libraries/octree/src/Octree.h | 8 ++++++++ libraries/voxels/src/VoxelTree.cpp | 5 +---- libraries/voxels/src/VoxelTree.h | 7 +++++++ libraries/voxels/src/VoxelTreeCommands.cpp | 2 +- 5 files changed, 30 insertions(+), 5 deletions(-) diff --git a/libraries/octree/src/Octree.cpp b/libraries/octree/src/Octree.cpp index ebfb954bd8..5e812c06c3 100644 --- a/libraries/octree/src/Octree.cpp +++ b/libraries/octree/src/Octree.cpp @@ -542,6 +542,19 @@ OctreeElement* Octree::getOctreeElementAt(float x, float y, float z, float s) co return node; } +OctreeElement* Octree::getOctreeEnclosingElementAt(float x, float y, float z, float s) const { + unsigned char* octalCode = pointToOctalCode(x,y,z,s); + OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL); + + delete[] octalCode; // cleanup memory +#ifdef HAS_AUDIT_CHILDREN + if (node) { + node->auditChildren("Octree::getOctreeElementAt()"); + } +#endif // def HAS_AUDIT_CHILDREN + return node; +} + OctreeElement* Octree::getOrCreateChildElementAt(float x, float y, float z, float s) { return getRoot()->getOrCreateChildElementAt(x, y, z, s); diff --git a/libraries/octree/src/Octree.h b/libraries/octree/src/Octree.h index 0b9f1657ee..a11e73ab04 100644 --- a/libraries/octree/src/Octree.h +++ b/libraries/octree/src/Octree.h @@ -210,7 +210,15 @@ public: void reaverageOctreeElements(OctreeElement* startNode = NULL); void deleteOctreeElementAt(float x, float y, float z, float s); + + /// Find the voxel at position x,y,z,s + /// \return pointer to the OctreeElement or NULL if none at x,y,z,s. OctreeElement* getOctreeElementAt(float x, float y, float z, float s) const; + + /// Find the voxel at position x,y,z,s + /// \return pointer to the OctreeElement or to the smallest enclosing parent if none at x,y,z,s. + OctreeElement* getOctreeEnclosingElementAt(float x, float y, float z, float s) const; + OctreeElement* getOrCreateChildElementAt(float x, float y, float z, float s); void recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData = NULL); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index aeb877ef78..b1ddf2e5b0 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -46,10 +46,7 @@ VoxelTreeElement* VoxelTree::getVoxelAt(float x, float y, float z, float s) cons } VoxelTreeElement* VoxelTree::getEnclosingVoxelAt(float x, float y, float z, float s) const { - unsigned char* octalCode = pointToOctalCode(x,y,z,s); - OctreeElement* node = nodeForOctalCode(_rootNode, octalCode, NULL); - - return static_cast(node); + return static_cast(getOctreeEnclosingElementAt(x, y, z, s)); } void VoxelTree::createVoxel(float x, float y, float z, float s, diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 2992815787..eb24c182b2 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -29,8 +29,15 @@ public: VoxelTreeElement* getRoot() { return (VoxelTreeElement*)_rootNode; } void deleteVoxelAt(float x, float y, float z, float s); + + /// Find the voxel at position x,y,z,s + /// \return pointer to the VoxelTreeElement or NULL if none at x,y,z,s. VoxelTreeElement* getVoxelAt(float x, float y, float z, float s) const; + + /// Find the voxel at position x,y,z,s + /// \return pointer to the VoxelTreeElement or to the smallest enclosing parent if none at x,y,z,s. VoxelTreeElement* getEnclosingVoxelAt(float x, float y, float z, float s) const; + void createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive = false); diff --git a/libraries/voxels/src/VoxelTreeCommands.cpp b/libraries/voxels/src/VoxelTreeCommands.cpp index a35096b5c7..39e08d3bc2 100644 --- a/libraries/voxels/src/VoxelTreeCommands.cpp +++ b/libraries/voxels/src/VoxelTreeCommands.cpp @@ -22,7 +22,7 @@ struct SendVoxelsOperationArgs { bool sendVoxelsOperation(OctreeElement* element, void* extraData) { VoxelTreeElement* voxel = static_cast(element); - SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; + SendVoxelsOperationArgs* args = static_cast(extraData); if (voxel->isColored()) { const unsigned char* nodeOctalCode = voxel->getOctalCode(); unsigned char* codeColorBuffer = NULL;