From a1ba36d5438d122796cc0d31fcf04d79eb584589 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Fri, 22 Nov 2013 20:08:44 -0800 Subject: [PATCH 01/10] Lean drive works with keys and no up/down --- interface/src/avatar/MyAvatar.cpp | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 6ec75931c1..12a6bb7f7a 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -459,13 +459,37 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { if (!Menu::getInstance()->isOptionChecked(MenuOption::MoveWithLean)) { return; } + + // Move with Lean by applying thrust proportional to leaning + glm::quat orientation = _head.getCameraOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + + const float LEAN_FWD_DEAD_ZONE = 2.f; + const float LEAN_SIDEWAYS_DEAD_ZONE = 2.f; + const float LEAN_FWD_THRUST_SCALE = 1.f; + const float LEAN_SIDEWAYS_THRUST_SCALE = 1.f; + + //printf("%.2f, %.2f\n", _head.getLeanForward(), _head.getLeanSideways()); + + if (fabs(_head.getLeanForward()) > LEAN_FWD_DEAD_ZONE) { + addThrust(front * -_head.getLeanForward() * LEAN_FWD_THRUST_SCALE); + } + if (fabs(_head.getLeanSideways()) > LEAN_SIDEWAYS_DEAD_ZONE) { + addThrust(right * -_head.getLeanSideways() * LEAN_SIDEWAYS_THRUST_SCALE); + } + +/* const float ANGULAR_DRIVE_SCALE = 0.1f; 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.0f && _driveKeys[LEFT] == 0.0f && _driveKeys[RIGHT] == 0.0f) { const float LINEAR_DRIVE_SCALE = 5.0f; @@ -476,6 +500,7 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { } else { setDriveKeys(UP, 0.0f); } + */ } static TextRenderer* textRenderer() { From 62c882b788682cd05aa1936013b098ce8bf54219 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 25 Nov 2013 09:44:40 -0800 Subject: [PATCH 02/10] Rounding numbers --- libraries/shared/src/PerfStat.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 267108f87e..cbec4806e5 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -113,20 +113,20 @@ PerformanceWarning::~PerformanceWarning() { if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; - qDebug("%s took %lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); + qDebug("%s took %.2lf seconds %s\n", _message, elapsedsec, (_alwaysDisplay ? "" : "WARNING!") ); } else { if (_suppressShortTimings) { if (elapsedmsec > 10) { - qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + qDebug("%s took %.1lf milliseconds %s\n", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } else { - qDebug("%s took %lf milliseconds %s\n", _message, elapsedmsec, + qDebug("%s took %.2lf milliseconds %s\n", _message, elapsedmsec, (_alwaysDisplay || (elapsedmsec < 10) ? "" : "WARNING!")); } } } else if (_alwaysDisplay) { - qDebug("%s took %lf milliseconds\n", _message, elapsedmsec); + qDebug("%s took %.2lf milliseconds\n", _message, elapsedmsec); } // if the caller gave us a pointer to store the running total, track it now. if (_runningTotal) { From 2cb701bce6cc751978df97069ebdc17a96c27e9d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 25 Nov 2013 17:28:33 -0800 Subject: [PATCH 03/10] Added adjustment for hydra position to user (it matters) --- interface/src/devices/SixenseManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index fcb795eaed..dfeab1f309 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -58,12 +58,20 @@ void SixenseManager::update() { avatar->setDriveKeys(DOWN, data.trigger); } - // set palm position and normal based on Hydra position/orientation + // 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]); + glm::vec3 position(data.pos[0], data.pos[1], data.pos[2]); + + // Adjust for distance between acquisition 'orb' and the user's torso + // (distance to the right of body center, distance below torso, distance behind torso) + const glm::vec3 SPHERE_TO_TORSO(-250.f, -300.f, -300.f); + position = SPHERE_TO_TORSO + position; palm.setRawPosition(position); glm::quat rotation(data.rot_quat[3], -data.rot_quat[0], data.rot_quat[1], -data.rot_quat[2]); + + // Rotate about controller + rotation = glm::angleAxis(180.0f, 0.f, 1.f, 0.f) * rotation; const glm::vec3 PALM_VECTOR(0.0f, -1.0f, 0.0f); palm.setRawNormal(rotation * PALM_VECTOR); From ec909a6c13a9e07e14d10a5cf8c737fb3892592c Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 26 Nov 2013 10:58:02 -0600 Subject: [PATCH 04/10] add a mutex lock and unlock on Menu instance creation --- interface/src/Menu.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fd942a77c1..a9c942ca39 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -36,11 +36,18 @@ Menu* Menu::_instance = NULL; Menu* Menu::getInstance() { + static QMutex menuInstanceMutex; + + // lock the menu instance mutex to make sure we don't race and create two menus and crash + menuInstanceMutex.lock(); + if (!_instance) { qDebug("First call to Menu::getInstance() - initing menu.\n"); _instance = new Menu(); } + + menuInstanceMutex.unlock(); return _instance; } From 09ca2a45db29efe9712b38e2e38e7f76d38e12e7 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 26 Nov 2013 11:25:06 -0800 Subject: [PATCH 05/10] Add local audio monitor option, tweak turning with head --- interface/src/Audio.cpp | 17 ++++---- interface/src/Audio.h | 2 + interface/src/Menu.cpp | 5 ++- interface/src/Menu.h | 3 +- interface/src/avatar/MyAvatar.cpp | 69 +++++++++++++------------------ 5 files changed, 46 insertions(+), 50 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index d3b23f273a..99bb2786e0 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -27,12 +27,8 @@ #include "Menu.h" #include "Util.h" -// Uncomment the following definition to test audio device latency by copying output to input -//#define TEST_AUDIO_LOOPBACK //#define SHOW_AUDIO_DEBUG -#define VISUALIZE_ECHO_CANCELLATION - static const int PHASE_DELAY_AT_90 = 20; static const float AMPLITUDE_RATIO_AT_90 = 0.5; static const int MIN_FLANGE_EFFECT_THRESHOLD = 600; @@ -84,11 +80,17 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - // If Mute button is pressed, clear the input buffer + // If Mute button is pressed, clear the input buffer if (_muted) { memset(inputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); } + // If local loopback enabled, copy input to output + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { + memcpy(outputLeft, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); + memcpy(outputRight, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); + } + // Add Procedural effects to input samples addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); @@ -120,7 +122,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // + 12 for 3 floats for position + float for bearing + 1 attenuation byte unsigned char dataPacket[MAX_PACKET_SIZE]; - PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio) + PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio) ? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO : PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO; @@ -360,7 +362,8 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _collisionSoundDuration(0.0f), _proceduralEffectSample(0), _heartbeatMagnitude(0.0f), - _muted(false) + _muted(false), + _localEcho(false) { outputPortAudioError(Pa_Initialize()); diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ec8ca6989c..347fb0551f 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -70,6 +70,7 @@ public: // in which case 'true' is returned - otherwise the return value is 'false'. // The results of the analysis are written to the log. bool eventuallyAnalyzePing(); + private: PaStream* _stream; @@ -109,6 +110,7 @@ private: float _heartbeatMagnitude; bool _muted; + bool _localEcho; GLuint _micTextureId; GLuint _muteTextureId; QRect _iconBounds; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index fd942a77c1..dbf4728b83 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -484,8 +484,9 @@ Menu::Menu() : addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::CoverageMapV2, Qt::SHIFT | Qt::CTRL | Qt::Key_P); QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools"); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio); - + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); + QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options"); addCheckableActionToQMenuAndActionHash(voxelProtoOptionsMenu, MenuOption::SendVoxelColors); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index db8b0ed528..aebb8f9858 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -168,7 +168,8 @@ namespace MenuOption { const QString DisplayLeapHands = "Display Leap Hands"; const QString DontRenderVoxels = "Don't call _voxels.render()"; const QString DontCallOpenGLForVoxels = "Don't call glDrawRangeElementsEXT() for Voxels"; - const QString EchoAudio = "Echo Audio"; + const QString EchoServerAudio = "Echo Server Audio"; + const QString EchoLocalAudio = "Echo Local Audio"; const QString ExportVoxels = "Export Voxels"; const QString ExtraDebugging = "Extra Debugging"; const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 76cf77775e..65670aa4f3 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -381,15 +381,18 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { if (faceshift->isActive()) { estimatedPosition = faceshift->getHeadTranslation(); estimatedRotation = safeEulerAngles(faceshift->getHeadRotation()); - // Rotate the body if the head is turned quickly + // Rotate the body if the head is turned beyond the screen if (turnWithHead) { - glm::vec3 headAngularVelocity = faceshift->getHeadAngularVelocity(); - const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.25f; - const float FACESHIFT_MIN_YAW_TURN = 10.f; - const float FACESHIFT_MAX_YAW_TURN = 30.f; + const float FACESHIFT_YAW_TURN_SENSITIVITY = 0.5f; + const float FACESHIFT_MIN_YAW_TURN = 15.f; + const float FACESHIFT_MAX_YAW_TURN = 50.f; if ( (fabs(estimatedRotation.y) > FACESHIFT_MIN_YAW_TURN) && (fabs(estimatedRotation.y) < FACESHIFT_MAX_YAW_TURN) ) { - _bodyYawDelta += estimatedRotation.y * FACESHIFT_YAW_TURN_SENSITIVITY; + if (estimatedRotation.y > 0.f) { + _bodyYawDelta += (estimatedRotation.y - FACESHIFT_MIN_YAW_TURN) * FACESHIFT_YAW_TURN_SENSITIVITY; + } else { + _bodyYawDelta += (estimatedRotation.y + FACESHIFT_MIN_YAW_TURN) * FACESHIFT_YAW_TURN_SENSITIVITY; + } } } } else if (gyros->isActive()) { @@ -464,43 +467,29 @@ void MyAvatar::updateFromGyrosAndOrWebcam(bool turnWithHead) { glm::quat orientation = _head.getCameraOrientation(); glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 right = orientation * IDENTITY_RIGHT; - - const float LEAN_FWD_DEAD_ZONE = 2.f; - const float LEAN_SIDEWAYS_DEAD_ZONE = 2.f; - const float LEAN_FWD_THRUST_SCALE = 1.f; - const float LEAN_SIDEWAYS_THRUST_SCALE = 1.f; - - //printf("%.2f, %.2f\n", _head.getLeanForward(), _head.getLeanSideways()); - - if (fabs(_head.getLeanForward()) > LEAN_FWD_DEAD_ZONE) { - addThrust(front * -_head.getLeanForward() * LEAN_FWD_THRUST_SCALE); - } - if (fabs(_head.getLeanSideways()) > LEAN_SIDEWAYS_DEAD_ZONE) { - addThrust(right * -_head.getLeanSideways() * LEAN_SIDEWAYS_THRUST_SCALE); - } - -/* - const float ANGULAR_DRIVE_SCALE = 0.1f; - const float ANGULAR_DEAD_ZONE = 0.3f; + float leanForward = _head.getLeanForward(); + float leanSideways = _head.getLeanSideways(); - 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.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; - setDriveKeys(UP, glm::clamp(torsoDelta * LINEAR_DRIVE_SCALE - LINEAR_DEAD_ZONE, 0.0f, 1.0f)); + // Degrees of 'dead zone' when leaning, and amount of acceleration to apply to lean angle + const float LEAN_FWD_DEAD_ZONE = 15.f; + const float LEAN_SIDEWAYS_DEAD_ZONE = 10.f; + const float LEAN_FWD_THRUST_SCALE = 4.f; + const float LEAN_SIDEWAYS_THRUST_SCALE = 3.f; - } else { - setDriveKeys(UP, 0.0f); + if (fabs(leanForward) > LEAN_FWD_DEAD_ZONE) { + if (leanForward > 0.f) { + addThrust(front * -(leanForward - LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE); + } else { + addThrust(front * -(leanForward + LEAN_FWD_DEAD_ZONE) * LEAN_FWD_THRUST_SCALE); + } + } + if (fabs(leanSideways) > LEAN_SIDEWAYS_DEAD_ZONE) { + if (leanSideways > 0.f) { + addThrust(right * -(leanSideways - LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE); + } else { + addThrust(right * -(leanSideways + LEAN_SIDEWAYS_DEAD_ZONE) * LEAN_SIDEWAYS_THRUST_SCALE); + } } - */ } static TextRenderer* textRenderer() { From 534c5105b047af18e67d82ed19184a8facc507ac Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 26 Nov 2013 11:46:11 -0800 Subject: [PATCH 06/10] echo the right one --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 99bb2786e0..378d86284a 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -86,7 +86,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } // If local loopback enabled, copy input to output - if (Menu::getInstance()->isOptionChecked(MenuOption::EchoServerAudio)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio)) { memcpy(outputLeft, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); memcpy(outputRight, inputLeft, PACKET_LENGTH_BYTES_PER_CHANNEL); } From cabd6ccbad23c9d5655ee1050eacc60e4bb68cb4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 27 Nov 2013 11:47:23 -0800 Subject: [PATCH 07/10] Advertise to others whether we have chat circling enabled, only include people with it enabled when doing the computations. --- interface/src/avatar/MyAvatar.cpp | 7 +++++-- libraries/avatars/src/AvatarData.cpp | 5 +++++ libraries/avatars/src/AvatarData.h | 5 +++++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 65670aa4f3..1257788d60 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -1161,17 +1161,20 @@ bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) { } void MyAvatar::updateChatCircle(float deltaTime) { - if (!Menu::getInstance()->isOptionChecked(MenuOption::ChatCircling)) { + if (!(_isChatCirclingEnabled = Menu::getInstance()->isOptionChecked(MenuOption::ChatCircling))) { return; } - // find all members and sort by distance + // find all circle-enabled members and sort by distance QVector sortedAvatars; NodeList* nodeList = NodeList::getInstance(); for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) { if (node->getLinkedData() && node->getType() == NODE_TYPE_AGENT) { SortedAvatar sortedAvatar; sortedAvatar.avatar = (Avatar*)node->getLinkedData(); + if (!sortedAvatar.avatar->isChatCirclingEnabled()) { + continue; + } sortedAvatar.distance = glm::distance(_position, sortedAvatar.avatar->getPosition()); sortedAvatars.append(sortedAvatar); } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index dc5a9c96d3..042deb9d3d 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -120,6 +120,9 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState); // faceshift state if (_headData->_isFaceshiftConnected) { setAtBit(bitItems, IS_FACESHIFT_CONNECTED); } + if (_isChatCirclingEnabled) { + setAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); + } *destinationBuffer++ = bitItems; // If it is connected, pack up the data @@ -248,6 +251,8 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { _headData->_isFaceshiftConnected = oneAtBit(bitItems, IS_FACESHIFT_CONNECTED); + _isChatCirclingEnabled = oneAtBit(bitItems, IS_CHAT_CIRCLING_ENABLED); + // If it is connected, pack up the data if (_headData->_isFaceshiftConnected) { memcpy(&_headData->_leftEyeBlink, sourceBuffer, sizeof(float)); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index b99be1bb09..13c9b1e049 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -30,6 +30,7 @@ const int KEY_STATE_START_BIT = 0; // 1st and 2nd bits const int HAND_STATE_START_BIT = 2; // 3rd and 4th bits const int IS_FACESHIFT_CONNECTED = 4; // 5th bit +const int IS_CHAT_CIRCLING_ENABLED = 5; const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation @@ -93,6 +94,8 @@ public: const std::string& setChatMessage() const { return _chatMessage; } QString getQStringChatMessage() { return QString(_chatMessage.data()); } + bool isChatCirclingEnabled() const { return _isChatCirclingEnabled; } + const QUuid& getLeaderUUID() const { return _leaderUUID; } void setHeadData(HeadData* headData) { _headData = headData; } @@ -124,6 +127,8 @@ protected: // chat message std::string _chatMessage; + bool _isChatCirclingEnabled; + std::vector _joints; HeadData* _headData; From b294b328ddde092bf910d8571ba5ea024554968f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 27 Nov 2013 12:56:31 -0800 Subject: [PATCH 08/10] Only render ball avatars when "avatars as balls" is checked. --- interface/src/Application.cpp | 6 +++--- interface/src/avatar/Avatar.cpp | 22 ++++++++++------------ interface/src/avatar/Avatar.h | 4 ++-- interface/src/avatar/Head.cpp | 16 +++++++++++----- interface/src/avatar/Head.h | 2 +- interface/src/avatar/MyAvatar.cpp | 16 ++++++---------- interface/src/avatar/MyAvatar.h | 4 ++-- 7 files changed, 35 insertions(+), 35 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58629df41e..0c0d5d072f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3850,7 +3850,7 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { if (!avatar->isInitialized()) { avatar->init(); } - avatar->render(false, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); + avatar->render(false); avatar->setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); } @@ -3860,12 +3860,12 @@ void Application::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) { // render avatar fades Glower glower; for (vector::iterator fade = _avatarFades.begin(); fade != _avatarFades.end(); fade++) { - (*fade)->render(false, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); + (*fade)->render(false); } } // Render my own Avatar - _myAvatar.render(forceRenderHead, Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)); + _myAvatar.render(forceRenderHead); _myAvatar.setDisplayingLookatVectors(Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors)); if (Menu::getInstance()->isOptionChecked(MenuOption::LookAtIndicator) && _lookatTargetAvatar) { diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 44e1f0aad1..0db3e6e3ee 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -21,6 +21,7 @@ #include "DataServerClient.h" #include "Hand.h" #include "Head.h" +#include "Menu.h" #include "Physics.h" #include "world.h" #include "devices/OculusManager.h" @@ -394,7 +395,7 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); glm::vec3 headPosition; - if (!_skeletonModel.getHeadPosition(headPosition)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) || !_skeletonModel.getHeadPosition(headPosition)) { headPosition = _bodyBall[BODY_BALL_HEAD_BASE].position; } _head.setPosition(headPosition); @@ -439,7 +440,7 @@ static TextRenderer* textRenderer() { return renderer; } -void Avatar::render(bool forceRenderHead, bool renderAvatarBalls) { +void Avatar::render(bool forceRenderHead) { if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) { _hand.setRaveLights(RAVE_LIGHTS_AVATAR); @@ -455,7 +456,7 @@ void Avatar::render(bool forceRenderHead, bool renderAvatarBalls) { Glower glower(_moving && glm::length(toTarget) > GLOW_DISTANCE ? 1.0f : 0.0f); // render body - renderBody(forceRenderHead, renderAvatarBalls); + renderBody(forceRenderHead); // render sphere when far away const float MAX_ANGLE = 10.f; @@ -666,7 +667,8 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ float distance = glm::length(armVector); // don't let right hand get dragged beyond maximum arm length... - float armLength = _skeletonModel.isActive() ? _skeletonModel.getRightArmLength() : _skeleton.getArmLength(); + float armLength = (_skeletonModel.isActive() && !Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) ? + _skeletonModel.getRightArmLength() : _skeleton.getArmLength(); const float ARM_RETRACTION = 0.75f; float retractedArmLength = armLength * ARM_RETRACTION; if (distance > retractedArmLength) { @@ -713,7 +715,7 @@ float Avatar::getBallRenderAlpha(int ball, bool forceRenderHead) const { return 1.0f; } -void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { +void Avatar::renderBody(bool forceRenderHead) { if (_head.getVideoFace().isFullFrame()) { // Render the full-frame video @@ -721,7 +723,7 @@ void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { if (alpha > 0.0f) { _head.getVideoFace().render(1.0f); } - } else if (renderAvatarBalls || !(_voxels.getVoxelURL().isValid() || _skeletonModel.isActive())) { + } else if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) { // Render the body as balls and cones glm::vec3 skinColor, darkSkinColor; getSkinColors(skinColor, darkSkinColor); @@ -738,7 +740,7 @@ void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { // Always render other people, and render myself when beyond threshold distance if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special if (alpha > 0.0f) { - _head.render(alpha, false); + _head.render(alpha, true); } } else if (alpha > 0.0f) { // Render the body ball sphere @@ -746,10 +748,6 @@ void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { skinColor.g - _bodyBall[b].touchForce * 0.2f, skinColor.b - _bodyBall[b].touchForce * 0.1f); - if (b == BODY_BALL_NECK_BASE && _head.getFaceModel().isActive()) { - continue; // don't render the neck if we have a face model - } - if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); @@ -793,7 +791,7 @@ void Avatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { void Avatar::getSkinColors(glm::vec3& lighter, glm::vec3& darker) { lighter = glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2]); darker = glm::vec3(DARK_SKIN_COLOR[0], DARK_SKIN_COLOR[1], DARK_SKIN_COLOR[2]); - if (_head.getFaceModel().isActive()) { + if (!Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) && _head.getFaceModel().isActive()) { lighter = glm::vec3(_head.getFaceModel().computeAverageColor()); const float SKIN_DARKENING = 0.9f; darker = lighter * SKIN_DARKENING; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index d633871891..cc18ce7f1a 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -141,7 +141,7 @@ public: void init(); void simulate(float deltaTime, Transmitter* transmitter); void follow(Avatar* leadingAvatar); - void render(bool forceRenderHead, bool renderAvatarBalls); + void render(bool forceRenderHead); //setters void setDisplayingLookatVectors(bool displayingLookatVectors) { _head.setRenderLookatVectors(displayingLookatVectors); } @@ -256,7 +256,7 @@ private: // private methods... glm::vec3 calculateAverageEyePosition() { return _head.calculateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) float getBallRenderAlpha(int ball, bool forceRenderHead) const; - void renderBody(bool forceRenderHead, bool renderAvatarBalls); + void renderBody(bool forceRenderHead); void initializeBodyBalls(); void resetBodyBalls(); void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement); diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index 0390506716..5dd59ed159 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -250,7 +250,9 @@ void Head::simulate(float deltaTime, bool isMine) { calculateGeometry(); // the blend face may have custom eye meshes - _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition); + if (!Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) { + _faceModel.getEyePositions(_leftEyePosition, _rightEyePosition); + } } void Head::calculateGeometry() { @@ -295,10 +297,11 @@ void Head::calculateGeometry() { + up * _scale * NOSE_UPTURN; } -void Head::render(float alpha, bool isMine) { +void Head::render(float alpha, bool renderAvatarBalls) { _renderAlpha = alpha; - if (!(_videoFace.render(alpha) || _faceModel.render(alpha))) { + bool lookatVectorsVisible = _renderLookatVectors; + if (renderAvatarBalls) { glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); @@ -309,9 +312,12 @@ void Head::render(float alpha, bool isMine) { renderMouth(); renderNose(); renderEyeBrows(); + + } else if (!_videoFace.render(alpha)) { + lookatVectorsVisible &= _faceModel.render(alpha); } - - if (_renderLookatVectors) { + + if (lookatVectorsVisible) { renderLookatVectors(_leftEyePosition, _rightEyePosition, _lookAtPosition); } } diff --git a/interface/src/avatar/Head.h b/interface/src/avatar/Head.h index 323375985d..47e998059d 100644 --- a/interface/src/avatar/Head.h +++ b/interface/src/avatar/Head.h @@ -44,7 +44,7 @@ public: void init(); void reset(); void simulate(float deltaTime, bool isMine); - void render(float alpha, bool isMine); + void render(float alpha, bool renderAvatarBalls); void renderMohawk(); void setScale(float scale); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 1257788d60..baedb1bc6b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -325,7 +325,7 @@ void MyAvatar::simulate(float deltaTime, Transmitter* transmitter) { _skeletonModel.simulate(deltaTime); _head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); glm::vec3 headPosition; - if (!_skeletonModel.getHeadPosition(headPosition)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls) || !_skeletonModel.getHeadPosition(headPosition)) { headPosition = _bodyBall[BODY_BALL_HEAD_BASE].position; } _head.setPosition(headPosition); @@ -497,7 +497,7 @@ static TextRenderer* textRenderer() { return renderer; } -void MyAvatar::render(bool forceRenderHead, bool renderAvatarBalls) { +void MyAvatar::render(bool forceRenderHead) { if (Application::getInstance()->getAvatar()->getHand().isRaveGloveActive()) { _hand.setRaveLights(RAVE_LIGHTS_AVATAR); @@ -507,7 +507,7 @@ void MyAvatar::render(bool forceRenderHead, bool renderAvatarBalls) { renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), _scale * 0.1f, 0.2f); // render body - renderBody(forceRenderHead, renderAvatarBalls); + renderBody(forceRenderHead); // if this is my avatar, then render my interactions with the other avatar _avatarTouch.render(Application::getInstance()->getCamera()->getPosition()); @@ -648,7 +648,7 @@ float MyAvatar::getBallRenderAlpha(int ball, bool forceRenderHead) const { (distanceToCamera - DO_NOT_RENDER_INSIDE) / (RENDER_OPAQUE_OUTSIDE - DO_NOT_RENDER_INSIDE), 0.f, 1.f); } -void MyAvatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { +void MyAvatar::renderBody(bool forceRenderHead) { if (_head.getVideoFace().isFullFrame()) { // Render the full-frame video @@ -656,7 +656,7 @@ void MyAvatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { if (alpha > 0.0f) { _head.getVideoFace().render(1.0f); } - } else if (renderAvatarBalls || !(_voxels.getVoxelURL().isValid() || _skeletonModel.isActive())) { + } else if (Menu::getInstance()->isOptionChecked(MenuOption::AvatarAsBalls)) { // Render the body as balls and cones glm::vec3 skinColor, darkSkinColor; getSkinColors(skinColor, darkSkinColor); @@ -690,10 +690,6 @@ void MyAvatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { alpha); } - if (b == BODY_BALL_NECK_BASE && _head.getFaceModel().isActive()) { - continue; // don't render the neck if we have a face model - } - if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); @@ -729,7 +725,7 @@ void MyAvatar::renderBody(bool forceRenderHead, bool renderAvatarBalls) { } float alpha = getBallRenderAlpha(BODY_BALL_HEAD_BASE, forceRenderHead); if (alpha > 0.0f) { - _head.render(alpha, true); + _head.render(alpha, false); } } _hand.render(); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 2d90a32108..790f76b233 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -20,7 +20,7 @@ public: void reset(); void simulate(float deltaTime, Transmitter* transmitter); void updateFromGyrosAndOrWebcam(bool turnWithHead); - void render(bool forceRenderHead, bool renderAvatarBalls); + void render(bool forceRenderHead); void renderScreenTint(ScreenTintLayer layer); // setters @@ -82,7 +82,7 @@ private: // private methods float getBallRenderAlpha(int ball, bool forceRenderHead) const; - void renderBody(bool forceRenderHead, bool renderAvatarBalls); + void renderBody(bool forceRenderHead); void updateThrust(float deltaTime, Transmitter * transmitter); void updateHandMovementAndTouching(float deltaTime, bool enableHandMovement); void updateAvatarCollisions(float deltaTime); From d8259f67f0940339397a5198893d9dcda9ee0f49 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 27 Nov 2013 13:09:52 -0800 Subject: [PATCH 09/10] Re-request skeleton/face URLs on login. --- interface/src/avatar/Profile.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/avatar/Profile.cpp b/interface/src/avatar/Profile.cpp index 69411e2eff..4a185f5788 100644 --- a/interface/src/avatar/Profile.cpp +++ b/interface/src/avatar/Profile.cpp @@ -23,6 +23,8 @@ Profile::Profile(const QString &username) : if (!_username.isEmpty()) { // we've been given a new username, ask the data-server for profile DataServerClient::getClientValueForKey(DataServerKey::UUID); + DataServerClient::getClientValueForKey(DataServerKey::FaceMeshURL); + DataServerClient::getClientValueForKey(DataServerKey::SkeletonURL); // send our current domain server to the data-server updateDomain(NodeList::getInstance()->getDomainHostname()); From ac714773d3f99eb6cb9f73200009fe1a09cc1bd5 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 27 Nov 2013 13:13:36 -0800 Subject: [PATCH 10/10] Initialize chat circling flag. --- libraries/avatars/src/AvatarData.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 042deb9d3d..0a90f4db96 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -33,6 +33,7 @@ AvatarData::AvatarData(Node* owningNode) : _leaderUUID(), _handState(0), _keyState(NO_KEY_DOWN), + _isChatCirclingEnabled(false), _headData(NULL), _handData(NULL) {