From f230eeadabe7e4584ee43bd7f3f1c8758329d65a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 13 Nov 2013 12:37:40 -0800 Subject: [PATCH 01/28] added decodeOctCode to voxel-edit --- voxel-edit/src/main.cpp | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 5787caabac..5f67a46163 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -272,7 +272,30 @@ int main(int argc, const char * argv[]) } else { qDebug() << "Unexpected number of parameters for getOctCode\n"; } + return 0; + } + + const char* DECODE_OCTCODE = "--decodeOctCode"; + const char* decodeParam = getCmdOption(argc, argv, DECODE_OCTCODE); + if (decodeParam) { + + QString decodeParamsString(decodeParam); + unsigned char* octalCodeToDecode = hexStringToOctalCode(decodeParamsString); + + VoxelPositionSize details; + voxelDetailsForCode(octalCodeToDecode, details); + + delete[] octalCodeToDecode; + + qDebug() << "octal code to decode: " << decodeParamsString << "\n"; + qDebug() << "Details for Octal Code:\n"; + qDebug() << " x:" << details.x << "[" << details.x * TREE_SCALE << "]" << "\n"; + qDebug() << " y:" << details.y << "[" << details.y * TREE_SCALE << "]" << "\n"; + qDebug() << " z:" << details.z << "[" << details.z * TREE_SCALE << "]" << "\n"; + qDebug() << " s:" << details.s << "[" << details.s * TREE_SCALE << "]" << "\n"; + return 0; } + // Handles taking and SVO and splitting it into multiple SVOs based on // jurisdiction details From 865d2d19f1e0fe2008307b689dfc09091d066ce8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 13 Nov 2013 17:29:01 -0800 Subject: [PATCH 02/28] added some debugging to see why the servers are spinning out constantly checking for dirty tree --- libraries/voxel-server-library/src/VoxelPersistThread.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index fd9834cc79..7cb57165e8 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -67,9 +67,13 @@ bool VoxelPersistThread::process() { uint64_t MSECS_TO_USECS = 1000; uint64_t USECS_TO_SLEEP = 100 * MSECS_TO_USECS; // every 100ms usleep(USECS_TO_SLEEP); + uint64_t now = usecTimestampNow(); + uint64_t sinceLastSave = now - _lastSave; + uint64_t intervalToCheck = _persistInterval * MSECS_TO_USECS; + - if ((usecTimestampNow() - _lastSave) > (_persistInterval * MSECS_TO_USECS)) { - qDebug("checking if voxels are dirty.\n"); + if (sinceLastSave > intervalToCheck) { + qDebug("checking if voxels are dirty. sinceLastSave=%llu intervalToCheck=%llu\n", sinceLastSave, intervalToCheck); // check the dirty bit and persist here... if (_tree->isDirty()) { _lastSave = usecTimestampNow(); From 1d272c333ab3524a6d03a4ada37cdd9a1d0bea04 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 13 Nov 2013 21:31:34 -0800 Subject: [PATCH 03/28] fix new VoxelPersistThread behavior so it's actually only checking dirty bits every each persist cycle --- libraries/voxel-server-library/src/VoxelPersistThread.cpp | 8 +++----- libraries/voxel-server-library/src/VoxelPersistThread.h | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index 7cb57165e8..6a9e5a53d5 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -60,7 +60,7 @@ bool VoxelPersistThread::process() { VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet); _initialLoadComplete = true; - _lastSave = usecTimestampNow(); // we just loaded, no need to save again + _lastCheck = usecTimestampNow(); // we just loaded, no need to save again } if (isStillRunning()) { @@ -68,15 +68,13 @@ bool VoxelPersistThread::process() { uint64_t USECS_TO_SLEEP = 100 * MSECS_TO_USECS; // every 100ms usleep(USECS_TO_SLEEP); uint64_t now = usecTimestampNow(); - uint64_t sinceLastSave = now - _lastSave; + uint64_t sinceLastSave = now - _lastCheck; uint64_t intervalToCheck = _persistInterval * MSECS_TO_USECS; - if (sinceLastSave > intervalToCheck) { - qDebug("checking if voxels are dirty. sinceLastSave=%llu intervalToCheck=%llu\n", sinceLastSave, intervalToCheck); // check the dirty bit and persist here... + _lastCheck = usecTimestampNow(); if (_tree->isDirty()) { - _lastSave = usecTimestampNow(); qDebug("saving voxels to file %s...\n",_filename); _tree->writeToSVOFile(_filename); _tree->clearDirtyBit(); // tree is clean after saving diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.h b/libraries/voxel-server-library/src/VoxelPersistThread.h index 5d0c46bfbb..de6b4ab094 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.h +++ b/libraries/voxel-server-library/src/VoxelPersistThread.h @@ -38,7 +38,7 @@ private: time_t _loadCompleted; uint64_t _loadTimeUSecs; - uint64_t _lastSave; + uint64_t _lastCheck; }; #endif // __voxel_server__VoxelPersistThread__ From 34668e8716fef96d36d879d8f947ab268525ca85 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 13 Nov 2013 23:04:51 -0800 Subject: [PATCH 04/28] add Paste To Voxel --- interface/src/Application.cpp | 32 +++++++++++++++++++------------- interface/src/Application.h | 2 +- interface/src/Menu.cpp | 33 ++++++++++++++++++++++++++++++++- interface/src/Menu.h | 2 ++ 4 files changed, 54 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 71b63e8593..697d5d3b35 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1603,22 +1603,11 @@ void Application::copyVoxels() { } } -void Application::pasteVoxels() { - unsigned char* calculatedOctCode = NULL; - VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - +void Application::pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination) { // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location SendVoxelsOperationArgs args; - - // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a - // target octalCode for where the user is pointing. - if (selectedNode) { - args.newBaseOctCode = selectedNode->getOctalCode(); - } else { - args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - } + args.newBaseOctCode = octalCodeDestination; _sharedVoxelSystem.getTree()->recurseTreeWithOperation(sendVoxelsOperation, &args); @@ -1628,6 +1617,23 @@ void Application::pasteVoxels() { } _voxelEditSender.releaseQueuedMessages(); +} + +void Application::pasteVoxels() { + unsigned char* calculatedOctCode = NULL; + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a + // target octalCode for where the user is pointing. + const unsigned char* octalCodeDestination; + if (selectedNode) { + octalCodeDestination = selectedNode->getOctalCode(); + } else { + octalCodeDestination = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } + + pasteVoxelsToOctalCode(octalCodeDestination); if (calculatedOctCode) { delete[] calculatedOctCode; diff --git a/interface/src/Application.h b/interface/src/Application.h index 61a65747af..78530ecea2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -171,7 +171,7 @@ public: glm::vec2 getViewportDimensions() const{ return glm::vec2(_glWidget->width(),_glWidget->height()); } NodeToJurisdictionMap& getVoxelServerJurisdictions() { return _voxelServerJurisdictions; } - + void pasteVoxelsToOctalCode(const unsigned char* octalCodeDestination); public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 602d2131c2..d884f74630 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -486,7 +486,11 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::DestructiveAddVoxel); addCheckableActionToQMenuAndActionHash(developerMenu, MenuOption::ExtraDebugging); - + addActionToQMenuAndActionHash(developerMenu, MenuOption::PasteToVoxel, + Qt::CTRL | Qt::SHIFT | Qt::Key_V, + this, + SLOT(pasteToVoxel())); + #ifndef Q_OS_MAC QMenu* helpMenu = addMenu("Help"); @@ -958,6 +962,33 @@ void Menu::goToUser() { sendFakeEnterEvent(); } +void Menu::pasteToVoxel() { + QInputDialog pasteToOctalCodeDialog(Application::getInstance()->getWindow()); + pasteToOctalCodeDialog.setWindowTitle("Paste to Voxel"); + pasteToOctalCodeDialog.setLabelText("Octal Code:"); + QString octalCode = ""; + pasteToOctalCodeDialog.setTextValue(octalCode); + pasteToOctalCodeDialog.setWindowFlags(Qt::Sheet); + pasteToOctalCodeDialog.resize(pasteToOctalCodeDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, + pasteToOctalCodeDialog.size().height()); + + int dialogReturn = pasteToOctalCodeDialog.exec(); + if (dialogReturn == QDialog::Accepted && !pasteToOctalCodeDialog.textValue().isEmpty()) { + // we got an octalCode to paste to... + QString locationToPaste = pasteToOctalCodeDialog.textValue(); + unsigned char* octalCodeDestination = hexStringToOctalCode(locationToPaste); + + // check to see if it was a legit octcode... + if (locationToPaste == octalCodeToHexString(octalCodeDestination)) { + Application::getInstance()->pasteVoxelsToOctalCode(octalCodeDestination); + } else { + qDebug() << "problem with octcode...\n"; + } + } + + sendFakeEnterEvent(); +} + void Menu::bandwidthDetails() { if (! _bandwidthDialog) { _bandwidthDialog = new BandwidthDialog(Application::getInstance()->getGLWidget(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 6e70fb44e4..7058cc1d04 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -76,6 +76,7 @@ public slots: void importSettings(); void exportSettings(); void goToUser(); + void pasteToVoxel(); private slots: void aboutApp(); @@ -212,6 +213,7 @@ namespace MenuOption { const QString Oscilloscope = "Audio Oscilloscope"; const QString Pair = "Pair"; const QString PasteVoxels = "Paste"; + const QString PasteToVoxel = "Paste to Voxel..."; const QString PipelineWarnings = "Show Render Pipeline Warnings"; const QString Preferences = "Preferences..."; const QString RandomizeVoxelColors = "Randomize Voxel TRUE Colors"; From c358b9f0fd5458e11ff339cf60c8ba63c0b48678 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 14 Nov 2013 10:19:35 -0800 Subject: [PATCH 05/28] Don't track the mouse in mirror mode. --- interface/src/Application.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 697d5d3b35..32a93a942e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2012,14 +2012,14 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); - if (!_lookatTargetAvatar) { + if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { + lookAtSpot = _myCamera.getPosition(); + + } else if (!_lookatTargetAvatar) { if (_isHoverVoxel) { // Look at the hovered voxel lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); - } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { - lookAtSpot = _myCamera.getPosition(); - } else { // Just look in direction of the mouse ray const float FAR_AWAY_STARE = TREE_SCALE; From d3d2c344e698d4f6446f97b9612637a7d565a8f1 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 14 Nov 2013 10:46:56 -0800 Subject: [PATCH 06/28] Set the head scale for other avatars. --- interface/src/avatar/Avatar.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 8e8225200d..829c4f4464 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -398,6 +398,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { headPosition = _bodyBall[BODY_BALL_HEAD_BASE].position; } _head.setPosition(headPosition); + _head.setScale(_scale); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.simulate(deltaTime, false); From f7458cf93421812a0c9ed1ea27c7fb2428501d03 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 14 Nov 2013 15:21:54 -0800 Subject: [PATCH 07/28] Fix for pupil dilation on Ryan's face. --- interface/src/renderer/FBXReader.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/interface/src/renderer/FBXReader.cpp b/interface/src/renderer/FBXReader.cpp index 46a677c516..e841780975 100644 --- a/interface/src/renderer/FBXReader.cpp +++ b/interface/src/renderer/FBXReader.cpp @@ -1234,7 +1234,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // find the clusters with which the mesh is associated - extracted.mesh.isEye = false; QVector clusterIDs; foreach (const QString& childID, childMap.values(it.key())) { foreach (const QString& clusterID, childMap.values(childID)) { @@ -1245,12 +1244,9 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) const Cluster& cluster = clusters[clusterID]; clusterIDs.append(clusterID); - QString jointID = childMap.value(clusterID); - if (jointID == jointEyeLeftID || jointID == jointEyeRightID) { - extracted.mesh.isEye = true; - } // see http://stackoverflow.com/questions/13566608/loading-skinning-information-from-fbx for a discussion // of skinning information in FBX + QString jointID = childMap.value(clusterID); fbxCluster.jointIndex = modelIDs.indexOf(jointID); if (fbxCluster.jointIndex == -1) { qDebug() << "Joint not in model list: " << jointID << "\n"; @@ -1278,16 +1274,19 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } // whether we're skinned depends on how many clusters are attached + int maxJointIndex = extracted.mesh.clusters.at(0).jointIndex; if (clusterIDs.size() > 1) { extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); + float maxWeight = 0.0f; for (int i = 0; i < clusterIDs.size(); i++) { QString clusterID = clusterIDs.at(i); const Cluster& cluster = clusters[clusterID]; - + float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { int oldIndex = cluster.indices.at(j); float weight = cluster.weights.at(j); + totalWeight += weight; for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); it != extracted.newIndices.end() && it.key() == oldIndex; it++) { glm::vec4& weights = extracted.mesh.clusterWeights[it.value()]; @@ -1302,8 +1301,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) } } } + if (totalWeight > maxWeight) { + maxWeight = totalWeight; + maxJointIndex = extracted.mesh.clusters.at(i).jointIndex; + } } } + extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); // extract spring edges, connections if springy if (extracted.mesh.springiness > 0.0f) { From 7249e5293c58d02c6e6649c636661a6487c0d23b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 15 Nov 2013 10:17:52 -0800 Subject: [PATCH 08/28] Added a slider in the preferences to control the amount of Faceshift eye deflection. --- interface/src/Application.cpp | 5 ++--- interface/src/Menu.cpp | 10 ++++++++++ interface/src/Menu.h | 2 ++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 32a93a942e..628a91c69b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2030,10 +2030,9 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& // deflect using Faceshift gaze data glm::vec3 origin = _myAvatar.getHead().calculateAverageEyePosition(); float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f; - const float PITCH_SCALE = 0.25f; - const float YAW_SCALE = 0.25f; + float deflection = Menu::getInstance()->getFaceshiftEyeDeflection(); lookAtSpot = origin + _myCamera.getRotation() * glm::quat(glm::radians(glm::vec3( - _faceshift.getEstimatedEyePitch() * pitchSign * PITCH_SCALE, _faceshift.getEstimatedEyeYaw() * YAW_SCALE, 0.0f))) * + _faceshift.getEstimatedEyePitch() * pitchSign * deflection, _faceshift.getEstimatedEyeYaw() * deflection, 0.0f))) * glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin); } _myAvatar.getHead().setLookAtPosition(lookAtSpot); diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index d884f74630..69ea9d010e 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -46,12 +46,14 @@ Menu* Menu::getInstance() { } const ViewFrustumOffset DEFAULT_FRUSTUM_OFFSET = {-135.0f, 0.0f, 0.0f, 25.0f, 0.0f}; +const float DEFAULT_FACESHIFT_EYE_DEFLECTION = 0.25f; Menu::Menu() : _actionHash(), _audioJitterBufferSamples(0), _bandwidthDialog(NULL), _fieldOfView(DEFAULT_FIELD_OF_VIEW_DEGREES), + _faceshiftEyeDeflection(DEFAULT_FACESHIFT_EYE_DEFLECTION), _frustumDrawMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffset(DEFAULT_FRUSTUM_OFFSET), _voxelModeActionsGroup(NULL), @@ -512,6 +514,7 @@ void Menu::loadSettings(QSettings* settings) { _audioJitterBufferSamples = loadSetting(settings, "audioJitterBufferSamples", 0); _fieldOfView = loadSetting(settings, "fieldOfView", DEFAULT_FIELD_OF_VIEW_DEGREES); + _faceshiftEyeDeflection = loadSetting(settings, "faceshiftEyeDeflection", DEFAULT_FACESHIFT_EYE_DEFLECTION); _maxVoxels = loadSetting(settings, "maxVoxels", DEFAULT_MAX_VOXELS_PER_SYSTEM); _voxelSizeScale = loadSetting(settings, "voxelSizeScale", DEFAULT_VOXEL_SIZE_SCALE); _boundaryLevelAdjust = loadSetting(settings, "boundaryLevelAdjust", 0); @@ -540,6 +543,7 @@ void Menu::saveSettings(QSettings* settings) { settings->setValue("audioJitterBufferSamples", _audioJitterBufferSamples); settings->setValue("fieldOfView", _fieldOfView); + settings->setValue("faceshiftEyeDeflection", _faceshiftEyeDeflection); settings->setValue("maxVoxels", _maxVoxels); settings->setValue("voxelSizeScale", _voxelSizeScale); settings->setValue("boundaryLevelAdjust", _boundaryLevelAdjust); @@ -790,6 +794,10 @@ void Menu::editPreferences() { pupilDilation->setValue(applicationInstance->getAvatar()->getHead().getPupilDilation() * pupilDilation->maximum()); form->addRow("Pupil Dilation:", pupilDilation); + QSlider* faceshiftEyeDeflection = new QSlider(Qt::Horizontal); + faceshiftEyeDeflection->setValue(_faceshiftEyeDeflection * faceshiftEyeDeflection->maximum()); + form->addRow("Faceshift Eye Deflection:", faceshiftEyeDeflection); + QSpinBox* fieldOfView = new QSpinBox(); fieldOfView->setMaximum(180); fieldOfView->setMinimum(1); @@ -865,6 +873,8 @@ void Menu::editPreferences() { _fieldOfView = fieldOfView->value(); applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height()); + + _faceshiftEyeDeflection = faceshiftEyeDeflection->value() / (float)faceshiftEyeDeflection->maximum(); } sendFakeEnterEvent(); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 7058cc1d04..dd1789689b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -50,6 +50,7 @@ public: float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; } float getFieldOfView() const { return _fieldOfView; } + float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; } BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; } FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; } ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; } @@ -127,6 +128,7 @@ private: int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback BandwidthDialog* _bandwidthDialog; float _fieldOfView; /// in Degrees, doesn't apply to HMD like Oculus + float _faceshiftEyeDeflection; FrustumDrawMode _frustumDrawMode; ViewFrustumOffset _viewFrustumOffset; QActionGroup* _voxelModeActionsGroup; From 4da70cf3c88c65c24eb6ee4f58e854fb0e1147b0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 15 Nov 2013 16:45:03 -0800 Subject: [PATCH 09/28] fix to crash on deleteNotify --- libraries/voxels/src/VoxelNode.cpp | 9 ++++++++- libraries/voxels/src/VoxelNode.h | 5 +++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index d10b02b193..609d11c1e9 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -1413,25 +1413,32 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const { return distance; } +QReadWriteLock VoxelNode::_deleteHooksLock; std::vector VoxelNode::_deleteHooks; void VoxelNode::addDeleteHook(VoxelNodeDeleteHook* hook) { + _deleteHooksLock.lockForWrite(); _deleteHooks.push_back(hook); + _deleteHooksLock.unlock(); } void VoxelNode::removeDeleteHook(VoxelNodeDeleteHook* hook) { + _deleteHooksLock.lockForWrite(); for (int i = 0; i < _deleteHooks.size(); i++) { if (_deleteHooks[i] == hook) { _deleteHooks.erase(_deleteHooks.begin() + i); - return; + break; } } + _deleteHooksLock.unlock(); } void VoxelNode::notifyDeleteHooks() { + _deleteHooksLock.lockForRead(); for (int i = 0; i < _deleteHooks.size(); i++) { _deleteHooks[i]->voxelDeleted(this); } + _deleteHooksLock.unlock(); } std::vector VoxelNode::_updateHooks; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 53af7ab602..3e10a2fc7b 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -13,6 +13,8 @@ //#define SIMPLE_CHILD_ARRAY #define SIMPLE_EXTERNAL_CHILDREN +#include + #include #include "AABox.h" #include "ViewFrustum.h" @@ -239,7 +241,10 @@ private: _unknownBufferIndex : 1, _childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit + static QReadWriteLock _deleteHooksLock; static std::vector _deleteHooks; + + //static QReadWriteLock _updateHooksLock; static std::vector _updateHooks; static uint64_t _voxelNodeCount; From 1f2fe5ddee553a0a8e5772f382160dde7a4ebffe Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 15 Nov 2013 18:06:32 -0800 Subject: [PATCH 10/28] Rudimentary Sixense (Razer Hydra) support. --- interface/CMakeLists.txt | 4 ++++ interface/src/Application.cpp | 8 ++++++++ interface/src/Application.h | 4 ++++ interface/src/avatar/Hand.cpp | 2 +- 4 files changed, 17 insertions(+), 1 deletion(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 4709bf234d..6629398bf7 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -15,6 +15,7 @@ set(LEAP_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/Leap) set(MOTIONDRIVER_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/MotionDriver) set(PORTAUDIO_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/PortAudio) set(OPENCV_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/OpenCV) +set(SIXENSE_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/Sixense) set(UVCCAMERACONTROL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/UVCCameraControl) if (APPLE) @@ -95,6 +96,7 @@ find_package(Leap) find_package(MotionDriver) find_package(OpenCV) find_package(OpenNI) +find_package(Sixense) find_package(UVCCameraControl) find_package(ZLIB) @@ -125,6 +127,7 @@ include_directories( ${LEAP_INCLUDE_DIRS} ${MOTIONDRIVER_INCLUDE_DIRS} ${OPENCV_INCLUDE_DIRS} + ${SIXENSE_INCLUDE_DIRS} ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${OPENCV_INCLUDE_DIRS}") @@ -135,6 +138,7 @@ target_link_libraries( ${MOTIONDRIVER_LIBRARIES} ${OPENCV_LIBRARIES} ${ZLIB_LIBRARIES} + ${SIXENSE_LIBRARIES} ) if (APPLE) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 628a91c69b..ca56301c8e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2205,6 +2205,13 @@ void Application::updateLeap(float deltaTime) { LeapManager::nextFrame(_myAvatar); } +void Application::updateSixense() { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateSixense()"); + + _sixenseManager.update(); +} + void Application::updateSerialDevices(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()"); @@ -2412,6 +2419,7 @@ void Application::update(float deltaTime) { updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels updateHandAndTouch(deltaTime); // Update state for touch sensors updateLeap(deltaTime); // Leap finger-sensing device + updateSixense(); // Razer Hydra controllers updateSerialDevices(deltaTime); // Read serial port interface devices updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... diff --git a/interface/src/Application.h b/interface/src/Application.h index 78530ecea2..945de07303 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -50,6 +50,7 @@ #include "avatar/HandControl.h" #include "devices/Faceshift.h" #include "devices/SerialInterface.h" +#include "devices/SixenseManager.h" #include "devices/Webcam.h" #include "renderer/AmbientOcclusionEffect.h" #include "renderer/GeometryCache.h" @@ -242,6 +243,7 @@ private: glm::vec3& eyePosition); void updateHandAndTouch(float deltaTime); void updateLeap(float deltaTime); + void updateSixense(); void updateSerialDevices(float deltaTime); void updateThreads(float deltaTime); void updateMyAvatarSimulation(float deltaTime); @@ -337,6 +339,8 @@ private: Faceshift _faceshift; + SixenseManager _sixenseManager; + Camera _myCamera; // My view onto the world Camera _viewFrustumOffsetCamera; // The camera we use to sometimes show the view frustum from an offset mode Camera _mirrorCamera; // Cammera for mirror view diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 2ee8aad4ae..ae22752acb 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -264,7 +264,7 @@ void Hand::renderLeapHands() { for (size_t i = 0; i < getNumPalms(); ++i) { PalmData& palm = getPalms()[i]; if (palm.isActive()) { - const float palmThickness = 0.002f; + const float palmThickness = 0.02f; glColor4f(handColor.r, handColor.g, handColor.b, 0.25); glm::vec3 tip = palm.getPosition(); glm::vec3 root = palm.getPosition() + palm.getNormal() * palmThickness; From 9c401607b101784884e251005c6127098d8adcb8 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 15 Nov 2013 18:47:25 -0800 Subject: [PATCH 11/28] Missed the actual files. --- cmake/modules/FindSixense.cmake | 44 ++++++++++++++++++++ interface/src/devices/SixenseManager.cpp | 53 ++++++++++++++++++++++++ interface/src/devices/SixenseManager.h | 22 ++++++++++ 3 files changed, 119 insertions(+) create mode 100644 cmake/modules/FindSixense.cmake create mode 100644 interface/src/devices/SixenseManager.cpp create mode 100644 interface/src/devices/SixenseManager.h diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake new file mode 100644 index 0000000000..b8692d4fb5 --- /dev/null +++ b/cmake/modules/FindSixense.cmake @@ -0,0 +1,44 @@ +# Try to find the Sixense controller library +# +# You must provide a SIXENSE_ROOT_DIR which contains lib and include directories +# +# Once done this will define +# +# SIXENSE_FOUND - system found Sixense +# SIXENSE_INCLUDE_DIRS - the Sixense include directory +# SIXENSE_LIBRARIES - Link this to use Sixense +# +# Created on 11/15/2013 by Andrzej Kapolka +# Copyright (c) 2013 High Fidelity +# + +if (SIXENSE_LIBRARIES AND SIXENSE_INCLUDE_DIRS) + # in cache already + set(SIXENSE_FOUND TRUE) +else (SIXENSE_LIBRARIES AND SIXENSE_INCLUDE_DIRS) + find_path(SIXENSE_INCLUDE_DIRS sixense.h ${SIXENSE_ROOT_DIR}/include) + + if (APPLE) + find_library(SIXENSE_LIBRARIES libsixense.dylib ${SIXENSE_ROOT_DIR}/lib/MacOS/) + elseif (UNIX) + find_library(SIXENSE_LIBRARIES libsixense_x64.so ${SIXENSE_ROOT_DIR}/lib/UNIX/) + endif () + + if (SIXENSE_INCLUDE_DIRS AND SIXENSE_LIBRARIES) + set(SIXENSE_FOUND TRUE) + endif (SIXENSE_INCLUDE_DIRS AND SIXENSE_LIBRARIES) + + if (SIXENSE_FOUND) + if (NOT SIXENSE_FIND_QUIETLY) + message(STATUS "Found Sixense: ${SIXENSE_LIBRARIES}") + endif (NOT SIXENSE_FIND_QUIETLY) + else (SIXENSE_FOUND) + if (SIXENSE_FIND_REQUIRED) + message(FATAL_ERROR "Could not find Sixense") + endif (SIXENSE_FIND_REQUIRED) + endif (SIXENSE_FOUND) + + # show the SIXENSE_INCLUDE_DIRS and SIXENSE_LIBRARIES variables only in the advanced view + mark_as_advanced(SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) + +endif (SIXENSE_LIBRARIES AND SIXENSE_INCLUDE_DIRS) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp new file mode 100644 index 0000000000..24110da227 --- /dev/null +++ b/interface/src/devices/SixenseManager.cpp @@ -0,0 +1,53 @@ +// +// Sixense.cpp +// interface +// +// Created by Andrzej Kapolka on 11/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "sixense.h" + +#include "Application.h" +#include "SixenseManager.h" + +SixenseManager::SixenseManager() { + sixenseInit(); +} + +SixenseManager::~SixenseManager() { + sixenseExit(); +} + +void SixenseManager::update() { + if (sixenseGetNumActiveControllers() == 0) { + return; + } + Hand& hand = Application::getInstance()->getAvatar()->getHand(); + hand.getPalms().clear(); + + int maxControllers = sixenseGetMaxControllers(); + for (int i = 0; i < maxControllers; i++) { + if (!sixenseIsControllerEnabled(i)) { + continue; + } + sixenseControllerData data; + sixenseGetNewestData(i, &data); + PalmData palm(&hand); + palm.setActive(true); + glm::vec3 position(-data.pos[0], data.pos[1], -data.pos[2]); + palm.setRawPosition(position); + glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); + palm.setRawNormal(rotation * glm::vec3(0.0f, -1.0f, 0.0f)); + FingerData finger(&palm, &hand); + finger.setActive(true); + finger.setRawRootPosition(position); + finger.setRawTipPosition(position + rotation * glm::vec3(0.0f, 0.0f, 100.0f)); + palm.getFingers().clear(); + palm.getFingers().push_back(finger); + palm.getFingers().push_back(finger); + palm.getFingers().push_back(finger); + hand.getPalms().push_back(palm); + } +} + diff --git a/interface/src/devices/SixenseManager.h b/interface/src/devices/SixenseManager.h new file mode 100644 index 0000000000..90b8cf988f --- /dev/null +++ b/interface/src/devices/SixenseManager.h @@ -0,0 +1,22 @@ +// +// SixenseManager.h +// interface +// +// Created by Andrzej Kapolka on 11/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__SixenseManager__ +#define __interface__SixenseManager__ + +/// Handles interaction with the Sixense SDK (e.g., Razer Hydra). +class SixenseManager { +public: + + SixenseManager(); + ~SixenseManager(); + + void update(); +}; + +#endif /* defined(__interface__SixenseManager__) */ From 73c1ef99972bb8ffad6657ec2af6ca007d1ccb7d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Sun, 17 Nov 2013 00:01:32 -0800 Subject: [PATCH 12/28] fix macos menu placement for About, Preferences, and Quit --- interface/src/Menu.cpp | 14 ++++++++++---- interface/src/Menu.h | 4 +++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 69ea9d010e..12eef18b96 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -72,7 +72,8 @@ Menu::Menu() : MenuOption::AboutApp, 0, this, - SLOT(aboutApp())); + SLOT(aboutApp()), + QAction::AboutRole); #endif (addActionToQMenuAndActionHash(fileMenu, @@ -120,7 +121,9 @@ Menu::Menu() : MenuOption::Quit, Qt::CTRL | Qt::Key_Q, appInstance, - SLOT(quit())); + SLOT(quit()), + QAction::QuitRole); + QMenu* editMenu = addMenu("Edit"); @@ -128,7 +131,8 @@ Menu::Menu() : MenuOption::Preferences, Qt::CTRL | Qt::Key_Comma, this, - SLOT(editPreferences())); + SLOT(editPreferences()), + QAction::PreferencesRole); addDisabledActionAndSeparator(editMenu, "Voxels"); @@ -679,7 +683,8 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, const QString actionName, const QKeySequence& shortcut, const QObject* receiver, - const char* member) { + const char* member, + QAction::MenuRole role) { QAction* action; if (receiver && member) { @@ -688,6 +693,7 @@ QAction* Menu::addActionToQMenuAndActionHash(QMenu* destinationMenu, action = destinationMenu->addAction(actionName); action->setShortcut(shortcut); } + action->setMenuRole(role); _actionHash.insert(actionName, action); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index dd1789689b..928a5dfc58 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -113,7 +113,9 @@ private: const QString actionName, const QKeySequence& shortcut = 0, const QObject* receiver = NULL, - const char* member = NULL); + const char* member = NULL, + QAction::MenuRole role = QAction::NoRole); + QAction* addCheckableActionToQMenuAndActionHash(QMenu* destinationMenu, const QString actionName, const QKeySequence& shortcut = 0, From 0231ed133cae4af1ae2df74e9c62f9d3e7773a4b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 18 Nov 2013 12:09:52 -0800 Subject: [PATCH 13/28] Optional compilation for Sixense. --- cmake/modules/FindSixense.cmake | 4 ++-- interface/CMakeLists.txt | 10 ++++++++-- interface/external/Sixense/readme.txt | 11 +++++++++++ interface/src/devices/SixenseManager.cpp | 25 ++++++++++++++++++++---- 4 files changed, 42 insertions(+), 8 deletions(-) create mode 100644 interface/external/Sixense/readme.txt diff --git a/cmake/modules/FindSixense.cmake b/cmake/modules/FindSixense.cmake index b8692d4fb5..cf23b2218c 100644 --- a/cmake/modules/FindSixense.cmake +++ b/cmake/modules/FindSixense.cmake @@ -19,9 +19,9 @@ else (SIXENSE_LIBRARIES AND SIXENSE_INCLUDE_DIRS) find_path(SIXENSE_INCLUDE_DIRS sixense.h ${SIXENSE_ROOT_DIR}/include) if (APPLE) - find_library(SIXENSE_LIBRARIES libsixense.dylib ${SIXENSE_ROOT_DIR}/lib/MacOS/) + find_library(SIXENSE_LIBRARIES libsixense_x64.dylib ${SIXENSE_ROOT_DIR}/lib/osx_x64/release_dll) elseif (UNIX) - find_library(SIXENSE_LIBRARIES libsixense_x64.so ${SIXENSE_ROOT_DIR}/lib/UNIX/) + find_library(SIXENSE_LIBRARIES libsixense_x64.so ${SIXENSE_ROOT_DIR}/lib/linux_x64/release) endif () if (SIXENSE_INCLUDE_DIRS AND SIXENSE_LIBRARIES) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 6629398bf7..735989dfbf 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -108,6 +108,14 @@ if (OPENNI_FOUND AND NOT DISABLE_OPENNI) target_link_libraries(${TARGET_NAME} ${OPENNI_LIBRARIES}) endif (OPENNI_FOUND AND NOT DISABLE_OPENNI) +# likewise with Sixense library for Razer Hydra +if (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) + add_definitions(-DHAVE_SIXENSE) + include_directories(SYSTEM ${SIXENSE_INCLUDE_DIRS}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${SIXENSE_INCLUDE_DIRS}") + target_link_libraries(${TARGET_NAME} ${SIXENSE_LIBRARIES}) +endif (SIXENSE_FOUND AND NOT DISABLE_SIXENSE) + qt5_use_modules(${TARGET_NAME} Core Gui Multimedia Network OpenGL Svg WebKit WebKitWidgets) # include headers for interface and InterfaceConfig. @@ -127,7 +135,6 @@ include_directories( ${LEAP_INCLUDE_DIRS} ${MOTIONDRIVER_INCLUDE_DIRS} ${OPENCV_INCLUDE_DIRS} - ${SIXENSE_INCLUDE_DIRS} ) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${OPENCV_INCLUDE_DIRS}") @@ -138,7 +145,6 @@ target_link_libraries( ${MOTIONDRIVER_LIBRARIES} ${OPENCV_LIBRARIES} ${ZLIB_LIBRARIES} - ${SIXENSE_LIBRARIES} ) if (APPLE) diff --git a/interface/external/Sixense/readme.txt b/interface/external/Sixense/readme.txt new file mode 100644 index 0000000000..4672765b25 --- /dev/null +++ b/interface/external/Sixense/readme.txt @@ -0,0 +1,11 @@ + +Instructions for adding the Sixense driver to Interface +Andrzej Kapolka, November 18, 2013 + +NOTE: Without doing step 2, you will crash at program start time. + +1. Copy the Sixense sdk folders (lib, include) into the interface/external/Sixense folder. This readme.txt should be there as well. + +2. IMPORTANT: Copy the file interface/external/Leap/lib/libc++/libLeap.dylib to /usr/lib + +3. Delete your build directory, run cmake and build, and you should be all set. diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 24110da227..96481db4c8 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -6,20 +6,27 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "sixense.h" +#ifdef HAVE_SIXENSE + #include "sixense.h" +#endif #include "Application.h" #include "SixenseManager.h" SixenseManager::SixenseManager() { +#ifdef HAVE_SIXENSE sixenseInit(); +#endif } SixenseManager::~SixenseManager() { +#ifdef HAVE_SIXENSE sixenseExit(); +#endif } void SixenseManager::update() { +#ifdef HAVE_SIXENSE if (sixenseGetNumActiveControllers() == 0) { return; } @@ -33,21 +40,31 @@ void SixenseManager::update() { } sixenseControllerData data; sixenseGetNewestData(i, &data); + + // set palm position and normal based on Hydra position/orientation PalmData palm(&hand); palm.setActive(true); glm::vec3 position(-data.pos[0], data.pos[1], -data.pos[2]); palm.setRawPosition(position); glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); - palm.setRawNormal(rotation * glm::vec3(0.0f, -1.0f, 0.0f)); + const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); + palm.setRawNormal(rotation * PALM_VECTOR); + + // initialize the "finger" based on the direction FingerData finger(&palm, &hand); finger.setActive(true); finger.setRawRootPosition(position); - finger.setRawTipPosition(position + rotation * glm::vec3(0.0f, 0.0f, 100.0f)); + const glm::vec3 FINGER_VECTOR(0.0f, 0.0f, 100.0f); + finger.setRawTipPosition(position + rotation * FINGER_VECTOR); + + // three fingers indicates to the skeleton that we have enough data to determine direction palm.getFingers().clear(); palm.getFingers().push_back(finger); palm.getFingers().push_back(finger); palm.getFingers().push_back(finger); + hand.getPalms().push_back(palm); - } + } +#endif } From 6d9bd6d2b0e1e392c95dacd7065ada05579f8dba Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 18 Nov 2013 12:16:25 -0800 Subject: [PATCH 14/28] Gitignore additions. --- .gitignore | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b90059c479..62686287bc 100644 --- a/.gitignore +++ b/.gitignore @@ -35,5 +35,9 @@ interface/external/Leap/lib/ interface/external/Leap/samples/ interface/external/Leap/util/ +# Ignore Sixense +interface/external/Sixense/include/ +interface/external/Sixense/lib/ - +# Ignore interfaceCache for Linux users +interface/interfaceCache/ From 83d89cdc30b0beeb866f537bec6ad1b276997582 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 18 Nov 2013 12:34:38 -0800 Subject: [PATCH 15/28] Path fix for readme. --- interface/external/Sixense/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/external/Sixense/readme.txt b/interface/external/Sixense/readme.txt index 4672765b25..dd6cbdd96c 100644 --- a/interface/external/Sixense/readme.txt +++ b/interface/external/Sixense/readme.txt @@ -6,6 +6,6 @@ NOTE: Without doing step 2, you will crash at program start time. 1. Copy the Sixense sdk folders (lib, include) into the interface/external/Sixense folder. This readme.txt should be there as well. -2. IMPORTANT: Copy the file interface/external/Leap/lib/libc++/libLeap.dylib to /usr/lib +2. IMPORTANT: Copy the file interface/external/Sixense/lib/osx_x64/release_dll/libsixense_x64.dylib to /usr/lib 3. Delete your build directory, run cmake and build, and you should be all set. From f59b403103dda931b0036255c2c00b68b1fbcd2f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 18 Nov 2013 16:20:00 -0800 Subject: [PATCH 16/28] Drive avatar with Sixense joysticks and triggers. --- interface/src/avatar/Avatar.h | 4 +++- interface/src/avatar/MyAvatar.cpp | 29 ++++++++++++++---------- interface/src/avatar/MyAvatar.h | 5 ++-- interface/src/devices/SixenseManager.cpp | 19 +++++++++++++++- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 4258ce6f14..aad3e4ce72 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -100,7 +100,9 @@ enum DriveKeys { UP, DOWN, ROT_LEFT, - ROT_RIGHT, + ROT_RIGHT, + ROT_UP, + ROT_DOWN, MAX_DRIVE_KEYS }; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3ce54d7032..3343f5c920 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -27,6 +27,7 @@ using namespace std; const glm::vec3 DEFAULT_UP_DIRECTION(0.0f, 1.0f, 0.0f); const float YAW_MAG = 500.0; +const float PITCH_MAG = 100.0f; const float COLLISION_RADIUS_SCALAR = 1.2; // pertains to avatar-to-avatar collisions const float COLLISION_BALL_FORCE = 200.0; // pertains to avatar-to-avatar collisions const float COLLISION_BODY_FORCE = 30.0; // pertains to avatar-to-avatar collisions @@ -42,6 +43,7 @@ MyAvatar::MyAvatar(Node* owningNode) : _mousePressed(false), _bodyPitchDelta(0.0f), _bodyRollDelta(0.0f), + _mousePitchDelta(0.0f), _shouldJump(false), _gravity(0.0f, -1.0f, 0.0f), _distanceToNearestAvatar(std::numeric_limits::max()), @@ -57,7 +59,7 @@ MyAvatar::MyAvatar(Node* owningNode) : _moveTargetStepCounter(0) { for (int i = 0; i < MAX_DRIVE_KEYS; i++) { - _driveKeys[i] = false; + _driveKeys[i] = 0.0f; } _collisionRadius = _height * COLLISION_RADIUS_SCALE; @@ -395,8 +397,8 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea } else { if (!_leadingAvatar) { - _head.setMousePitch(pitchFromTouch); - _head.setPitch(pitchFromTouch); + _head.setMousePitch(pitchFromTouch + _mousePitchDelta); + _head.setPitch(pitchFromTouch + _mousePitchDelta); } _head.getVideoFace().clearFrame(); @@ -408,7 +410,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, RESTORE_RATE)); return; } - _head.setMousePitch(pitchFromTouch); + _head.setMousePitch(pitchFromTouch + _mousePitchDelta); if (webcam->isActive()) { estimatedPosition = webcam->getEstimatedPosition(); @@ -707,14 +709,17 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { const float THRUST_JUMP = 120.f; // Add Thrusts from keyboard - if (_driveKeys[FWD]) {_thrust += _scale * THRUST_MAG_FWD * _thrustMultiplier * deltaTime * front;} - if (_driveKeys[BACK]) {_thrust -= _scale * THRUST_MAG_BACK * _thrustMultiplier * deltaTime * front;} - if (_driveKeys[RIGHT]) {_thrust += _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right;} - if (_driveKeys[LEFT]) {_thrust -= _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right;} - if (_driveKeys[UP]) {_thrust += _scale * THRUST_MAG_UP * _thrustMultiplier * deltaTime * up;} - if (_driveKeys[DOWN]) {_thrust -= _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up;} - if (_driveKeys[ROT_RIGHT]) {_bodyYawDelta -= YAW_MAG * deltaTime;} - if (_driveKeys[ROT_LEFT]) {_bodyYawDelta += YAW_MAG * deltaTime;} + _thrust += _driveKeys[FWD] * _scale * THRUST_MAG_FWD * _thrustMultiplier * deltaTime * front; + _thrust -= _driveKeys[BACK] * _scale * THRUST_MAG_BACK * _thrustMultiplier * deltaTime * front; + _thrust += _driveKeys[RIGHT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right; + _thrust -= _driveKeys[LEFT] * _scale * THRUST_MAG_LATERAL * _thrustMultiplier * deltaTime * right; + _thrust += _driveKeys[UP] * _scale * THRUST_MAG_UP * _thrustMultiplier * deltaTime * up; + _thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up; + _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_MAG * deltaTime; + _bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_MAG * deltaTime; + const float MAX_PITCH = 90.0f; + _mousePitchDelta = min(_mousePitchDelta + _driveKeys[ROT_UP] * PITCH_MAG * deltaTime, MAX_PITCH); + _mousePitchDelta = max(_mousePitchDelta - _driveKeys[ROT_DOWN] * PITCH_MAG * deltaTime, -MAX_PITCH); // If thrust keys are being held down, slowly increase thrust to allow reaching great speeds if (_driveKeys[FWD] || _driveKeys[BACK] || _driveKeys[RIGHT] || _driveKeys[LEFT] || _driveKeys[UP] || _driveKeys[DOWN]) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 790510536f..9398a0d52d 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -54,7 +54,7 @@ public: void loadData(QSettings* settings); // Set what driving keys are being pressed to control thrust levels - void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; + void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key]; }; void jump() { _shouldJump = true; }; @@ -66,8 +66,9 @@ private: bool _mousePressed; float _bodyPitchDelta; float _bodyRollDelta; + float _mousePitchDelta; bool _shouldJump; - int _driveKeys[MAX_DRIVE_KEYS]; + float _driveKeys[MAX_DRIVE_KEYS]; glm::vec3 _gravity; float _distanceToNearestAvatar; // How close is the nearest avatar? Avatar* _interactingOther; diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 96481db4c8..fcb795eaed 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -30,7 +30,8 @@ void SixenseManager::update() { if (sixenseGetNumActiveControllers() == 0) { return; } - Hand& hand = Application::getInstance()->getAvatar()->getHand(); + MyAvatar* avatar = Application::getInstance()->getAvatar(); + Hand& hand = avatar->getHand(); hand.getPalms().clear(); int maxControllers = sixenseGetMaxControllers(); @@ -41,6 +42,22 @@ void SixenseManager::update() { sixenseControllerData data; sixenseGetNewestData(i, &data); + // drive avatar with joystick and triggers + if (data.controller_index) { + avatar->setDriveKeys(ROT_LEFT, qMax(0.0f, -data.joystick_x)); + avatar->setDriveKeys(ROT_RIGHT, qMax(0.0f, data.joystick_x)); + avatar->setDriveKeys(ROT_UP, qMax(0.0f, data.joystick_y)); + avatar->setDriveKeys(ROT_DOWN, qMax(0.0f, -data.joystick_y)); + avatar->setDriveKeys(UP, data.trigger); + + } else { + avatar->setDriveKeys(FWD, qMax(0.0f, data.joystick_y)); + avatar->setDriveKeys(BACK, qMax(0.0f, -data.joystick_y)); + avatar->setDriveKeys(LEFT, qMax(0.0f, -data.joystick_x)); + avatar->setDriveKeys(RIGHT, qMax(0.0f, data.joystick_x)); + avatar->setDriveKeys(DOWN, data.trigger); + } + // set palm position and normal based on Hydra position/orientation PalmData palm(&hand); palm.setActive(true); From 5e933b08153efe3dafb65e66d266d4aad47ec0c5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 18 Nov 2013 18:06:01 -0800 Subject: [PATCH 17/28] Working on basic Faceshift drive. --- interface/src/Menu.cpp | 2 ++ interface/src/Menu.h | 2 ++ interface/src/devices/Faceshift.cpp | 15 +++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 69ea9d010e..9f2b665af9 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -333,6 +333,7 @@ Menu::Menu() : false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); + addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FaceshiftDrive, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); QMenu* webcamOptionsMenu = developerMenu->addMenu("Webcam Options"); @@ -361,6 +362,7 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::SimulateLeapHand); addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::DisplayLeapHands, 0, true); + addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::LeapDrive, 0, false); addCheckableActionToQMenuAndActionHash(raveGloveOptionsMenu, MenuOption::TestRaveGlove); QMenu* trackingOptionsMenu = developerMenu->addMenu("Tracking Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index dd1789689b..9a2ded7154 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -172,6 +172,7 @@ namespace MenuOption { const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString FaceMode = "Cycle Face Mode"; + const QString FaceshiftDrive = "Faceshift Drive"; const QString FaceshiftTCP = "Faceshift (TCP)"; const QString FalseColorByDistance = "FALSE Color By Distance"; const QString FalseColorBySource = "FALSE Color By Source"; @@ -198,6 +199,7 @@ namespace MenuOption { const QString GoHome = "Go Home"; const QString Gravity = "Use Gravity"; const QString ParticleCloud = "Particle Cloud"; + const QString LeapDrive = "Leap Drive"; const QString LodTools = "LOD Tools"; const QString Log = "Log"; const QString Login = "Login"; diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 9a45810cbe..0e8aefd0f8 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -10,6 +10,7 @@ #include +#include "Application.h" #include "Faceshift.h" #include "Menu.h" #include "Util.h" @@ -80,6 +81,20 @@ void Faceshift::update() { } _estimatedEyePitch = eulers.x - _longTermAverageEyePitch; _estimatedEyeYaw = eulers.y - _longTermAverageEyeYaw; + + // if Faceshift drive is enabled, set the avatar drive based on the head position + if (!Menu::getInstance()->isOptionChecked(MenuOption::FaceshiftDrive)) { + return; + } + MyAvatar* avatar = Application::getInstance()->getAvatar(); + const float DRIVE_SCALE = 1.0f; + const float DEAD_ZONE = 0.1f; + avatar->setDriveKeys(FWD, qMax(0.0f, -_headTranslation.z * DRIVE_SCALE - DEAD_ZONE)); + avatar->setDriveKeys(BACK, qMax(0.0f, _headTranslation.z * DRIVE_SCALE - DEAD_ZONE)); + avatar->setDriveKeys(LEFT, qMax(0.0f, -_headTranslation.x * DRIVE_SCALE - DEAD_ZONE)); + avatar->setDriveKeys(RIGHT, qMax(0.0f, _headTranslation.x * DRIVE_SCALE - DEAD_ZONE)); + avatar->setDriveKeys(UP, qMax(0.0f, _headTranslation.y * DRIVE_SCALE - DEAD_ZONE)); + avatar->setDriveKeys(DOWN, qMax(0.0f, -_headTranslation.y * DRIVE_SCALE - DEAD_ZONE)); } void Faceshift::reset() { From df8fbf8f72c468b88794436fd293a338d80816ca Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 11:09:02 -0800 Subject: [PATCH 18/28] More general, angle-driven form of driving based on lean. --- interface/src/Menu.cpp | 2 +- interface/src/Menu.h | 2 +- interface/src/avatar/MyAvatar.cpp | 24 +++++++++++++++++++++--- interface/src/devices/Faceshift.cpp | 14 -------------- 4 files changed, 23 insertions(+), 19 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 9f2b665af9..647b387332 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -243,6 +243,7 @@ Menu::Menu() : MenuOption::TurnWithHead, 0, true); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::MoveWithLean, 0, false); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HeadMouse, 0, false); @@ -333,7 +334,6 @@ Menu::Menu() : false, appInstance->getFaceshift(), SLOT(setTCPEnabled(bool))); - addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::FaceshiftDrive, 0, false); addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true); QMenu* webcamOptionsMenu = developerMenu->addMenu("Webcam Options"); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 9a2ded7154..d35deb3500 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -172,7 +172,6 @@ namespace MenuOption { const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; const QString HeadMouse = "Head Mouse"; const QString FaceMode = "Cycle Face Mode"; - const QString FaceshiftDrive = "Faceshift Drive"; const QString FaceshiftTCP = "Faceshift (TCP)"; const QString FalseColorByDistance = "FALSE Color By Distance"; const QString FalseColorBySource = "FALSE Color By Source"; @@ -207,6 +206,7 @@ namespace MenuOption { const QString LookAtVectors = "Look-at Vectors"; const QString LowRes = "Lower Resolution While Moving"; const QString Mirror = "Mirror"; + const QString MoveWithLean = "Move with Lean"; const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString NudgeVoxels = "Nudge"; const QString OcclusionCulling = "Occlusion Culling"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3343f5c920..98394747c7 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -446,12 +446,30 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea _head.setRoll(estimatedRotation.z * AVATAR_HEAD_ROLL_MAGNIFY); // Update torso lean distance based on accelerometer data - const float TORSO_LENGTH = _scale * 0.5f; + const float TORSO_LENGTH = 0.5f; + glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f); const float MAX_LEAN = 45.0f; - _head.setLeanSideways(glm::clamp(glm::degrees(atanf(estimatedPosition.x * _leanScale / TORSO_LENGTH)), + _head.setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / relativePosition.y)), -MAX_LEAN, MAX_LEAN)); - _head.setLeanForward(glm::clamp(glm::degrees(atanf(estimatedPosition.z * _leanScale / TORSO_LENGTH)), + _head.setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / relativePosition.y)), -MAX_LEAN, MAX_LEAN)); + + // if Faceshift drive is enabled, set the avatar drive based on the head position + if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { + return; + } + const float ANGULAR_DRIVE_SCALE = 0.1f; + const float ANGULAR_DEAD_ZONE = 0.5f; + setDriveKeys(FWD, qMax(0.0f, _head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); + setDriveKeys(BACK, qMax(0.0f, -_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); + setDriveKeys(LEFT, qMax(0.0f, _head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); + setDriveKeys(RIGHT, qMax(0.0f, -_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); + + const float LINEAR_DRIVE_SCALE = 10.0f; + const float LINEAR_DEAD_ZONE = 0.1f; + float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; + setDriveKeys(UP, qMax(0.0f, torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE)); + setDriveKeys(DOWN, qMax(0.0f, -torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE)); } static TextRenderer* textRenderer() { diff --git a/interface/src/devices/Faceshift.cpp b/interface/src/devices/Faceshift.cpp index 0e8aefd0f8..6264ac26b5 100644 --- a/interface/src/devices/Faceshift.cpp +++ b/interface/src/devices/Faceshift.cpp @@ -81,20 +81,6 @@ void Faceshift::update() { } _estimatedEyePitch = eulers.x - _longTermAverageEyePitch; _estimatedEyeYaw = eulers.y - _longTermAverageEyeYaw; - - // if Faceshift drive is enabled, set the avatar drive based on the head position - if (!Menu::getInstance()->isOptionChecked(MenuOption::FaceshiftDrive)) { - return; - } - MyAvatar* avatar = Application::getInstance()->getAvatar(); - const float DRIVE_SCALE = 1.0f; - const float DEAD_ZONE = 0.1f; - avatar->setDriveKeys(FWD, qMax(0.0f, -_headTranslation.z * DRIVE_SCALE - DEAD_ZONE)); - avatar->setDriveKeys(BACK, qMax(0.0f, _headTranslation.z * DRIVE_SCALE - DEAD_ZONE)); - avatar->setDriveKeys(LEFT, qMax(0.0f, -_headTranslation.x * DRIVE_SCALE - DEAD_ZONE)); - avatar->setDriveKeys(RIGHT, qMax(0.0f, _headTranslation.x * DRIVE_SCALE - DEAD_ZONE)); - avatar->setDriveKeys(UP, qMax(0.0f, _headTranslation.y * DRIVE_SCALE - DEAD_ZONE)); - avatar->setDriveKeys(DOWN, qMax(0.0f, -_headTranslation.y * DRIVE_SCALE - DEAD_ZONE)); } void Faceshift::reset() { From 1e7866ad0217af4298232a940503a0c4d9f3b657 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 11:51:32 -0800 Subject: [PATCH 19/28] Clamped values, adjusted them. --- interface/src/avatar/MyAvatar.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 98394747c7..9c60836040 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -459,17 +459,19 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea return; } const float ANGULAR_DRIVE_SCALE = 0.1f; - const float ANGULAR_DEAD_ZONE = 0.5f; - setDriveKeys(FWD, qMax(0.0f, _head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); - setDriveKeys(BACK, qMax(0.0f, -_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); - setDriveKeys(LEFT, qMax(0.0f, _head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); - setDriveKeys(RIGHT, qMax(0.0f, -_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE)); - - const float LINEAR_DRIVE_SCALE = 10.0f; - const float LINEAR_DEAD_ZONE = 0.1f; - float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; - setDriveKeys(UP, qMax(0.0f, torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE)); - setDriveKeys(DOWN, qMax(0.0f, -torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE)); + const float ANGULAR_DEAD_ZONE = 0.3f; + setDriveKeys(FWD, glm::clamp(-_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + setDriveKeys(BACK, glm::clamp(_head.getLeanForward() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + setDriveKeys(LEFT, glm::clamp(_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + setDriveKeys(RIGHT, glm::clamp(-_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + + // only consider going up if we're not going in any of the four horizontal directions + if (_driveKeys[FWD] == 0.0f && _driveKeys[BACK] == 0 && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { + const float LINEAR_DRIVE_SCALE = 5.0f; + const float LINEAR_DEAD_ZONE = 0.95f; + float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; + setDriveKeys(UP, glm::clamp(torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + } } static TextRenderer* textRenderer() { From 3d82fe65b46e03ce305fc0b038a82287d1cbe807 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 11:53:57 -0800 Subject: [PATCH 20/28] Forgot this part. --- interface/src/avatar/MyAvatar.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 9c60836040..7ca01b65b1 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -449,9 +449,9 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea const float TORSO_LENGTH = 0.5f; glm::vec3 relativePosition = estimatedPosition - glm::vec3(0.0f, -TORSO_LENGTH, 0.0f); const float MAX_LEAN = 45.0f; - _head.setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / relativePosition.y)), + _head.setLeanSideways(glm::clamp(glm::degrees(atanf(relativePosition.x * _leanScale / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); - _head.setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / relativePosition.y)), + _head.setLeanForward(glm::clamp(glm::degrees(atanf(relativePosition.z * _leanScale / TORSO_LENGTH)), -MAX_LEAN, MAX_LEAN)); // if Faceshift drive is enabled, set the avatar drive based on the head position From ced1fca2e43c5b54a6f0b121de12afd6623b48ff Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 11:57:01 -0800 Subject: [PATCH 21/28] Missed another spot. --- interface/src/avatar/MyAvatar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 7ca01b65b1..3106bb4b34 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -466,7 +466,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea setDriveKeys(RIGHT, glm::clamp(-_head.getLeanSideways() * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); // only consider going up if we're not going in any of the four horizontal directions - if (_driveKeys[FWD] == 0.0f && _driveKeys[BACK] == 0 && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { + if (_driveKeys[FWD] == 0.0f && _driveKeys[BACK] == 0.0f && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { const float LINEAR_DRIVE_SCALE = 5.0f; const float LINEAR_DEAD_ZONE = 0.95f; float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; From bc523092babd0ee6457bf578bf5866797aa8d06e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 11:59:25 -0800 Subject: [PATCH 22/28] Sniffing glue, wrong week, etc. --- interface/src/avatar/MyAvatar.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 3106bb4b34..e754054fec 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -471,6 +471,9 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea const float LINEAR_DEAD_ZONE = 0.95f; float torsoDelta = glm::length(relativePosition) - TORSO_LENGTH; setDriveKeys(UP, glm::clamp(torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + + } else { + setDriveKeys(UP, 0.0f); } } From 38c2abd6d89696ca885acab0e048f2747a2b70c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 15:10:02 -0800 Subject: [PATCH 23/28] First stab at Leap driving. --- interface/src/Application.cpp | 3 +- interface/src/devices/LeapManager.cpp | 84 +++++++++++++++++++++++++-- interface/src/devices/LeapManager.h | 4 +- 3 files changed, 84 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ca56301c8e..08a4e96da6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2202,7 +2202,7 @@ void Application::updateLeap(float deltaTime) { LeapManager::enableFakeFingers(Menu::getInstance()->isOptionChecked(MenuOption::SimulateLeapHand)); _myAvatar.getHand().setRaveGloveActive(Menu::getInstance()->isOptionChecked(MenuOption::TestRaveGlove)); - LeapManager::nextFrame(_myAvatar); + LeapManager::nextFrame(); } void Application::updateSixense() { @@ -4100,6 +4100,7 @@ void Application::resetSensors() { } _webcam.reset(); _faceshift.reset(); + LeapManager::reset(); QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); _myTransmitter.resetLevels(); diff --git a/interface/src/devices/LeapManager.cpp b/interface/src/devices/LeapManager.cpp index c3dd993c16..adb14d41a0 100644 --- a/interface/src/devices/LeapManager.cpp +++ b/interface/src/devices/LeapManager.cpp @@ -6,12 +6,16 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "LeapManager.h" -#include "avatar/Avatar.h" -#include #include // needed for RTLD_LAZY + #include +#include + +#include "Application.h" +#include "LeapManager.h" +#include "Menu.h" + // Uncomment the next line to use Leap-smoothed stabilized (slower) data. //#define USE_STABILIZED_DATA @@ -19,6 +23,7 @@ bool LeapManager::_libraryExists = false; bool LeapManager::_doFakeFingers = false; Leap::Controller* LeapManager::_controller = NULL; HifiLeapListener* LeapManager::_listener = NULL; +glm::vec3 LeapManager::_baseDrivePosition; class HifiLeapListener : public Leap::Listener { public: @@ -44,6 +49,25 @@ void LeapManager::initialize() { #endif } +static PalmData* getRightmostPalm() { + PalmData* rightmostPalm = NULL; + Hand& hand = Application::getInstance()->getAvatar()->getHand(); + for (int i = 0; i < hand.getNumPalms(); i++) { + PalmData* palm = &hand.getPalms()[i]; + if (palm->isActive() && (rightmostPalm == NULL || palm->getRawPosition().x > rightmostPalm->getRawPosition().x)) { + rightmostPalm = palm; + } + } + return rightmostPalm; +} + +void LeapManager::reset() { + PalmData* rightmostPalm = getRightmostPalm(); + if (rightmostPalm != NULL) { + _baseDrivePosition = rightmostPalm->getRawPosition(); + } +} + void LeapManager::terminate() { delete _listener; delete _controller; @@ -51,9 +75,10 @@ void LeapManager::terminate() { _controller = NULL; } -void LeapManager::nextFrame(Avatar& avatar) { +void LeapManager::nextFrame() { // Apply the frame data directly to the avatar. - Hand& hand = avatar.getHand(); + MyAvatar* avatar = Application::getInstance()->getAvatar(); + Hand& hand = avatar->getHand(); // If we actually get valid Leap data, this will be set to true; bool gotRealData = false; @@ -244,6 +269,55 @@ void LeapManager::nextFrame(Avatar& avatar) { } } hand.updateFingerTrails(); + + // if Leap drive is enabled, drive avatar based on Leap input + if (!Menu::getInstance()->isOptionChecked(MenuOption::LeapDrive)) { + return; + } + glm::vec3 relativePosition; + glm::vec3 eulerAngles; + PalmData* rightmostPalm = getRightmostPalm(); + if (rightmostPalm != NULL) { + relativePosition = rightmostPalm->getRawPosition() - _baseDrivePosition; + + glm::vec3 directionSum; + int activeFingerCount = 0; + for (int i = 0; i < rightmostPalm->getNumFingers(); i++) { + FingerData& finger = rightmostPalm->getFingers()[i]; + glm::vec3 fingerVector = finger.getTipRawPosition() - rightmostPalm->getRawPosition(); + if (finger.isActive() && glm::length(fingerVector) > EPSILON) { + directionSum += glm::normalize(fingerVector); + activeFingerCount++; + } + } + const int MIN_DIRECTION_FINGER_COUNT = 3; + glm::vec3 right; + if (activeFingerCount >= MIN_DIRECTION_FINGER_COUNT) { + right = glm::normalize(glm::cross(glm::normalize(directionSum), -rightmostPalm->getRawNormal())); + + } else { + right = glm::normalize(glm::cross(IDENTITY_FRONT, -rightmostPalm->getRawNormal())); + } + eulerAngles = safeEulerAngles(glm::quat_cast(glm::mat3(right, -rightmostPalm->getRawNormal(), + glm::cross(right, -rightmostPalm->getRawNormal())))); + } + const float LINEAR_DRIVE_SCALE = 0.1f; + const float LINEAR_DEAD_ZONE = 0.3f; + avatar->setDriveKeys(FWD, glm::clamp(-relativePosition.z * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(BACK, glm::clamp(relativePosition.z * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(LEFT, glm::clamp(-relativePosition.x * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(RIGHT, glm::clamp(relativePosition.x * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(UP, glm::clamp(relativePosition.y * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(DOWN, glm::clamp(-relativePosition.y * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + + const float ANGULAR_DRIVE_SCALE = 0.1f; + const float ANGULAR_DEAD_ZONE = 0.3f; + avatar->setDriveKeys(ROT_LEFT, glm::clamp(glm::max(eulerAngles.y, eulerAngles.z) * ANGULAR_DRIVE_SCALE - + ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(ROT_RIGHT, glm::clamp(glm::max(-eulerAngles.y, -eulerAngles.z) * ANGULAR_DRIVE_SCALE - + ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(ROT_UP, glm::clamp(eulerAngles.x * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); + avatar->setDriveKeys(ROT_DOWN, glm::clamp(-eulerAngles.x * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); } void LeapManager::enableFakeFingers(bool enable) { diff --git a/interface/src/devices/LeapManager.h b/interface/src/devices/LeapManager.h index 11dbefe849..4544d5afcf 100755 --- a/interface/src/devices/LeapManager.h +++ b/interface/src/devices/LeapManager.h @@ -21,7 +21,7 @@ namespace Leap { class LeapManager { public: - static void nextFrame(Avatar& avatar); // called once per frame to get new Leap data + static void nextFrame(); // called once per frame to get new Leap data static bool controllersExist(); // Returns true if there's at least one active Leap plugged in static void enableFakeFingers(bool enable); // put fake data in if there's no Leap plugged in static const std::vector& getFingerTips(); @@ -30,6 +30,7 @@ public: static const std::vector& getHandNormals(); static std::string statusString(); static void initialize(); + static void reset(); static void terminate(); private: @@ -37,6 +38,7 @@ private: static bool _doFakeFingers; static Leap::Controller* _controller; static HifiLeapListener* _listener; + static glm::vec3 _baseDrivePosition; }; #endif /* defined(__hifi__LeapManager__) */ From 80e6606dd24974af20c17cafd53bb7095891199e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 15:31:04 -0800 Subject: [PATCH 24/28] Adjusted constants, added reasonable starting base position. --- interface/src/devices/LeapManager.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/devices/LeapManager.cpp b/interface/src/devices/LeapManager.cpp index adb14d41a0..b0f6f6077f 100644 --- a/interface/src/devices/LeapManager.cpp +++ b/interface/src/devices/LeapManager.cpp @@ -23,7 +23,7 @@ bool LeapManager::_libraryExists = false; bool LeapManager::_doFakeFingers = false; Leap::Controller* LeapManager::_controller = NULL; HifiLeapListener* LeapManager::_listener = NULL; -glm::vec3 LeapManager::_baseDrivePosition; +glm::vec3 LeapManager::_baseDrivePosition(0.0f, 150.0f, 0.0f); // experimentally derived class HifiLeapListener : public Leap::Listener { public: @@ -301,8 +301,8 @@ void LeapManager::nextFrame() { eulerAngles = safeEulerAngles(glm::quat_cast(glm::mat3(right, -rightmostPalm->getRawNormal(), glm::cross(right, -rightmostPalm->getRawNormal())))); } - const float LINEAR_DRIVE_SCALE = 0.1f; - const float LINEAR_DEAD_ZONE = 0.3f; + const float LINEAR_DRIVE_SCALE = 0.01f; + const float LINEAR_DEAD_ZONE = 0.25f; avatar->setDriveKeys(FWD, glm::clamp(-relativePosition.z * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); avatar->setDriveKeys(BACK, glm::clamp(relativePosition.z * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); avatar->setDriveKeys(LEFT, glm::clamp(-relativePosition.x * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); @@ -310,8 +310,8 @@ void LeapManager::nextFrame() { avatar->setDriveKeys(UP, glm::clamp(relativePosition.y * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); avatar->setDriveKeys(DOWN, glm::clamp(-relativePosition.y * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); - const float ANGULAR_DRIVE_SCALE = 0.1f; - const float ANGULAR_DEAD_ZONE = 0.3f; + const float ANGULAR_DRIVE_SCALE = 0.05f; + const float ANGULAR_DEAD_ZONE = 0.75f; avatar->setDriveKeys(ROT_LEFT, glm::clamp(glm::max(eulerAngles.y, eulerAngles.z) * ANGULAR_DRIVE_SCALE - ANGULAR_DEAD_ZONE, 0.0f, 1.0f)); avatar->setDriveKeys(ROT_RIGHT, glm::clamp(glm::max(-eulerAngles.y, -eulerAngles.z) * ANGULAR_DRIVE_SCALE - From 69b5b81f349f0916fd15db9176fc3f9772d26ec4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 16:31:24 -0800 Subject: [PATCH 25/28] Limit combined pitch. --- interface/src/avatar/MyAvatar.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e754054fec..5cb2ba491f 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -370,6 +370,8 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { } +const float MAX_PITCH = 90.0f; + // Update avatar head rotation with sensor data void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHead) { Faceshift* faceshift = Application::getInstance()->getFaceshift(); @@ -377,6 +379,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea Webcam* webcam = Application::getInstance()->getWebcam(); glm::vec3 estimatedPosition, estimatedRotation; + float combinedPitch = glm::clamp(pitchFromTouch + _mousePitchDelta, -MAX_PITCH, MAX_PITCH); if (faceshift->isActive()) { estimatedPosition = faceshift->getHeadTranslation(); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); @@ -397,8 +400,8 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea } else { if (!_leadingAvatar) { - _head.setMousePitch(pitchFromTouch + _mousePitchDelta); - _head.setPitch(pitchFromTouch + _mousePitchDelta); + _head.setMousePitch(combinedPitch); + _head.setPitch(combinedPitch); } _head.getVideoFace().clearFrame(); @@ -410,7 +413,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(float pitchFromTouch, bool turnWithHea _head.setLeanForward(glm::mix(_head.getLeanForward(), 0.0f, RESTORE_RATE)); return; } - _head.setMousePitch(pitchFromTouch + _mousePitchDelta); + _head.setMousePitch(combinedPitch); if (webcam->isActive()) { estimatedPosition = webcam->getEstimatedPosition(); @@ -740,7 +743,6 @@ void MyAvatar::updateThrust(float deltaTime, Transmitter * transmitter) { _thrust -= _driveKeys[DOWN] * _scale * THRUST_MAG_DOWN * _thrustMultiplier * deltaTime * up; _bodyYawDelta -= _driveKeys[ROT_RIGHT] * YAW_MAG * deltaTime; _bodyYawDelta += _driveKeys[ROT_LEFT] * YAW_MAG * deltaTime; - const float MAX_PITCH = 90.0f; _mousePitchDelta = min(_mousePitchDelta + _driveKeys[ROT_UP] * PITCH_MAG * deltaTime, MAX_PITCH); _mousePitchDelta = max(_mousePitchDelta - _driveKeys[ROT_DOWN] * PITCH_MAG * deltaTime, -MAX_PITCH); From 4e952b0f994d3e0c6cfa3ed92800e34b46dae0a5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 19 Nov 2013 16:40:29 -0800 Subject: [PATCH 26/28] Clamp pitch from touch when adjusting it. --- interface/src/Application.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 08a4e96da6..8481ba7908 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2189,8 +2189,10 @@ void Application::updateHandAndTouch(float deltaTime) { float TOUCH_YAW_SCALE = -0.25f; float TOUCH_PITCH_SCALE = -12.5f; float FIXED_TOUCH_TIMESTEP = 0.016f; + const float MAX_PITCH = 90.0f; _yawFromTouch += ((_touchAvgX - _lastTouchAvgX) * TOUCH_YAW_SCALE * FIXED_TOUCH_TIMESTEP); - _pitchFromTouch += ((_touchAvgY - _lastTouchAvgY) * TOUCH_PITCH_SCALE * FIXED_TOUCH_TIMESTEP); + _pitchFromTouch = glm::clamp(_pitchFromTouch + (_touchAvgY - _lastTouchAvgY) * TOUCH_PITCH_SCALE * + FIXED_TOUCH_TIMESTEP, -MAX_PITCH, MAX_PITCH); _lastTouchAvgX = _touchAvgX; _lastTouchAvgY = _touchAvgY; } From 6881d9fb363457cd60a243e8f808b93942bf24b8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 19 Nov 2013 22:57:42 -0800 Subject: [PATCH 27/28] fix to crash in client side VoxelSceneStats crash --- interface/src/Application.cpp | 22 +---- interface/src/Application.h | 3 + interface/src/ui/VoxelStatsDialog.cpp | 3 + libraries/voxels/src/VoxelSceneStats.cpp | 115 +++++++++++++++++++++++ libraries/voxels/src/VoxelSceneStats.h | 6 ++ 5 files changed, 132 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 628a91c69b..385e7bc8af 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -4188,9 +4188,11 @@ void Application::nodeKilled(Node* node) { } // also clean up scene stats for that server + _voxelSceneStatsLock.lockForWrite(); if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { _voxelServerSceneStats.erase(nodeUUID); } + _voxelSceneStatsLock.unlock(); } else if (node->getLinkedData() == _lookatTargetAvatar) { _lookatTargetAvatar = NULL; } @@ -4211,27 +4213,13 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng QUuid nodeUUID = voxelServer->getUUID(); // now that we know the node ID, let's add these stats to the stats for that node... + _voxelSceneStatsLock.lockForWrite(); if (_voxelServerSceneStats.find(nodeUUID) != _voxelServerSceneStats.end()) { - VoxelSceneStats& oldStats = _voxelServerSceneStats[nodeUUID]; - - // this if construct is a little strange because we aren't quite using it yet. But - // we want to keep this logic in here for now because we plan to use it soon to determine - // additional network optimization states and better rate control - if (!oldStats.isMoving() && temp.isMoving()) { - // we think we are starting to move - _voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength); - } else if (oldStats.isMoving() && !temp.isMoving()) { - // we think we are done moving - _voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength); - } else if (!oldStats.isMoving() && !temp.isMoving()) { - // we think we are still not moving - } else { - // we think we are still moving - } - + _voxelServerSceneStats[nodeUUID].unpackFromMessage(messageData, messageLength); } else { _voxelServerSceneStats[nodeUUID] = temp; } + _voxelSceneStatsLock.unlock(); VoxelPositionSize rootDetails; voxelDetailsForCode(temp.getJurisdictionRoot(), rootDetails); diff --git a/interface/src/Application.h b/interface/src/Application.h index 78530ecea2..21e3479288 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -136,6 +136,8 @@ public: Swatch* getSwatch() { return &_swatch; } QMainWindow* getWindow() { return _window; } NodeToVoxelSceneStats* getVoxelSceneStats() { return &_voxelServerSceneStats; } + void lockVoxelSceneStats() { _voxelSceneStatsLock.lockForRead(); } + void unlockVoxelSceneStats() { _voxelSceneStatsLock.unlock(); } QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } GeometryCache* getGeometryCache() { return &_geometryCache; } @@ -454,6 +456,7 @@ private: NodeToJurisdictionMap _voxelServerJurisdictions; NodeToVoxelSceneStats _voxelServerSceneStats; + QReadWriteLock _voxelSceneStatsLock; std::vector _voxelFades; }; diff --git a/interface/src/ui/VoxelStatsDialog.cpp b/interface/src/ui/VoxelStatsDialog.cpp index ab1371f53f..ff082e4b02 100644 --- a/interface/src/ui/VoxelStatsDialog.cpp +++ b/interface/src/ui/VoxelStatsDialog.cpp @@ -154,6 +154,8 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) { unsigned long totalNodes = 0; unsigned long totalInternal = 0; unsigned long totalLeaves = 0; + + Application::getInstance()->lockVoxelSceneStats(); NodeToVoxelSceneStats* sceneStats = Application::getInstance()->getVoxelSceneStats(); for(NodeToVoxelSceneStatsIterator i = sceneStats->begin(); i != sceneStats->end(); i++) { //const QUuid& uuid = i->first; @@ -176,6 +178,7 @@ void VoxelStatsDialog::paintEvent(QPaintEvent* event) { sendingMode << "S"; } } + Application::getInstance()->unlockVoxelSceneStats(); sendingMode << " - " << serverCount << " servers"; if (movingServerCount > 0) { sendingMode << " "; diff --git a/libraries/voxels/src/VoxelSceneStats.cpp b/libraries/voxels/src/VoxelSceneStats.cpp index cce7d7d7b3..fa5968a6e3 100644 --- a/libraries/voxels/src/VoxelSceneStats.cpp +++ b/libraries/voxels/src/VoxelSceneStats.cpp @@ -28,6 +28,97 @@ VoxelSceneStats::VoxelSceneStats() : _isStarted = false; } +// copy constructor +VoxelSceneStats::VoxelSceneStats(const VoxelSceneStats& other) : +_jurisdictionRoot(NULL) { + copyFromOther(other); +} + +// copy assignment +VoxelSceneStats& VoxelSceneStats::operator=(const VoxelSceneStats& other) { + copyFromOther(other); + return *this; +} + +void VoxelSceneStats::copyFromOther(const VoxelSceneStats& other) { + _totalEncodeTime = other._totalEncodeTime; + _encodeStart = other._encodeStart; + + _packets = other._packets; + _bytes = other._bytes; + _passes = other._passes; + + _totalVoxels = other._totalVoxels; + _totalInternal = other._totalInternal; + _totalLeaves = other._totalLeaves; + + _traversed = other._traversed; + _internal = other._internal; + _leaves = other._leaves; + + _skippedDistance = other._skippedDistance; + _internalSkippedDistance = other._internalSkippedDistance; + _leavesSkippedDistance = other._leavesSkippedDistance; + + _skippedOutOfView = other._skippedOutOfView; + _internalSkippedOutOfView = other._internalSkippedOutOfView; + _leavesSkippedOutOfView = other._leavesSkippedOutOfView; + + _skippedWasInView = other._skippedWasInView; + _internalSkippedWasInView = other._internalSkippedWasInView; + _leavesSkippedWasInView = other._leavesSkippedWasInView; + + _skippedNoChange = other._skippedNoChange; + _internalSkippedNoChange = other._internalSkippedNoChange; + _leavesSkippedNoChange = other._leavesSkippedNoChange; + + _skippedOccluded = other._skippedOccluded; + _internalSkippedOccluded = other._internalSkippedOccluded; + _leavesSkippedOccluded = other._leavesSkippedOccluded; + + _colorSent = other._colorSent; + _internalColorSent = other._internalColorSent; + _leavesColorSent = other._leavesColorSent; + + _didntFit = other._didntFit; + _internalDidntFit = other._internalDidntFit; + _leavesDidntFit = other._leavesDidntFit; + + _colorBitsWritten = other._colorBitsWritten; + _existsBitsWritten = other._existsBitsWritten; + _existsInPacketBitsWritten = other._existsInPacketBitsWritten; + _treesRemoved = other._treesRemoved; + + // before copying the jurisdictions, delete any current values... + if (_jurisdictionRoot) { + delete[] _jurisdictionRoot; + _jurisdictionRoot = NULL; + } + for (int i=0; i < _jurisdictionEndNodes.size(); i++) { + if (_jurisdictionEndNodes[i]) { + delete[] _jurisdictionEndNodes[i]; + } + } + _jurisdictionEndNodes.clear(); + + // Now copy the values from the other + if (other._jurisdictionRoot) { + int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(other._jurisdictionRoot)); + _jurisdictionRoot = new unsigned char[bytes]; + memcpy(_jurisdictionRoot, other._jurisdictionRoot, bytes); + } + for (int i=0; i < other._jurisdictionEndNodes.size(); i++) { + unsigned char* endNodeCode = other._jurisdictionEndNodes[i]; + if (endNodeCode) { + int bytes = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(endNodeCode)); + unsigned char* endNodeCodeCopy = new unsigned char[bytes]; + memcpy(endNodeCodeCopy, endNodeCode, bytes); + _jurisdictionEndNodes.push_back(endNodeCodeCopy); + } + } +} + + VoxelSceneStats::~VoxelSceneStats() { reset(); } @@ -48,6 +139,15 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r delete[] _jurisdictionRoot; _jurisdictionRoot = NULL; } + // clear existing endNodes before copying new ones... + for (int i=0; i < _jurisdictionEndNodes.size(); i++) { + if (_jurisdictionEndNodes[i]) { + delete[] _jurisdictionEndNodes[i]; + } + } + _jurisdictionEndNodes.clear(); + + // setup jurisdictions if (jurisdictionMap) { unsigned char* jurisdictionRoot = jurisdictionMap->getRootOctalCode(); if (jurisdictionRoot) { @@ -56,6 +156,7 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r memcpy(_jurisdictionRoot, jurisdictionRoot, bytes); } + // copy new endNodes... for (int i=0; i < jurisdictionMap->getEndNodeCount(); i++) { unsigned char* endNodeCode = jurisdictionMap->getEndNodeOctalCode(i); if (endNodeCode) { @@ -436,6 +537,20 @@ int VoxelSceneStats::unpackFromMessage(unsigned char* sourceBuffer, int availabl memcpy(&_treesRemoved, sourceBuffer, sizeof(_treesRemoved)); sourceBuffer += sizeof(_treesRemoved); + // before allocating new juridiction, clean up existing ones + if (_jurisdictionRoot) { + delete[] _jurisdictionRoot; + _jurisdictionRoot = NULL; + } + + // clear existing endNodes before copying new ones... + for (int i=0; i < _jurisdictionEndNodes.size(); i++) { + if (_jurisdictionEndNodes[i]) { + delete[] _jurisdictionEndNodes[i]; + } + } + _jurisdictionEndNodes.clear(); + // read the root jurisdiction int bytes = 0; memcpy(&bytes, sourceBuffer, sizeof(bytes)); diff --git a/libraries/voxels/src/VoxelSceneStats.h b/libraries/voxels/src/VoxelSceneStats.h index c93633fea7..245fe430dd 100644 --- a/libraries/voxels/src/VoxelSceneStats.h +++ b/libraries/voxels/src/VoxelSceneStats.h @@ -27,6 +27,9 @@ public: ~VoxelSceneStats(); void reset(); + VoxelSceneStats(const VoxelSceneStats& other); // copy constructor + VoxelSceneStats& operator= (const VoxelSceneStats& other); // copy assignment + /// Call when beginning the computation of a scene. Initializes internal structures void sceneStarted(bool fullScene, bool moving, VoxelNode* root, JurisdictionMap* jurisdictionMap); @@ -144,6 +147,9 @@ public: unsigned long getTotalLeaves() const { return _totalLeaves; } private: + + void copyFromOther(const VoxelSceneStats& other); + bool _isReadyToSend; unsigned char _statsMessage[MAX_PACKET_SIZE]; int _statsMessageLength; From cb56ad2e2f3710f2ad2b34d3e23ca37ae790a27d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 21 Nov 2013 10:43:40 -0800 Subject: [PATCH 28/28] fix a couple of bugs in display of voxel stats on server status --- .../voxel-server-library/src/VoxelServer.cpp | 31 ++++++++++++------- .../src/VoxelServerPacketProcessor.h | 4 +-- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 16a2c38c3a..cf650117f2 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -189,17 +189,22 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { // display voxel file load time if (theServer->isInitialLoadComplete()) { - tm* voxelsLoadedAtLocal = localtime(theServer->getLoadCompleted()); - const int MAX_TIME_LENGTH = 128; - char buffer[MAX_TIME_LENGTH]; - strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtLocal); - mg_printf(connection, "Voxels Loaded At: %s", buffer); + time_t* loadCompleted = theServer->getLoadCompleted(); + if (loadCompleted) { + tm* voxelsLoadedAtLocal = localtime(loadCompleted); + const int MAX_TIME_LENGTH = 128; + char buffer[MAX_TIME_LENGTH]; + strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtLocal); + mg_printf(connection, "Voxels Loaded At: %s", buffer); - // Convert now to tm struct for UTC - tm* voxelsLoadedAtUTM = gmtime(theServer->getLoadCompleted()); - if (gmtm != NULL) { - strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtUTM); - mg_printf(connection, " [%s UTM] ", buffer); + // Convert now to tm struct for UTC + tm* voxelsLoadedAtUTM = gmtime(theServer->getLoadCompleted()); + if (gmtm != NULL) { + strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtUTM); + mg_printf(connection, " [%s UTM] ", buffer); + } + } else { + mg_printf(connection, "%s", "Voxel Persist Disabled...\r\n"); } mg_printf(connection, "%s", "\r\n"); @@ -259,7 +264,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { // display inbound packet stats mg_printf(connection, "%s", "Voxel Edit Statistics... [RESET]\r\n"); - uint64_t averageTransitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverateTransitTimePerPacket(); + uint64_t averageTransitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageTransitTimePerPacket(); uint64_t averageProcessTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageProcessTimePerPacket(); uint64_t averageLockWaitTimePerPacket = theServer->_voxelServerPacketProcessor->getAverageLockWaitTimePerPacket(); uint64_t averageProcessTimePerVoxel = theServer->_voxelServerPacketProcessor->getAverageProcessTimePerVoxel(); @@ -297,7 +302,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "\r\n Stats for sender %d uuid: %s\r\n", senderNumber, senderID.toString().toLocal8Bit().constData()); - averageTransitTimePerPacket = senderStats.getAverateTransitTimePerPacket(); + averageTransitTimePerPacket = senderStats.getAverageTransitTimePerPacket(); averageProcessTimePerPacket = senderStats.getAverageProcessTimePerPacket(); averageLockWaitTimePerPacket = senderStats.getAverageLockWaitTimePerPacket(); averageProcessTimePerVoxel = senderStats.getAverageProcessTimePerVoxel(); @@ -305,6 +310,8 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { totalVoxelsProcessed = senderStats.getTotalVoxelsProcessed(); totalPacketsProcessed = senderStats.getTotalPacketsProcessed(); + averageVoxelsPerPacket = totalPacketsProcessed == 0 ? 0 : totalVoxelsProcessed / totalPacketsProcessed; + mg_printf(connection, " Total Inbound Packets: %s packets\r\n", locale.toString((uint)totalPacketsProcessed).rightJustified(COLUMN_WIDTH, ' ').toLocal8Bit().constData()); mg_printf(connection, " Total Inbound Voxels: %s voxels\r\n", diff --git a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h index 108e101417..2408e0dd60 100644 --- a/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h +++ b/libraries/voxel-server-library/src/VoxelServerPacketProcessor.h @@ -20,7 +20,7 @@ class SingleSenderStats { public: SingleSenderStats(); - uint64_t getAverateTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } + uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } uint64_t getTotalVoxelsProcessed() const { return _totalVoxelsInPacket; } @@ -48,7 +48,7 @@ class VoxelServerPacketProcessor : public ReceivedPacketProcessor { public: VoxelServerPacketProcessor(VoxelServer* myServer); - uint64_t getAverateTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } + uint64_t getAverageTransitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalTransitTime / _totalPackets; } uint64_t getAverageProcessTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalProcessTime / _totalPackets; } uint64_t getAverageLockWaitTimePerPacket() const { return _totalPackets == 0 ? 0 : _totalLockWaitTime / _totalPackets; } uint64_t getTotalVoxelsProcessed() const { return _totalVoxelsInPacket; }