From b30f7b02bd6493b821b4b1c235e0be40af8ff322 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 14 May 2013 15:10:44 -0700 Subject: [PATCH 01/24] Removed mouse shift prototype. --- interface/src/Application.cpp | 50 +++++------------------------------ interface/src/Application.h | 3 --- 2 files changed, 6 insertions(+), 47 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0a6fd4e948..494e0e9db5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -54,16 +54,9 @@ static char STAR_CACHE_FILE[] = "cachedStars.txt"; const glm::vec3 START_LOCATION(6.1f, 0, 1.4f); // Where one's own agent begins in the world // (will be overwritten if avatar data file is found) -const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff - // in the idle loop? (60 FPS is default) +const int IDLE_SIMULATE_MSECS = 16; // How often should call simulate and other stuff + // in the idle loop? (60 FPS is default) -const bool USING_MOUSE_VIEW_SHIFT = false; -const float MOUSE_VIEW_SHIFT_RATE = 40.0f; -const float MOUSE_VIEW_SHIFT_YAW_MARGIN = (float)(1200 * 0.2f); -const float MOUSE_VIEW_SHIFT_PITCH_MARGIN = (float)(800 * 0.2f); -const float MOUSE_VIEW_SHIFT_YAW_LIMIT = 45.0; -const float MOUSE_VIEW_SHIFT_PITCH_LIMIT = 30.0; - const bool DISPLAY_HEAD_MOUSE = true; // customized canvas that simply forwards requests/events to the singleton application @@ -135,8 +128,6 @@ Application::Application(int& argc, char** argv) : _viewFrustumOffsetRoll(0.0), _viewFrustumOffsetDistance(25.0), _viewFrustumOffsetUp(0.0), - _mouseViewShiftYaw(0.0f), - _mouseViewShiftPitch(0.0f), _audioScope(256, 200, true), _myAvatar(true), _mouseX(0), @@ -312,13 +303,13 @@ void Application::paintGL() { } else { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw() - _mouseViewShiftYaw, - _myAvatar.getRenderPitch() + _mouseViewShiftPitch, 0.0f); + _myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(), + _myAvatar.getRenderPitch(), 0.0f); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getBodyYaw() - _mouseViewShiftYaw, _mouseViewShiftPitch, 0.0f); - } + _myCamera.setTargetRotation(_myAvatar.getBodyYaw(), 0.0f, 0.0f); + } } // important... @@ -863,8 +854,6 @@ void Application::idle() { // walking triggers the handControl to stop if (_myAvatar.getMode() == AVATAR_MODE_WALKING) { _handControl.stop(); - _mouseViewShiftYaw *= 0.9; - _mouseViewShiftPitch *= 0.9; } // Read serial port interface devices @@ -1215,33 +1204,6 @@ void Application::updateAvatar(float deltaTime) { } - if (USING_MOUSE_VIEW_SHIFT) - { - //make it so that when your mouse hits the edge of the screen, the camera shifts - float rightBoundary = (float)_glWidget->width() - MOUSE_VIEW_SHIFT_YAW_MARGIN; - float bottomBoundary = (float)_glWidget->height() - MOUSE_VIEW_SHIFT_PITCH_MARGIN; - - if (_mouseX > rightBoundary) { - float f = (_mouseX - rightBoundary) / ( (float)_glWidget->width() - rightBoundary); - _mouseViewShiftYaw += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; - if (_mouseViewShiftYaw > MOUSE_VIEW_SHIFT_YAW_LIMIT) { _mouseViewShiftYaw = MOUSE_VIEW_SHIFT_YAW_LIMIT; } - } else if (_mouseX < MOUSE_VIEW_SHIFT_YAW_MARGIN) { - float f = 1.0 - (_mouseX / MOUSE_VIEW_SHIFT_YAW_MARGIN); - _mouseViewShiftYaw -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; - if (_mouseViewShiftYaw < -MOUSE_VIEW_SHIFT_YAW_LIMIT) { _mouseViewShiftYaw = -MOUSE_VIEW_SHIFT_YAW_LIMIT; } - } - if (_mouseY < MOUSE_VIEW_SHIFT_PITCH_MARGIN) { - float f = 1.0 - (_mouseY / MOUSE_VIEW_SHIFT_PITCH_MARGIN); - _mouseViewShiftPitch += MOUSE_VIEW_SHIFT_RATE * f * deltaTime; - if (_mouseViewShiftPitch > MOUSE_VIEW_SHIFT_PITCH_LIMIT ) { _mouseViewShiftPitch = MOUSE_VIEW_SHIFT_PITCH_LIMIT; } - } - else if (_mouseY > bottomBoundary) { - float f = (_mouseY - bottomBoundary) / ((float)_glWidget->height() - bottomBoundary); - _mouseViewShiftPitch -= MOUSE_VIEW_SHIFT_RATE * f * deltaTime; - if (_mouseViewShiftPitch < -MOUSE_VIEW_SHIFT_PITCH_LIMIT) { _mouseViewShiftPitch = -MOUSE_VIEW_SHIFT_PITCH_LIMIT; } - } - } - if (OculusManager::isConnected()) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); diff --git a/interface/src/Application.h b/interface/src/Application.h index e22409a77b..8869fba7fc 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -171,9 +171,6 @@ private: float _viewFrustumOffsetDistance; float _viewFrustumOffsetUp; - float _mouseViewShiftYaw; - float _mouseViewShiftPitch; - Oscilloscope _audioScope; Avatar _myAvatar; // The rendered avatar of oneself From 6cfdf96deac0fd1a8a371bb3ec3bb9b1980147dd Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Tue, 14 May 2013 17:11:16 -0700 Subject: [PATCH 02/24] Added mouse panning in the Yaw direction - at edges of screen. --- interface/src/Application.cpp | 19 ++++++++++++------- interface/src/Avatar.cpp | 17 +++++++++++++++++ interface/src/Avatar.h | 1 + 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 65c29d2d88..1f11a63367 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -859,6 +859,9 @@ void Application::idle() { _handControl.stop(); } + // Update from Mouse + _myAvatar.updateFromMouse(_mouseX, _mouseY, _glWidget->width(), _glWidget->height()); + // Read serial port interface devices if (_serialPort.active) { _serialPort.readData(); @@ -1162,8 +1165,8 @@ void Application::init() { _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); - _headMouseX = _glWidget->width()/2; - _headMouseY = _glWidget->height()/2; + _headMouseX = _mouseX = _glWidget->width() / 2; + _headMouseY = _mouseY = _glWidget->height() / 2; _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); @@ -1173,7 +1176,9 @@ void Application::init() { a.distance = 1.5f; a.tightness = 8.0f; _myCamera.setMode(CAMERA_MODE_THIRD_PERSON, a); - _myAvatar.setDisplayingHead(true); + _myAvatar.setDisplayingHead(true); + + QCursor::setPos(_headMouseX, _headMouseY); OculusManager::connect(); @@ -1228,7 +1233,6 @@ void Application::updateAvatar(float deltaTime) { renderPitchSpring * deltaTime * -_myAvatar.getHeadPitch() * RENDER_PITCH_MULTIPLY); } - if (OculusManager::isConnected()) { float yaw, pitch, roll; OculusManager::getEulerAngles(yaw, pitch, roll); @@ -1900,12 +1904,13 @@ void Application::deleteVoxelUnderCursor() { void Application::resetSensors() { _myAvatar.setPosition(START_LOCATION); - _headMouseX = _glWidget->width() / 2; - _headMouseY = _glWidget->height() / 2; + _headMouseX = _mouseX = _glWidget->width() / 2; + _headMouseY = _mouseY = _glWidget->height() / 2; if (_serialPort.active) { _serialPort.resetAverages(); - } + } + QCursor::setPos(_headMouseX, _headMouseY); _myAvatar.reset(); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 64b9310b78..4203bd0d4c 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -291,6 +291,23 @@ bool Avatar::getIsNearInteractingOther() { return _avatarTouch.getAbleToReachOtherAvatar(); } +void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { + // Update pitch and yaw based on mouse behavior + const float MOUSE_MOVE_RADIUS = 0.25f; + const float MOUSE_ROTATE_SPEED = 7.5f; + float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; + + if (fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) { + float mouseMag = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; + setBodyYaw(getBodyYaw() - + ((mouseLocationX > 0.f) ? + mouseMag : + -mouseMag) ); + } + + return; +} + void Avatar::simulate(float deltaTime) { //figure out if the mouse cursor is over any body spheres... diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index beca93b53e..c4075858e1 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -82,6 +82,7 @@ public: void reset(); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); + void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight); void setNoise (float mag) {_head.noise = mag;} void setRenderYaw(float y) {_renderYaw = y;} void setRenderPitch(float p) {_renderPitch = p;} From daaf86a63414ca16e26804beff55009477d36678 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 08:06:53 -0700 Subject: [PATCH 03/24] restrict avatar body yaw to be between 0-360 --- interface/src/Avatar.cpp | 1 + libraries/avatars/src/AvatarData.cpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 4203bd0d4c..dbbc42d378 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -303,6 +303,7 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree ((mouseLocationX > 0.f) ? mouseMag : -mouseMag) ); + printLog("yaw = %f\n", getBodyYaw()); } return; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1f4856abf7..501279b14a 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -217,7 +217,11 @@ float AvatarData::getBodyYaw() { } void AvatarData::setBodyYaw(float bodyYaw) { + if ((bodyYaw > 360.f) || (bodyYaw < 0.f)) { + bodyYaw -= floorf(bodyYaw / 360.f) * 360.f; + } _bodyYaw = bodyYaw; + } float AvatarData::getBodyPitch() { From 73c793c0a17bb03191fabc2edcced206d4450669 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 09:37:36 -0700 Subject: [PATCH 04/24] Added optional millisecond onscreen frame timer for easier latency timing with high-speed camera --- interface/src/Application.cpp | 14 ++++++++++++++ interface/src/Application.h | 5 +++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 146d4a30c3..acf11fba0a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1085,6 +1085,9 @@ void Application::initMenu() { _renderAtmosphereOn->setShortcut(Qt::SHIFT | Qt::Key_A); (_renderAvatarsOn = renderMenu->addAction("Avatars"))->setCheckable(true); _renderAvatarsOn->setChecked(true); + (_renderFrameTimerOn = renderMenu->addAction("Show Timer"))->setCheckable(true); + _renderFrameTimerOn->setChecked(false); + renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true); (_oculusOn = renderMenu->addAction("Oculus", this, SLOT(setOculus(bool)), Qt::Key_O))->setCheckable(true); @@ -1629,6 +1632,17 @@ void Application::displayOverlay() { if (_chatEntryOn) { _chatEntry.render(_glWidget->width(), _glWidget->height()); } + + // Show on-screen msec timer + if (_renderFrameTimerOn->isChecked()) { + char frameTimer[10]; + double mSecsNow = floor(usecTimestampNow() / 1000.0 + 0.5); + mSecsNow = mSecsNow - floor(mSecsNow / 1000.0) * 1000.0; + sprintf(frameTimer, "%3.0f\n", mSecsNow); + drawtext(_glWidget->width() - 100, _glWidget->height() - 20, 0.30, 0, 1.0, 0, frameTimer, 0, 0, 0); + drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30, 0, 1.0, 0, frameTimer, 1, 1, 1); + } + // Stats at upper right of screen about who domain server is telling us about glPointSize(1.0f); diff --git a/interface/src/Application.h b/interface/src/Application.h index f9b46be889..1500ceb850 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -134,8 +134,9 @@ private: QAction* _renderAtmosphereOn; // Whether to display the atmosphere QAction* _renderAvatarsOn; // Whether to render avatars QAction* _oculusOn; // Whether to configure the display for the Oculus Rift - QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats - QAction* _logOn; // Whether to show on-screen log + QAction* _renderStatsOn; // Whether to show onscreen text overlay with stats + QAction* _renderFrameTimerOn; // Whether to show onscreen text overlay with stats + QAction* _logOn; // Whether to show on-screen log QAction* _voxelPaintColor; // The color with which to paint voxels QAction* _frustumOn; // Whether or not to display the debug view frustum QAction* _viewFrustumFromOffset; // Whether or not to offset the view of the frustum From 124f04820eb4321c1a0bf43ddddd4a035e1fc1be Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 09:52:12 -0700 Subject: [PATCH 05/24] Removed renderPitch(), and renderYaw() from code/classes - we will use bodyPitch(), headPitch() only. --- interface/src/Application.cpp | 4 +++- interface/src/Avatar.cpp | 5 +---- interface/src/Avatar.h | 4 ---- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index acf11fba0a..2ad109a02a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -306,7 +306,7 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(), - _myAvatar.getRenderPitch(), 0.0f); + _myAvatar.getAbsoluteHeadPitch(), 0.0f); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); @@ -1225,6 +1225,7 @@ void Application::updateAvatar(float deltaTime) { // Update head and body pitch and yaw based on measured gyro rates if (_gyroLook->isChecked()) { // Render Yaw + /* NOTE: PER - Leave here until I get back and can modify to couple gyros to head pitch, yaw float renderYawSpring = fabs(_headMouseX - _glWidget->width() / 2.f) / (_glWidget->width() / 2.f); const float RENDER_YAW_MULTIPLY = 4.f; _myAvatar.setRenderYaw((1.f - renderYawSpring * deltaTime) * _myAvatar.getRenderYaw() + @@ -1234,6 +1235,7 @@ void Application::updateAvatar(float deltaTime) { const float RENDER_PITCH_MULTIPLY = 4.f; _myAvatar.setRenderPitch((1.f - renderPitchSpring * deltaTime) * _myAvatar.getRenderPitch() + renderPitchSpring * deltaTime * -_myAvatar.getHeadPitch() * RENDER_PITCH_MULTIPLY); + */ } if (OculusManager::isConnected()) { diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index dbbc42d378..ef56fe23b7 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -96,8 +96,6 @@ Avatar::Avatar(bool isMine) { _head.initialize(); _movedHandOffset = glm::vec3(0.0f, 0.0f, 0.0f); - _renderYaw = 0.0; - _renderPitch = 0.0; _sphere = NULL; _handHoldingPosition = glm::vec3(0.0f, 0.0f, 0.0f); _distanceToNearestAvatar = std::numeric_limits::max(); @@ -126,7 +124,6 @@ Avatar::Avatar(const Avatar &otherAvatar) { _mode = otherAvatar._mode; _isMine = otherAvatar._isMine; _renderYaw = otherAvatar._renderYaw; - _renderPitch = otherAvatar._renderPitch; _maxArmLength = otherAvatar._maxArmLength; _transmitterTimer = otherAvatar._transmitterTimer; _transmitterIsFirstData = otherAvatar._transmitterIsFirstData; @@ -303,7 +300,7 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree ((mouseLocationX > 0.f) ? mouseMag : -mouseMag) ); - printLog("yaw = %f\n", getBodyYaw()); + //printLog("yaw = %f\n", getBodyYaw()); } return; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index c4075858e1..a6b3a9901c 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -84,10 +84,6 @@ public: void updateHeadFromGyros(float frametime, SerialInterface * serialInterface, glm::vec3 * gravity); void updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight); void setNoise (float mag) {_head.noise = mag;} - void setRenderYaw(float y) {_renderYaw = y;} - void setRenderPitch(float p) {_renderPitch = p;} - float getRenderYaw() {return _renderYaw;} - float getRenderPitch() {return _renderPitch;} float getLastMeasuredHeadYaw() const {return _head.yawRate;} float getBodyYaw() {return _bodyYaw;}; void addBodyYaw(float y) {_bodyYaw += y;}; From 72d657b51df19a3eef137747bbdca2df08676c91 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 10:00:30 -0700 Subject: [PATCH 06/24] Preventing render bug with mis-scaled mouth (part of screen all black) --- interface/src/Head.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 6cdc9a7c7a..d94d9197a9 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -297,9 +297,10 @@ void Head::render(bool lookingInMirror, float bodyYaw) { glColor3f(0,0,0); glRotatef(mouthPitch, 1, 0, 0); glRotatef(mouthYaw, 0, 0, 1); - if (averageLoudness > 1.f) { - glScalef(mouthWidth * (.7f + sqrt(averageLoudness) /60.f), - mouthHeight * (1.f + sqrt(averageLoudness) /30.f), 1); + + if ((averageLoudness > 1.f) && (averageLoudness < 10000.f)) { + glScalef(mouthWidth * (.7f + sqrt(averageLoudness) / 60.f), + mouthHeight * (1.f + sqrt(averageLoudness) / 30.f), 1); } else { glScalef(mouthWidth, mouthHeight, 1); } From 84d18296d2006520c1e44db5953ff01913d895f0 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 10:02:02 -0700 Subject: [PATCH 07/24] removed normalization of body yaw (need to fix springs before we do it) --- libraries/avatars/src/AvatarData.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 501279b14a..1f4856abf7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -217,11 +217,7 @@ float AvatarData::getBodyYaw() { } void AvatarData::setBodyYaw(float bodyYaw) { - if ((bodyYaw > 360.f) || (bodyYaw < 0.f)) { - bodyYaw -= floorf(bodyYaw / 360.f) * 360.f; - } _bodyYaw = bodyYaw; - } float AvatarData::getBodyPitch() { From f6389cac38a1684fbebbb8b064d7f392b654d63f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 13:03:22 -0700 Subject: [PATCH 08/24] First commit, audio echo detection, also changed scope to show last buffer played rather than next buffer to play. --- interface/src/Audio.cpp | 27 ++++++++++++++++++--------- interface/src/AudioData.cpp | 31 +++++++++++++++++++++++++++++++ interface/src/AudioData.h | 3 ++- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8a455ec419..20d39f6f00 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -105,10 +105,19 @@ int audioCallback (const void *inputBuffer, AudioData *data = (AudioData *) userData; int16_t *inputLeft = ((int16_t **) inputBuffer)[0]; + int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; + int16_t *outputRight = ((int16_t **) outputBuffer)[1]; + + // Compare the input and output streams to look for correlation + data->analyzeEcho(inputLeft, outputLeft, BUFFER_LENGTH_SAMPLES); // Add Procedural effects to input samples data->addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); + // add data to the scope + scope->addSamples(1, outputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL); + scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); + if (inputLeft != NULL) { // Measure the loudness of the signal from the microphone and store in audio object @@ -169,10 +178,7 @@ int audioCallback (const void *inputBuffer, data->audioSocket->send((sockaddr *)&audioMixerSocket, dataPacket, BUFFER_LENGTH_BYTES + leadingBytes); } } - - int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; - int16_t *outputRight = ((int16_t **) outputBuffer)[1]; - + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); @@ -265,11 +271,7 @@ int audioCallback (const void *inputBuffer, outputLeft[s] = leftSample; outputRight[s] = rightSample; } - - // add data to the scope - scope->addSamples(1, outputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL); - scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); - + ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); if (ringBuffer->getNextOutput() == ringBuffer->getBuffer() + RING_BUFFER_SAMPLES) { @@ -278,6 +280,13 @@ int audioCallback (const void *inputBuffer, } } + if (randFloat() < 0.01) { + printLog("Ping!\n"); + for (int i = 0; i < BUFFER_LENGTH_SAMPLES; i++) { + outputLeft[i] = (int16_t) (cosf((float)i / 8.f * 2000.f)); + } + } + gettimeofday(&data->lastCallback, NULL); return paContinue; } diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp index 83b53b0ea3..faa0a27a83 100644 --- a/interface/src/AudioData.cpp +++ b/interface/src/AudioData.cpp @@ -44,5 +44,36 @@ void AudioData::addProceduralSounds(int16_t* inputBuffer, int numSamples) { return; } +void AudioData::analyzeEcho(int16_t* inputBuffer, int16_t* outputBuffer, int numSamples) { + // Compare output and input streams, looking for evidence of correlation needing echo cancellation + // + // OFFSET_RANGE tells us how many samples to vary the analysis window when looking for correlation, + // and should be equal to the largest physical distance between speaker and microphone, where + // OFFSET_RANGE = 1 / (speedOfSound (meters / sec) / SamplingRate (samples / sec)) * distance + // + const int OFFSET_RANGE = 10; + const int SIGNAL_FLOOR = 1000; + float correlation[2 * OFFSET_RANGE + 1]; + int numChecked = 0; + bool foundSignal = false; + for (int offset = -OFFSET_RANGE; offset <= OFFSET_RANGE; offset++) { + for (int i = 0; i < numSamples; i++) { + if ((i + offset >= 0) && (i + offset < numSamples)) { + correlation[offset + OFFSET_RANGE] += + (float) abs(inputBuffer[i] - outputBuffer[i + offset]); + numChecked++; + foundSignal |= (inputBuffer[i] > SIGNAL_FLOOR); + } + } + correlation[offset + OFFSET_RANGE] /= numChecked; + numChecked = 0; + if (foundSignal) { + printLog("%4.2f, ", correlation[offset + OFFSET_RANGE]); + } + } + if (foundSignal) printLog("\n"); +} + + #endif diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h index 80de3df6dc..a98c40b38a 100644 --- a/interface/src/AudioData.h +++ b/interface/src/AudioData.h @@ -43,8 +43,9 @@ class AudioData { void setLastVelocity(glm::vec3 v) { _lastVelocity = v; }; void setLastAcceleration(glm::vec3 a) { _lastAcceleration = a; }; void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void analyzeEcho(int16_t* inputBuffer, int16_t* outputBuffer, int numSamples); - private: + private: glm::vec3 _lastVelocity; glm::vec3 _lastAcceleration; From 1a283c3ac061ae4a926a174600972c3c9ebcfc3f Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Wed, 15 May 2013 21:15:55 -0600 Subject: [PATCH 09/24] Improvements to scope display, added framework for echo analysis over multiple frames --- interface/src/Application.cpp | 5 ++ interface/src/Audio.cpp | 96 ++++++++++++++++++++++++++-------- interface/src/Audio.h | 11 ++++ interface/src/AudioData.cpp | 79 ---------------------------- interface/src/AudioData.h | 55 ------------------- interface/src/Oscilloscope.cpp | 9 ++-- 6 files changed, 96 insertions(+), 159 deletions(-) delete mode 100644 interface/src/AudioData.cpp delete mode 100644 interface/src/AudioData.h diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index faebf55df3..b161f635b8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -534,6 +534,10 @@ void Application::keyPressEvent(QKeyEvent* event) { sendVoxelServerAddScene(); break; + case Qt::Key_Semicolon: + _audio.startEchoTest(); + break; + case Qt::Key_L: _displayLevels = !_displayLevels; break; @@ -1641,6 +1645,7 @@ void Application::displayOverlay() { #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); _audioScope.render(20, _glWidget->height() - 200); + //_audio.renderEchoCompare(); // PER: Will turn back on to further test echo #endif //noiseTest(_glWidget->width(), _glWidget->height()); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index df3fab75ed..f9504b9ed7 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -87,22 +87,26 @@ int audioCallback (const void* inputBuffer, Application* interface = (Application*) QCoreApplication::instance(); Avatar interfaceAvatar = interface->getAvatar(); - bool addPing = (randFloat() < 0.005f); - int16_t *inputLeft = ((int16_t **) inputBuffer)[0]; int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; int16_t *outputRight = ((int16_t **) outputBuffer)[1]; - // Compare the input and output streams to look for correlation - parentAudio->analyzeEcho(inputLeft, outputLeft, BUFFER_LENGTH_SAMPLES); - // Add Procedural effects to input samples parentAudio->addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); - // add data to the scope + // add output (@speakers) data to the scope parentAudio->_scope->addSamples(1, outputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL); parentAudio->_scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); - + + // if needed, add input/output data to echo analysis buffers + if (parentAudio->_gatheringEchoFrames) { + memcpy(parentAudio->_echoInputSamples, inputLeft, + PACKET_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); + memcpy(parentAudio->_echoOutputSamples, outputLeft, + PACKET_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); + parentAudio->addedPingFrame(); + } + if (inputLeft != NULL) { // Measure the loudness of the signal from the microphone and store in audio object @@ -114,7 +118,7 @@ int audioCallback (const void* inputBuffer, loudness /= BUFFER_LENGTH_SAMPLES; parentAudio->_lastInputLoudness = loudness; - // add data to the scope + // add input (@microphone) data to the scope parentAudio->_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES); Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); @@ -192,7 +196,6 @@ int audioCallback (const void* inputBuffer, } // play whatever we have in the audio buffer - // if we haven't fired off the flange effect, check if we should // TODO: lastMeasuredHeadYaw is now relative to body - check if this still works. @@ -254,12 +257,8 @@ int audioCallback (const void* inputBuffer, } } - if (!addPing) { - outputLeft[s] = leftSample; - outputRight[s] = rightSample; - } else { - outputLeft[s] = outputRight[s] = (int16_t)(sinf((float) s / 15.f) * 8000.f); - } + outputLeft[s] = leftSample; + outputRight[s] = rightSample; } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -268,11 +267,19 @@ int audioCallback (const void* inputBuffer, } } } - + if (parentAudio->_sendingEchoPing) { + const float PING_PITCH = 4.f; + const float PING_VOLUME = 32000.f; + for (int s = 0; s < PACKET_LENGTH_SAMPLES_PER_CHANNEL; s++) { + outputLeft[s] = outputRight[s] = (int16_t)(sinf((float) s / PING_PITCH) * PING_VOLUME); + } + parentAudio->_gatheringEchoFrames = true; + } gettimeofday(&parentAudio->_lastCallbackTime, NULL); return paContinue; } + void outputPortAudioError(PaError error) { if (error != paNoError) { printLog("-- portaudio termination error --\n"); @@ -293,8 +300,12 @@ Audio::Audio(Oscilloscope* scope) : _lastAcceleration(0), _totalPacketsReceived(0), _firstPlaybackTime(), - _packetsReceivedThisPlayback(0) -{ + _packetsReceivedThisPlayback(0), + _startEcho(false), + _sendingEchoPing(false), + _echoPingFrameCount(0), + _gatheringEchoFrames(false) +{ outputPortAudioError(Pa_Initialize()); outputPortAudioError(Pa_OpenDefaultStream(&_stream, 2, @@ -307,7 +318,12 @@ Audio::Audio(Oscilloscope* scope) : // start the stream now that sources are good to go outputPortAudioError(Pa_StartStream(_stream)); - + + _echoInputSamples = new int16_t[BUFFER_LENGTH_BYTES]; + _echoOutputSamples = new int16_t[BUFFER_LENGTH_BYTES]; + memset(_echoInputSamples, 0, BUFFER_LENGTH_SAMPLES * sizeof(int)); + memset(_echoOutputSamples, 0, BUFFER_LENGTH_SAMPLES * sizeof(int)); + gettimeofday(&_lastReceiveTime, NULL); } @@ -318,6 +334,28 @@ Audio::~Audio() { } } +void Audio::renderEchoCompare() { + const int XPOS = 0; + const int YPOS = 500; + const int YSCALE = 500; + const int XSCALE = 2; + glPointSize(1.0); + glLineWidth(1.0); + glDisable(GL_LINE_SMOOTH); + glColor3f(1,1,1); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < BUFFER_LENGTH_SAMPLES; i++) { + glVertex2f(XPOS + i * XSCALE, YPOS + _echoInputSamples[i]/YSCALE); + } + glEnd(); + glColor3f(0,1,1); + glBegin(GL_LINE_STRIP); + for (int i = 0; i < BUFFER_LENGTH_SAMPLES; i++) { + glVertex2f(XPOS + i * XSCALE, YPOS + _echoOutputSamples[i]/YSCALE); + } + glEnd(); +} + // Take a pointer to the acquired microphone input samples and add procedural sounds void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; @@ -331,10 +369,27 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((cosf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); } } } + +void Audio::startEchoTest() { + _startEcho = true; + _echoPingFrameCount = 0; + _sendingEchoPing = true; + _gatheringEchoFrames = false; +} + +void Audio::addedPingFrame() { + const int ECHO_PING_FRAMES = 1; + _echoPingFrameCount++; + if (_echoPingFrameCount == ECHO_PING_FRAMES) { + _gatheringEchoFrames = false; + _sendingEchoPing = false; + //startEchoTest(); + } +} void Audio::analyzeEcho(int16_t* inputBuffer, int16_t* outputBuffer, int numSamples) { // Compare output and input streams, looking for evidence of correlation needing echo cancellation // @@ -385,7 +440,6 @@ void Audio::addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBy if (::stdev.getSamples() > 500) { _measuredJitter = ::stdev.getStDev(); - //printLog("Avg: %4.2f, Stdev: %4.2f\n", stdev.getAverage(), sharedAudioData->measuredJitter); ::stdev.reset(); } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index eb5021d10e..28d47a68d8 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -36,6 +36,11 @@ public: void addReceivedAudioToBuffer(unsigned char* receivedData, int receivedBytes); + + void startEchoTest(); + void addedPingFrame(); + void renderEchoCompare(); + private: PaStream* _stream; AudioRingBuffer _ringBuffer; @@ -52,6 +57,12 @@ private: int _totalPacketsReceived; timeval _firstPlaybackTime; int _packetsReceivedThisPlayback; + bool _startEcho; + bool _sendingEchoPing; + int _echoPingFrameCount; + int16_t* _echoInputSamples; + int16_t* _echoOutputSamples; + bool _gatheringEchoFrames; // give access to AudioData class from audioCallback friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); diff --git a/interface/src/AudioData.cpp b/interface/src/AudioData.cpp deleted file mode 100644 index faa0a27a83..0000000000 --- a/interface/src/AudioData.cpp +++ /dev/null @@ -1,79 +0,0 @@ -// -// AudioData.cpp -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// -#ifndef _WIN32 - -#include "AudioData.h" - -AudioData::AudioData() { - mixerAddress = 0; - mixerPort = 0; - - averagedLatency = 0.0; - lastCallback.tv_usec = 0; - wasStarved = 0; - measuredJitter = 0; - jitterBuffer = 0; - - mixerLoopbackFlag = false; - audioSocket = NULL; -} - - -AudioData::~AudioData() { - delete audioSocket; -} - -// Take a pointer to the acquired microphone input samples and add procedural sounds -void AudioData::addProceduralSounds(int16_t* inputBuffer, int numSamples) { - const float MAX_AUDIBLE_VELOCITY = 6.0; - const float MIN_AUDIBLE_VELOCITY = 0.1; - float speed = glm::length(_lastVelocity); - float volume = 400 * (1.f - speed/MAX_AUDIBLE_VELOCITY); - // Add a noise-modulated sinewave with volume that tapers off with speed increasing - if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { - for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t) ((cosf((float)i / 8.f * speed) * randFloat()) * volume * speed) ; - } - } - - return; -} - -void AudioData::analyzeEcho(int16_t* inputBuffer, int16_t* outputBuffer, int numSamples) { - // Compare output and input streams, looking for evidence of correlation needing echo cancellation - // - // OFFSET_RANGE tells us how many samples to vary the analysis window when looking for correlation, - // and should be equal to the largest physical distance between speaker and microphone, where - // OFFSET_RANGE = 1 / (speedOfSound (meters / sec) / SamplingRate (samples / sec)) * distance - // - const int OFFSET_RANGE = 10; - const int SIGNAL_FLOOR = 1000; - float correlation[2 * OFFSET_RANGE + 1]; - int numChecked = 0; - bool foundSignal = false; - for (int offset = -OFFSET_RANGE; offset <= OFFSET_RANGE; offset++) { - for (int i = 0; i < numSamples; i++) { - if ((i + offset >= 0) && (i + offset < numSamples)) { - correlation[offset + OFFSET_RANGE] += - (float) abs(inputBuffer[i] - outputBuffer[i + offset]); - numChecked++; - foundSignal |= (inputBuffer[i] > SIGNAL_FLOOR); - } - } - correlation[offset + OFFSET_RANGE] /= numChecked; - numChecked = 0; - if (foundSignal) { - printLog("%4.2f, ", correlation[offset + OFFSET_RANGE]); - } - } - if (foundSignal) printLog("\n"); -} - - - -#endif diff --git a/interface/src/AudioData.h b/interface/src/AudioData.h deleted file mode 100644 index a98c40b38a..0000000000 --- a/interface/src/AudioData.h +++ /dev/null @@ -1,55 +0,0 @@ -// -// AudioData.h -// interface -// -// Created by Stephen Birarda on 1/29/13. -// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. -// - -#ifndef __interface__AudioData__ -#define __interface__AudioData__ - -#include -#include -#include "AudioRingBuffer.h" -#include "UDPSocket.h" -#include "Avatar.h" - -class AudioData { - public: - AudioData(); - ~AudioData(); - AudioRingBuffer *ringBuffer; - - UDPSocket *audioSocket; - - Avatar *linkedAvatar; - - // store current mixer address and port - in_addr_t mixerAddress; - in_port_t mixerPort; - - timeval lastCallback; - float averagedLatency; - float measuredJitter; - float jitterBuffer; - int wasStarved; - - float lastInputLoudness; - - bool mixerLoopbackFlag; - - // Added avatar acceleration and velocity for procedural effects sounds from client - void setLastVelocity(glm::vec3 v) { _lastVelocity = v; }; - void setLastAcceleration(glm::vec3 a) { _lastAcceleration = a; }; - void addProceduralSounds(int16_t* inputBuffer, int numSamples); - void analyzeEcho(int16_t* inputBuffer, int16_t* outputBuffer, int numSamples); - - private: - glm::vec3 _lastVelocity; - glm::vec3 _lastAcceleration; - - -}; - -#endif /* defined(__interface__AudioData__) */ diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp index e34903b298..ae984ebe61 100644 --- a/interface/src/Oscilloscope.cpp +++ b/interface/src/Oscilloscope.cpp @@ -113,18 +113,19 @@ void Oscilloscope::render(int x, int y) { } } - glLineWidth(2.0); + glLineWidth(1.0); + glDisable(GL_LINE_SMOOTH); glPushMatrix(); glTranslatef((float)x + 0.0f, (float)y + _valHeight / 2.0f, 0.0f); glScaled(1.0f, _valHeight / 32767.0f, 1.0f); glVertexPointer(2, GL_SHORT, 0, _arrVertices); glEnableClientState(GL_VERTEX_ARRAY); glColor3f(1.0f, 1.0f, 1.0f); - glDrawArrays(GL_LINES, MAX_SAMPLES * 0, usedWidth); + glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 0, usedWidth); glColor3f(0.0f, 1.0f ,1.0f); - glDrawArrays(GL_LINES, MAX_SAMPLES * 1, usedWidth); + glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 1, usedWidth); glColor3f(0.0f, 1.0f ,1.0f); - glDrawArrays(GL_LINES, MAX_SAMPLES * 2, usedWidth); + glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 2, usedWidth); glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); } From 0a6b4702c6afa062433f167080b61ca4ab7cf42a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Wed, 15 May 2013 22:18:56 -0700 Subject: [PATCH 10/24] Experimenting with simple Perlin noise shader for voxels. --- .../resources/shaders/grainy_voxels.frag | 57 +++++++++++++++++++ .../resources/shaders/grainy_voxels.vert | 20 +++++++ interface/src/VoxelSystem.cpp | 40 +++++++++++++ interface/src/VoxelSystem.h | 5 ++ 4 files changed, 122 insertions(+) create mode 100644 interface/resources/shaders/grainy_voxels.frag create mode 100644 interface/resources/shaders/grainy_voxels.vert diff --git a/interface/resources/shaders/grainy_voxels.frag b/interface/resources/shaders/grainy_voxels.frag new file mode 100644 index 0000000000..a01de0c577 --- /dev/null +++ b/interface/resources/shaders/grainy_voxels.frag @@ -0,0 +1,57 @@ +// +// grainy_voxels.frag +// fragment shader +// +// Created by Andrzej Kapolka on 5/15/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#version 120 + +// the texture containing our permutations and normals +uniform sampler2D permutationNormalTexture; + +// the position in model space +varying vec3 position; + +// returns the gradient at a single corner of our sampling cube +vec3 grad(vec3 location) { + float p1 = texture2D(permutationNormalTexture, vec2(location.x / 256.0, 0.25)).r; + float p2 = texture2D(permutationNormalTexture, vec2(p1 + location.y / 256.0, 0.25)).r; + return texture2D(permutationNormalTexture, vec2(p2 + location.z / 256.0, 0.75)).xyz * 2.0 - vec3(1.0, 1.0, 1.0); +} + +// returns the perlin noise value for the specified location +float perlin(vec3 location) { + vec3 floors = floor(location); + vec3 ceils = ceil(location); + vec3 fff = grad(floors); + vec3 ffc = grad(vec3(floors.x, floors.y, ceils.z)); + vec3 fcf = grad(vec3(floors.x, ceils.y, floors.z)); + vec3 fcc = grad(vec3(floors.x, ceils.y, ceils.z)); + vec3 cff = grad(vec3(ceils.x, floors.y, floors.z)); + vec3 cfc = grad(vec3(ceils.x, floors.y, ceils.z)); + vec3 ccf = grad(vec3(ceils.x, ceils.y, floors.z)); + vec3 ccc = grad(ceils); + vec3 ffracts = fract(location); + vec3 cfracts = ffracts - vec3(1.0, 1.0, 1.0); + vec3 params = ffracts*ffracts*(3.0 - 2.0*ffracts); + + float fffv = dot(fff, ffracts); + float ffcv = dot(ffc, vec3(ffracts.x, ffracts.y, cfracts.z)); + float fcfv = dot(fcf, vec3(ffracts.x, cfracts.y, ffracts.z)); + float fccv = dot(fcc, vec3(ffracts.x, cfracts.y, cfracts.z)); + float cffv = dot(cff, vec3(cfracts.x, ffracts.y, ffracts.z)); + float cfcv = dot(cfc, vec3(cfracts.x, ffracts.y, cfracts.z)); + float ccfv = dot(ccf, vec3(cfracts.x, cfracts.y, ffracts.z)); + float cccv = dot(ccc, cfracts); + + return mix( + mix(mix(fffv, cffv, params.x), mix(fcfv, ccfv, params.x), params.y), + mix(mix(ffcv, cfcv, params.x), mix(fccv, cccv, params.x), params.y), + params.z); +} + +void main(void) { + gl_FragColor = vec4(gl_Color.rgb * (0.85 + perlin(position * 1024.0) * 0.15), 1.0); +} diff --git a/interface/resources/shaders/grainy_voxels.vert b/interface/resources/shaders/grainy_voxels.vert new file mode 100644 index 0000000000..856b4e7955 --- /dev/null +++ b/interface/resources/shaders/grainy_voxels.vert @@ -0,0 +1,20 @@ +// +// grainy_voxels.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#version 120 + +// the position in model space +varying vec3 position; + +void main(void) { + position = gl_Vertex.xyz; + vec4 normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); + gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + + gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); + gl_Position = ftransform(); +} diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 513253ec19..7ad967491d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -13,6 +13,7 @@ #include #include // to load voxels from file #include // to load voxels from file +#include #include #include #include @@ -20,6 +21,8 @@ #include #include "Log.h" #include "VoxelConstants.h" +#include "InterfaceConfig.h" +#include "renderer/ProgramObject.h" #include "VoxelSystem.h" @@ -497,6 +500,37 @@ void VoxelSystem::init() { // delete the indices and normals arrays that are no longer needed delete[] indicesArray; delete[] normalsArray; + + // create our simple fragment shader + switchToResourcesParentIfRequired(); + _grainProgram = new ProgramObject(); + _grainProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/grainy_voxels.vert"); + _grainProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/grainy_voxels.frag"); + _grainProgram->link(); + + _grainProgram->setUniformValue("permutationNormalTexture", 0); + + // create the permutation/normal texture + glGenTextures(1, &_permutationNormalTextureID); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + + // the first line consists of random permutation offsets + unsigned char data[256 * 2 * 3]; + for (int i = 0; i < 256 * 3; i++) { + data[i] = rand() % 256; + } + // the next, random unit normals + for (int i = 256 * 3; i < 256 * 3 * 2; i += 3) { + glm::vec3 randvec = glm::sphericalRand(1.0f); + data[i] = ((randvec.x + 1.0f) / 2.0f) * 255.0f; + data[i + 1] = ((randvec.y + 1.0f) / 2.0f) * 255.0f; + data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f; + } + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 256, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glBindTexture(GL_TEXTURE_2D, 0); } void VoxelSystem::updateFullVBOs() { @@ -606,11 +640,17 @@ void VoxelSystem::render() { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); + _grainProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); + _grainProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 50997d84bf..61ed570563 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -21,6 +21,8 @@ #include "Util.h" #include "world.h" +class ProgramObject; + const int NUM_CHILDREN = 8; class VoxelSystem : public AgentData { @@ -133,6 +135,9 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; + ProgramObject* _grainProgram; + GLuint _permutationNormalTextureID; + ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; From 1b039c37555cf8607ae98be4d0b9f62ee4542e8a Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 16 May 2013 00:10:10 -0600 Subject: [PATCH 11/24] Transmitter V2 drives the hand, and rendering levels with 'l' shows the hand transmitter data. Physics will need to be tuned. --- interface/src/Application.cpp | 29 ++++- interface/src/Avatar.cpp | 185 +++++++++++++----------------- interface/src/Avatar.h | 9 ++ interface/src/Oscilloscope.cpp | 2 +- interface/src/SerialInterface.cpp | 2 +- interface/src/world.h | 1 + 6 files changed, 116 insertions(+), 112 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 80c7349e01..8ae9d79f3e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -774,11 +774,20 @@ void Application::idle() { if (diffclock(&_lastTimeIdle, &check) > IDLE_SIMULATE_MSECS) { float deltaTime = 1.f/_fps; - - // update behaviors for avatar hand movement: handControl takes mouse values as input, - // and gives back 3D values modulated for smooth transitioning between interaction modes. - _handControl.update(_mouseX, _mouseY); - _myAvatar.setHandMovementValues(_handControl.getValues()); + + // Use Transmitter Hand to move hand if connected, else use mouse + if (_myAvatar.transmitterV2IsConnected()) { + const float HAND_FORCE_SCALING = 0.05f; + const float* handAcceleration = _myAvatar.getTransmitterHandLastAcceleration(); + _myAvatar.setHandMovementValues(glm::vec3(-handAcceleration[0] * HAND_FORCE_SCALING, + handAcceleration[1] * HAND_FORCE_SCALING, + handAcceleration[2] * HAND_FORCE_SCALING)); + } else { + // update behaviors for avatar hand movement: handControl takes mouse values as input, + // and gives back 3D values modulated for smooth transitioning between interaction modes. + _handControl.update(_mouseX, _mouseY); + _myAvatar.setHandMovementValues(_handControl.getValues()); + } // tell my avatar if the mouse is being pressed... _myAvatar.setMousePressed(_mousePressed); @@ -1668,6 +1677,10 @@ void Application::displayOverlay() { // Show detected levels from the serial I/O ADC channel sensors if (_displayLevels) _serialPort.renderLevels(_glWidget->width(), _glWidget->height()); + // Show hand transmitter data if detected + if (_myAvatar.transmitterV2IsConnected()) { + _myAvatar.transmitterV2RenderLevels(_glWidget->width(), _glWidget->height()); + } // Display stats and log text onscreen glLineWidth(1.0f); glPointSize(1.0f); @@ -2020,13 +2033,17 @@ void* Application::networkReceive(void* args) { app->_myAvatar.processTransmitterData(app->_incomingPacket, bytesReceived); break; case PACKET_HEADER_TRANSMITTER_DATA_V2: + /* float rotationRates[3]; float accelerations[3]; memcpy(rotationRates, app->_incomingPacket + 2, sizeof(rotationRates)); memcpy(accelerations, app->_incomingPacket + 3 + sizeof(rotationRates), sizeof(accelerations)); - printf("The rotation: %f, %f, %f\n", rotationRates[0], rotationRates[1], rotationRates[2]); + printf("Acceleration: %f, %f, %f\n", accelerations[0], accelerations[1], accelerations[2]); + */ + app->_myAvatar.processTransmitterDataV2(app->_incomingPacket, bytesReceived); + break; case PACKET_HEADER_MIXED_AUDIO: app->_audio.addReceivedAudioToBuffer(app->_incomingPacket, bytesReceived); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index ef56fe23b7..26d19b267d 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -10,6 +10,7 @@ #include #include #include +#include "world.h" #include "Avatar.h" #include "Head.h" #include "Log.h" @@ -82,6 +83,7 @@ Avatar::Avatar(bool isMine) { _transmitterPackets = 0; _transmitterIsFirstData = true; _transmitterInitialReading = glm::vec3(0.f, 0.f, 0.f); + _transmitterV2IsConnected = false; _speed = 0.0; _pelvisStandingHeight = 0.0f; _displayingHead = true; @@ -131,6 +133,7 @@ Avatar::Avatar(const Avatar &otherAvatar) { _transmitterHz = otherAvatar._transmitterHz; _transmitterInitialReading = otherAvatar._transmitterInitialReading; _transmitterPackets = otherAvatar._transmitterPackets; + _transmitterV2IsConnected = otherAvatar._transmitterV2IsConnected; _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; _movedHandOffset = otherAvatar._movedHandOffset; @@ -610,110 +613,6 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { void Avatar::updateHead(float deltaTime) { -/* - // Decay head back to center if turned on - if (_isMine && _returnHeadToCenter) { - // Decay back toward center - _headPitch *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); - _headYaw *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); - _headRoll *= (1.0f - DECAY * _head.returnSpringScale * 2 * deltaTime); - } - - // For invensense gyro, decay only slightly when roughly centered - if (_isMine) { - const float RETURN_RANGE = 15.0; - const float RETURN_STRENGTH = 2.0; - if (fabs(_headPitch) < RETURN_RANGE) { _headPitch *= (1.0f - RETURN_STRENGTH * deltaTime); } - if (fabs(_headYaw) < RETURN_RANGE) { _headYaw *= (1.0f - RETURN_STRENGTH * deltaTime); } - if (fabs(_headRoll) < RETURN_RANGE) { _headRoll *= (1.0f - RETURN_STRENGTH * deltaTime); } - } - - if (_head.noise) { - // Move toward new target - _headPitch += (_head.pitchTarget - _headPitch) * 10 * deltaTime; // (1.f - DECAY*deltaTime)*Pitch + ; - _headYaw += (_head.yawTarget - _headYaw ) * 10 * deltaTime; // (1.f - DECAY*deltaTime); - _headRoll *= 1.f - (DECAY * deltaTime); - } - - _head.leanForward *= (1.f - DECAY * 30 * deltaTime); - _head.leanSideways *= (1.f - DECAY * 30 * deltaTime); - - // Update where the avatar's eyes are - // - // First, decide if we are making eye contact or not - if (randFloat() < 0.005) { - _head.eyeContact = !_head.eyeContact; - _head.eyeContact = 1; - if (!_head.eyeContact) { - // If we just stopped making eye contact,move the eyes markedly away - _head.eyeballPitch[0] = _head.eyeballPitch[1] = _head.eyeballPitch[0] + 5.0 + (randFloat() - 0.5) * 10; - _head.eyeballYaw [0] = _head.eyeballYaw [1] = _head.eyeballYaw [0] + 5.0 + (randFloat() - 0.5) * 5; - } else { - // If now making eye contact, turn head to look right at viewer - SetNewHeadTarget(0,0); - } - } - - const float DEGREES_BETWEEN_VIEWER_EYES = 3; - const float DEGREES_TO_VIEWER_MOUTH = 7; - - if (_head.eyeContact) { - // Should we pick a new eye contact target? - if (randFloat() < 0.01) { - // Choose where to look next - if (randFloat() < 0.1) { - _head.eyeContactTarget = MOUTH; - } else { - if (randFloat() < 0.5) _head.eyeContactTarget = LEFT_EYE; else _head.eyeContactTarget = RIGHT_EYE; - } - } - // Set eyeball pitch and yaw to make contact - float eye_target_yaw_adjust = 0; - float eye_target_pitch_adjust = 0; - if (_head.eyeContactTarget == LEFT_EYE) eye_target_yaw_adjust = DEGREES_BETWEEN_VIEWER_EYES; - if (_head.eyeContactTarget == RIGHT_EYE) eye_target_yaw_adjust = -DEGREES_BETWEEN_VIEWER_EYES; - if (_head.eyeContactTarget == MOUTH) eye_target_pitch_adjust = DEGREES_TO_VIEWER_MOUTH; - - _head.eyeballPitch[0] = _head.eyeballPitch[1] = -_headPitch + eye_target_pitch_adjust; - _head.eyeballYaw[0] = _head.eyeballYaw[1] = -_headYaw + eye_target_yaw_adjust; - } - - if (_head.noise) - { - _headPitch += (randFloat() - 0.5) * 0.2 * _head.noiseEnvelope; - _headYaw += (randFloat() - 0.5) * 0.3 *_head.noiseEnvelope; - //PupilSize += (randFloat() - 0.5) * 0.001*NoiseEnvelope; - - if (randFloat() < 0.005) _head.mouthWidth = MouthWidthChoices[rand()%3]; - - if (!_head.eyeContact) { - if (randFloat() < 0.01) _head.eyeballPitch[0] = _head.eyeballPitch[1] = (randFloat() - 0.5) * 20; - if (randFloat() < 0.01) _head.eyeballYaw[0] = _head.eyeballYaw[1] = (randFloat()- 0.5) * 10; - } - - if ((randFloat() < 0.005) && (fabs(_head.pitchTarget - _headPitch) < 1.0) && (fabs(_head.yawTarget - _headYaw) < 1.0)) { - SetNewHeadTarget((randFloat()-0.5) * 20.0, (randFloat()-0.5) * 45.0); - } - - if (0) { - - // Pick new target - _head.pitchTarget = (randFloat() - 0.5) * 45; - _head.yawTarget = (randFloat() - 0.5) * 22; - } - if (randFloat() < 0.01) - { - _head.eyebrowPitch[0] = _head.eyebrowPitch[1] = BrowPitchAngle[rand()%3]; - _head.eyebrowRoll [0] = _head.eyebrowRoll[1] = BrowRollAngle[rand()%5]; - _head.eyebrowRoll [1] *=-1; - } - } - - // Update audio trailing average for rendering facial animations - const float AUDIO_AVERAGING_SECS = 0.05; - _head.averageLoudness = (1.f - deltaTime / AUDIO_AVERAGING_SECS) * _head.averageLoudness + - (deltaTime / AUDIO_AVERAGING_SECS) * _audioLoudness; -*/ } @@ -1425,6 +1324,84 @@ void Avatar::processTransmitterData(unsigned char* packetData, int numBytes) { } } +// +// Process UDP data from version 2 Transmitter acting as Hand +// +void Avatar::processTransmitterDataV2(unsigned char* packetData, int numBytes) { + if (numBytes == 3 + sizeof(_transmitterHandLastRotationRates) + + sizeof(_transmitterHandLastAcceleration)) { + memcpy(_transmitterHandLastRotationRates, packetData + 2, + sizeof(_transmitterHandLastRotationRates)); + memcpy(_transmitterHandLastAcceleration, packetData + 3 + + sizeof(_transmitterHandLastRotationRates), + sizeof(_transmitterHandLastAcceleration)); + // Convert from transmitter units to internal units + for (int i = 0; i < 3; i++) { + _transmitterHandLastRotationRates[i] *= 180.f / PI; + _transmitterHandLastAcceleration[i] *= GRAVITY_EARTH; + } + if (!_transmitterV2IsConnected) { + printf("Transmitter V2 Connected.\n"); + _transmitterV2IsConnected = true; + } + } else { + printf("Transmitter V2 packet read error.\n"); + } +} + +void Avatar::transmitterV2RenderLevels(int width, int height) { + + char val[50]; + const int LEVEL_CORNER_X = 10; + const int LEVEL_CORNER_Y = 400; + + // Draw the numeric degree/sec values from the gyros + sprintf(val, "Yaw %4.1f", _transmitterHandLastRotationRates[1]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y, 0.10, 0, 1.0, 1, val, 0, 1, 0); + sprintf(val, "Pitch %4.1f", _transmitterHandLastRotationRates[0]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 15, 0.10, 0, 1.0, 1, val, 0, 1, 0); + sprintf(val, "Roll %4.1f", _transmitterHandLastRotationRates[2]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 30, 0.10, 0, 1.0, 1, val, 0, 1, 0); + sprintf(val, "X %4.3f", _transmitterHandLastAcceleration[0]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 45, 0.10, 0, 1.0, 1, val, 0, 1, 0); + sprintf(val, "Y %4.3f", _transmitterHandLastAcceleration[1]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 60, 0.10, 0, 1.0, 1, val, 0, 1, 0); + sprintf(val, "Z %4.3f", _transmitterHandLastAcceleration[2]); + drawtext(LEVEL_CORNER_X, LEVEL_CORNER_Y + 75, 0.10, 0, 1.0, 1, val, 0, 1, 0); + + // Draw the levels as horizontal lines + const int LEVEL_CENTER = 150; + const float ACCEL_VIEW_SCALING = 50.f; + glLineWidth(2.0); + glColor4f(1, 1, 1, 1); + glBegin(GL_LINES); + // Gyro rates + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 3); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[1], LEVEL_CORNER_Y - 3); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 12); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[0], LEVEL_CORNER_Y + 12); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 27); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + _transmitterHandLastRotationRates[2], LEVEL_CORNER_Y + 27); + // Acceleration + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 42); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[0] * ACCEL_VIEW_SCALING), + LEVEL_CORNER_Y + 42); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 57); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[1] * ACCEL_VIEW_SCALING), + LEVEL_CORNER_Y + 57); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 72); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER + (int)(_transmitterHandLastAcceleration[2] * ACCEL_VIEW_SCALING), + LEVEL_CORNER_Y + 72); + + glEnd(); + // Draw green vertical centerline + glColor4f(0, 1, 0, 0.5); + glBegin(GL_LINES); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y - 6); + glVertex2f(LEVEL_CORNER_X + LEVEL_CENTER, LEVEL_CORNER_Y + 30); + glEnd(); +} + void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity, float deltaTime, float smoothingTime) { // diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index a6b3a9901c..0f33d5d195 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -127,6 +127,12 @@ public: // Related to getting transmitter UDP data used to animate the avatar hand void processTransmitterData(unsigned char * packetData, int numBytes); + void processTransmitterDataV2(unsigned char * packetData, int numBytes); + const bool transmitterV2IsConnected() const { return _transmitterV2IsConnected; }; + const float* getTransmitterHandLastAcceleration() const { return _transmitterHandLastAcceleration; }; + const float* getTransmitterHandLastRotationRates() const { return _transmitterHandLastRotationRates; }; + void transmitterV2RenderLevels(int width, int height); + float getTransmitterHz() { return _transmitterHz; }; void writeAvatarDataToFile(); @@ -181,6 +187,9 @@ private: float _transmitterHz; int _transmitterPackets; glm::vec3 _transmitterInitialReading; + float _transmitterHandLastRotationRates[3]; + float _transmitterHandLastAcceleration[3]; + bool _transmitterV2IsConnected; float _pelvisStandingHeight; float _height; Balls* _balls; diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp index ae984ebe61..d081dbb0dc 100644 --- a/interface/src/Oscilloscope.cpp +++ b/interface/src/Oscilloscope.cpp @@ -125,7 +125,7 @@ void Oscilloscope::render(int x, int y) { glColor3f(0.0f, 1.0f ,1.0f); glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 1, usedWidth); glColor3f(0.0f, 1.0f ,1.0f); - glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 2, usedWidth); + glDrawArrays(GL_LINE_STRIP, MAX_SAMPLES * 2, usedWidth); glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); } diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index 9fb022471f..233a004568 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -187,7 +187,7 @@ void SerialInterface::readData() { convertHexToInt(sensorBuffer + 10, accelYRate); convertHexToInt(sensorBuffer + 14, accelXRate); - const float LSB_TO_METERS_PER_SECOND2 = 1.f / 16384.f * 9.80665f; + const float LSB_TO_METERS_PER_SECOND2 = 1.f / 16384.f * GRAVITY_EARTH; // From MPU-9150 register map, with setting on // highest resolution = +/- 2G diff --git a/interface/src/world.h b/interface/src/world.h index 5b43e5a760..7d22aab6a2 100644 --- a/interface/src/world.h +++ b/interface/src/world.h @@ -15,5 +15,6 @@ const float WORLD_SIZE = 10.0; #define PI 3.14159265 #define PIf 3.14159265f +#define GRAVITY_EARTH 9.80665f; #endif From 78bd5ab40f4ddf7f360dc357a5eb8cbe942959d1 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 16 May 2013 13:34:48 -0600 Subject: [PATCH 12/24] Fixes per review --- interface/src/Application.cpp | 27 ++++++++++++--------------- interface/src/Audio.cpp | 28 ++++++++++++++-------------- interface/src/Audio.h | 6 +++--- interface/src/Avatar.cpp | 14 +++++--------- interface/src/Avatar.h | 4 ++-- interface/src/Head.cpp | 8 ++++++-- 6 files changed, 42 insertions(+), 45 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8ae9d79f3e..6d1e6fd9f3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -295,17 +295,22 @@ void Application::paintGL() { } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getBodyYaw() - 180.0f, 0.0f, 0.0f); + _myCamera.setTargetRotation(_myAvatar.getBodyYaw() - 180.0f, + 0.0f, + 0.0f); } else { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(), - _myAvatar.getAbsoluteHeadPitch(), 0.0f); + _myAvatar.getAbsoluteHeadPitch(), + 0.0f); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); - _myCamera.setTargetRotation(_myAvatar.getBodyYaw(), 0.0f, 0.0f); + _myCamera.setTargetRotation(_myAvatar.getBodyYaw(), + 0.0f, + 0.0f); } } @@ -776,7 +781,7 @@ void Application::idle() { float deltaTime = 1.f/_fps; // Use Transmitter Hand to move hand if connected, else use mouse - if (_myAvatar.transmitterV2IsConnected()) { + if (_myAvatar.isTransmitterV2Connected()) { const float HAND_FORCE_SCALING = 0.05f; const float* handAcceleration = _myAvatar.getTransmitterHandLastAcceleration(); _myAvatar.setHandMovementValues(glm::vec3(-handAcceleration[0] * HAND_FORCE_SCALING, @@ -1678,7 +1683,7 @@ void Application::displayOverlay() { if (_displayLevels) _serialPort.renderLevels(_glWidget->width(), _glWidget->height()); // Show hand transmitter data if detected - if (_myAvatar.transmitterV2IsConnected()) { + if (_myAvatar.isTransmitterV2Connected()) { _myAvatar.transmitterV2RenderLevels(_glWidget->width(), _glWidget->height()); } // Display stats and log text onscreen @@ -2029,19 +2034,11 @@ void* Application::networkReceive(void* args) { switch (app->_incomingPacket[0]) { case PACKET_HEADER_TRANSMITTER_DATA_V1: - // Process UDP packets that are sent to the client from local sensor devices + // V1 = android app, or the Google Glass app->_myAvatar.processTransmitterData(app->_incomingPacket, bytesReceived); break; case PACKET_HEADER_TRANSMITTER_DATA_V2: - /* - float rotationRates[3]; - float accelerations[3]; - - memcpy(rotationRates, app->_incomingPacket + 2, sizeof(rotationRates)); - memcpy(accelerations, app->_incomingPacket + 3 + sizeof(rotationRates), sizeof(accelerations)); - - printf("Acceleration: %f, %f, %f\n", accelerations[0], accelerations[1], accelerations[2]); - */ + // V2 = IOS transmitter app app->_myAvatar.processTransmitterDataV2(app->_incomingPacket, bytesReceived); break; diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index e782808c33..5bca301552 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -87,9 +87,9 @@ int audioCallback (const void* inputBuffer, Application* interface = (Application*) QCoreApplication::instance(); Avatar* interfaceAvatar = interface->getAvatar(); - int16_t *inputLeft = ((int16_t **) inputBuffer)[0]; - int16_t *outputLeft = ((int16_t **) outputBuffer)[0]; - int16_t *outputRight = ((int16_t **) outputBuffer)[1]; + int16_t* inputLeft = ((int16_t**) inputBuffer)[0]; + int16_t* outputLeft = ((int16_t**) outputBuffer)[0]; + int16_t* outputRight = ((int16_t**) outputBuffer)[1]; // Add Procedural effects to input samples parentAudio->addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES); @@ -99,7 +99,7 @@ int audioCallback (const void* inputBuffer, parentAudio->_scope->addSamples(2, outputRight, PACKET_LENGTH_SAMPLES_PER_CHANNEL); // if needed, add input/output data to echo analysis buffers - if (parentAudio->_gatheringEchoFrames) { + if (parentAudio->_isGatheringEchoFrames) { memcpy(parentAudio->_echoInputSamples, inputLeft, PACKET_LENGTH_SAMPLES_PER_CHANNEL * sizeof(int16_t)); memcpy(parentAudio->_echoOutputSamples, outputLeft, @@ -267,13 +267,13 @@ int audioCallback (const void* inputBuffer, } } } - if (parentAudio->_sendingEchoPing) { + if (parentAudio->_isSendingEchoPing) { const float PING_PITCH = 4.f; const float PING_VOLUME = 32000.f; for (int s = 0; s < PACKET_LENGTH_SAMPLES_PER_CHANNEL; s++) { outputLeft[s] = outputRight[s] = (int16_t)(sinf((float) s / PING_PITCH) * PING_VOLUME); } - parentAudio->_gatheringEchoFrames = true; + parentAudio->_isGatheringEchoFrames = true; } gettimeofday(&parentAudio->_lastCallbackTime, NULL); return paContinue; @@ -301,10 +301,10 @@ Audio::Audio(Oscilloscope* scope) : _totalPacketsReceived(0), _firstPlaybackTime(), _packetsReceivedThisPlayback(0), - _startEcho(false), - _sendingEchoPing(false), + _shouldStartEcho(false), + _isSendingEchoPing(false), _echoPingFrameCount(0), - _gatheringEchoFrames(false) + _isGatheringEchoFrames(false) { outputPortAudioError(Pa_Initialize()); outputPortAudioError(Pa_OpenDefaultStream(&_stream, @@ -375,18 +375,18 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { } void Audio::startEchoTest() { - _startEcho = true; + _shouldStartEcho = true; _echoPingFrameCount = 0; - _sendingEchoPing = true; - _gatheringEchoFrames = false; + _isSendingEchoPing = true; + _isGatheringEchoFrames = false; } void Audio::addedPingFrame() { const int ECHO_PING_FRAMES = 1; _echoPingFrameCount++; if (_echoPingFrameCount == ECHO_PING_FRAMES) { - _gatheringEchoFrames = false; - _sendingEchoPing = false; + _isGatheringEchoFrames = false; + _isSendingEchoPing = false; //startEchoTest(); } } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index 28d47a68d8..2eae70bb34 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -57,12 +57,12 @@ private: int _totalPacketsReceived; timeval _firstPlaybackTime; int _packetsReceivedThisPlayback; - bool _startEcho; - bool _sendingEchoPing; + bool _shouldStartEcho; + bool _isSendingEchoPing; int _echoPingFrameCount; int16_t* _echoInputSamples; int16_t* _echoOutputSamples; - bool _gatheringEchoFrames; + bool _isGatheringEchoFrames; // give access to AudioData class from audioCallback friend int audioCallback (const void*, void*, unsigned long, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 26d19b267d..03c803b798 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -83,7 +83,7 @@ Avatar::Avatar(bool isMine) { _transmitterPackets = 0; _transmitterIsFirstData = true; _transmitterInitialReading = glm::vec3(0.f, 0.f, 0.f); - _transmitterV2IsConnected = false; + _isTransmitterV2Connected = false; _speed = 0.0; _pelvisStandingHeight = 0.0f; _displayingHead = true; @@ -133,7 +133,7 @@ Avatar::Avatar(const Avatar &otherAvatar) { _transmitterHz = otherAvatar._transmitterHz; _transmitterInitialReading = otherAvatar._transmitterInitialReading; _transmitterPackets = otherAvatar._transmitterPackets; - _transmitterV2IsConnected = otherAvatar._transmitterV2IsConnected; + _isTransmitterV2Connected = otherAvatar._isTransmitterV2Connected; _TEST_bigSphereRadius = otherAvatar._TEST_bigSphereRadius; _TEST_bigSpherePosition = otherAvatar._TEST_bigSpherePosition; _movedHandOffset = otherAvatar._movedHandOffset; @@ -299,11 +299,7 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree if (fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) { float mouseMag = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; - setBodyYaw(getBodyYaw() - - ((mouseLocationX > 0.f) ? - mouseMag : - -mouseMag) ); - //printLog("yaw = %f\n", getBodyYaw()); + setBodyYaw(getBodyYaw() - ((mouseLocationX > 0.f) ? mouseMag : -mouseMag)); } return; @@ -1340,9 +1336,9 @@ void Avatar::processTransmitterDataV2(unsigned char* packetData, int numBytes) { _transmitterHandLastRotationRates[i] *= 180.f / PI; _transmitterHandLastAcceleration[i] *= GRAVITY_EARTH; } - if (!_transmitterV2IsConnected) { + if (!_isTransmitterV2Connected) { printf("Transmitter V2 Connected.\n"); - _transmitterV2IsConnected = true; + _isTransmitterV2Connected = true; } } else { printf("Transmitter V2 packet read error.\n"); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 0f33d5d195..b653440461 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -128,7 +128,7 @@ public: // Related to getting transmitter UDP data used to animate the avatar hand void processTransmitterData(unsigned char * packetData, int numBytes); void processTransmitterDataV2(unsigned char * packetData, int numBytes); - const bool transmitterV2IsConnected() const { return _transmitterV2IsConnected; }; + const bool isTransmitterV2Connected() const { return _isTransmitterV2Connected; }; const float* getTransmitterHandLastAcceleration() const { return _transmitterHandLastAcceleration; }; const float* getTransmitterHandLastRotationRates() const { return _transmitterHandLastRotationRates; }; void transmitterV2RenderLevels(int width, int height); @@ -189,7 +189,7 @@ private: glm::vec3 _transmitterInitialReading; float _transmitterHandLastRotationRates[3]; float _transmitterHandLastAcceleration[3]; - bool _transmitterV2IsConnected; + bool _isTransmitterV2Connected; float _pelvisStandingHeight; float _height; Balls* _balls; diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index d94d9197a9..ebedb44397 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -292,6 +292,10 @@ void Head::render(bool lookingInMirror, float bodyYaw) { glPopMatrix(); // Mouth + const float MIN_LOUDNESS_SCALE_WIDTH = 0.7f; + const float WIDTH_SENSITIVITY = 60.f; + const float HEIGHT_SENSITIVITY = 30.f; + const float MIN_LOUDNESS_SCALE_HEIGHT = 1.0f; glPushMatrix(); glTranslatef(0,-0.35,0.75); glColor3f(0,0,0); @@ -299,8 +303,8 @@ void Head::render(bool lookingInMirror, float bodyYaw) { glRotatef(mouthYaw, 0, 0, 1); if ((averageLoudness > 1.f) && (averageLoudness < 10000.f)) { - glScalef(mouthWidth * (.7f + sqrt(averageLoudness) / 60.f), - mouthHeight * (1.f + sqrt(averageLoudness) / 30.f), 1); + glScalef(mouthWidth * (MIN_LOUDNESS_SCALE_WIDTH + sqrt(averageLoudness) / WIDTH_SENSITIVITY), + mouthHeight * (MIN_LOUDNESS_SCALE_HEIGHT + sqrt(averageLoudness) / HEIGHT_SENSITIVITY), 1); } else { glScalef(mouthWidth, mouthHeight, 1); } From 5514966d9c82bf84bd8da36eda26a3d7250273ea Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 12:40:23 -0700 Subject: [PATCH 13/24] add an AudioInjectionManager to handle multiple injections, link eve to it --- eve/src/main.cpp | 26 ++--- .../shared/src/AudioInjectionManager.cpp | 106 ++++++++++++++++++ libraries/shared/src/AudioInjectionManager.h | 36 ++++++ libraries/shared/src/AudioInjector.cpp | 79 +------------ libraries/shared/src/AudioInjector.h | 33 +++--- 5 files changed, 175 insertions(+), 105 deletions(-) create mode 100644 libraries/shared/src/AudioInjectionManager.cpp create mode 100644 libraries/shared/src/AudioInjectionManager.h diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 733bd2b715..4f056174e1 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -15,6 +15,7 @@ #include #include #include +#include #include const int EVE_AGENT_LISTEN_PORT = 55441; @@ -106,20 +107,19 @@ int main(int argc, const char* argv[]) { // put her hand out so somebody can shake it eve.setHandPosition(glm::vec3(eve.getPosition()[0] - 0.2, 0.5, - eve.getPosition()[2] + 0.1)); + eve.getPosition()[2] + 0.1)); + + // prepare the audio injection manager by giving it a handle to our agent socket + AudioInjectionManager::setInjectorSocket(agentList->getAgentSocket()); + // read eve's audio data AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw"); // lower Eve's volume by setting the attentuation modifier (this is a value out of 255) - eveAudioInjector.setAttenuationModifier(190); - - // pass the agentList UDPSocket pointer to the audio injector - eveAudioInjector.setInjectorSocket(agentList->getAgentSocket()); + eveAudioInjector.setVolume(190); // set the position of the audio injector - float injectorPosition[3]; - memcpy(injectorPosition, &eve.getPosition(), sizeof(injectorPosition)); - eveAudioInjector.setPosition(injectorPosition); + eveAudioInjector.setPosition(eve.getPosition()); // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; @@ -165,15 +165,11 @@ int main(int argc, const char* argv[]) { Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); if (audioMixer) { - // until the audio mixer is setup for ping-reply, activate the public socket if it's not active - if (!audioMixer->getActiveSocket()) { - audioMixer->activatePublicSocket(); - } - - eveAudioInjector.setDestinationSocket(audioMixer->getActiveSocket()); + // update the destination socket for the AIM, in case the mixer has changed + AudioInjectionManager::setDestinationSocket(*audioMixer->getPublicSocket()); // we have an active audio mixer we can send data to - eveAudioInjector.threadInjectionOfAudio(); + AudioInjectionManager::threadInjector(&eveAudioInjector); } } } diff --git a/libraries/shared/src/AudioInjectionManager.cpp b/libraries/shared/src/AudioInjectionManager.cpp new file mode 100644 index 0000000000..b9ca3a4150 --- /dev/null +++ b/libraries/shared/src/AudioInjectionManager.cpp @@ -0,0 +1,106 @@ +// +// AudioInjectionManager.cpp +// hifi +// +// Created by Stephen Birarda on 5/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#include + +#include "SharedUtil.h" +#include "PacketHeaders.h" + +#include "AudioInjectionManager.h" + +UDPSocket* AudioInjectionManager::_injectorSocket = NULL; +sockaddr AudioInjectionManager::_destinationSocket; +AudioInjector* AudioInjectionManager::_injectors[50] = {}; + +AudioInjector* AudioInjectionManager::injectorWithSamplesFromFile(const char* filename) { + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (!_injectors[i]) { + _injectors[i] = new AudioInjector(filename); + return _injectors[i]; + } + } + + return NULL; +} + +AudioInjector* AudioInjectionManager::injectorWithCapacity(int capacity) { + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (!_injectors[i]) { + _injectors[i] = new AudioInjector(capacity); + return _injectors[i]; + } + } + + return NULL; +} + +void* AudioInjectionManager::injectAudioViaThread(void* args) { + AudioInjector* injector = (AudioInjector*) args; + + if (injector->_audioSampleArray) { + injector->setIsInjectingAudio(true); + + timeval startTime; + + // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte + int leadingBytes = 1 + (sizeof(float) * 4) + 1; + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; + + dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; + unsigned char *currentPacketPtr = dataPacket + 1; + + memcpy(currentPacketPtr, &injector->getPosition(), sizeof(injector->getPosition())); + currentPacketPtr += sizeof(injector->getPosition()); + + *currentPacketPtr = injector->getVolume(); + currentPacketPtr++; + + memcpy(currentPacketPtr, &injector->_bearing, sizeof(injector->_bearing)); + currentPacketPtr += sizeof(injector->_bearing); + + for (int i = 0; i < injector->_numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { + gettimeofday(&startTime, NULL); + + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; + + if (injector->_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { + numSamplesToCopy = injector->_numTotalSamples - i; + memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); + } + + memcpy(currentPacketPtr, injector->_audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); + + _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); + + double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + } + + injector->_isInjectingAudio = false; + } + + // if this an injector inside the injection manager's array we're responsible for deletion + for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { + if (_injectors[i] == injector) { + // pointer matched - delete this injector + delete injector; + + // set the pointer to NULL so we can reuse this spot + _injectors[i] = NULL; + } + } + + pthread_exit(0); +} + +void AudioInjectionManager::threadInjector(AudioInjector* injector) { + pthread_t audioInjectThread; + pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) injector); +} \ No newline at end of file diff --git a/libraries/shared/src/AudioInjectionManager.h b/libraries/shared/src/AudioInjectionManager.h new file mode 100644 index 0000000000..3297305475 --- /dev/null +++ b/libraries/shared/src/AudioInjectionManager.h @@ -0,0 +1,36 @@ +// +// AudioInjectionManager.h +// hifi +// +// Created by Stephen Birarda on 5/16/13. +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// + +#ifndef __hifi__AudioInjectionManager__ +#define __hifi__AudioInjectionManager__ + +#include + +#include "UDPSocket.h" +#include "AudioInjector.h" + +const int MAX_CONCURRENT_INJECTORS = 50; + +class AudioInjectionManager { +public: + static AudioInjector* injectorWithCapacity(int capacity); + static AudioInjector* injectorWithSamplesFromFile(const char* filename); + + static void threadInjector(AudioInjector* injector); + + static void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket;} + static void setDestinationSocket(sockaddr& destinationSocket) { _destinationSocket = destinationSocket; } +private: + static void* injectAudioViaThread(void* args); + + static UDPSocket* _injectorSocket; + static sockaddr _destinationSocket; + static AudioInjector* _injectors[MAX_CONCURRENT_INJECTORS]; +}; + +#endif /* defined(__hifi__AudioInjectionManager__) */ diff --git a/libraries/shared/src/AudioInjector.cpp b/libraries/shared/src/AudioInjector.cpp index c89385226c..05530cebe3 100644 --- a/libraries/shared/src/AudioInjector.cpp +++ b/libraries/shared/src/AudioInjector.cpp @@ -3,27 +3,20 @@ // hifi // // Created by Stephen Birarda on 4/23/13. -// +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // -#include #include #include #include "SharedUtil.h" -#include "PacketHeaders.h" #include "AudioInjector.h" -const int BUFFER_LENGTH_BYTES = 512; -const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); -const float SAMPLE_RATE = 22050.0f; -const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; - AudioInjector::AudioInjector(const char* filename) : _position(), _bearing(0), - _attenuationModifier(255), + _volume(0xFF), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -50,7 +43,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), _bearing(0), - _attenuationModifier(255), + _volume(0xFF), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -62,12 +55,6 @@ AudioInjector::~AudioInjector() { delete[] _audioSampleArray; } -void AudioInjector::setPosition(float* position) { - _position[0] = position[0]; - _position[1] = position[1]; - _position[2] = position[2]; -} - void AudioInjector::addSample(const int16_t sample) { if (_indexOfNextSlot != _numTotalSamples) { // only add this sample if we actually have space for it @@ -82,63 +69,3 @@ void AudioInjector::addSamples(int16_t* sampleBuffer, int numSamples) { _indexOfNextSlot += numSamples; } } - -void AudioInjector::injectAudio() { - if (_audioSampleArray) { - _isInjectingAudio = true; - - timeval startTime; - - // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte - int leadingBytes = 1 + (sizeof(float) * 4) + 1; - unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; - - dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; - - for (int i = 0; i < 3; i++) { - memcpy(currentPacketPtr, &_position[i], sizeof(float)); - currentPacketPtr += sizeof(float); - } - - *currentPacketPtr = _attenuationModifier; - currentPacketPtr++; - - memcpy(currentPacketPtr, &_bearing, sizeof(float)); - currentPacketPtr += sizeof(float); - - for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { - gettimeofday(&startTime, NULL); - - int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; - - if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { - numSamplesToCopy = _numTotalSamples - i; - memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); - } - - memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); - - _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); - - double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - _isInjectingAudio = false; - } -} - -void* injectAudioViaThread(void* args) { - AudioInjector* parentInjector = (AudioInjector*) args; - parentInjector->injectAudio(); - - pthread_exit(0); -} - -void AudioInjector::threadInjectionOfAudio() { - pthread_t audioInjectThread; - pthread_create(&audioInjectThread, NULL, injectAudioViaThread, (void*) this); -} diff --git a/libraries/shared/src/AudioInjector.h b/libraries/shared/src/AudioInjector.h index 3e79869034..fb5bf86c58 100644 --- a/libraries/shared/src/AudioInjector.h +++ b/libraries/shared/src/AudioInjector.h @@ -3,45 +3,50 @@ // hifi // // Created by Stephen Birarda on 4/23/13. -// +// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // #ifndef __hifi__AudioInjector__ #define __hifi__AudioInjector__ #include -#include -#include "UDPSocket.h" +#include + +const int BUFFER_LENGTH_BYTES = 512; +const int BUFFER_LENGTH_SAMPLES = BUFFER_LENGTH_BYTES / sizeof(int16_t); +const float SAMPLE_RATE = 22050.0f; +const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES / SAMPLE_RATE) * 1000000; class AudioInjector { + friend class AudioInjectionManager; + public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); ~AudioInjector(); bool isInjectingAudio() const { return _isInjectingAudio; } + void setIsInjectingAudio(bool isInjectingAudio) { _isInjectingAudio = isInjectingAudio; } - void setPosition(float* position); + unsigned char getVolume() const { return _volume; } + void setVolume(unsigned char volume) { _volume = volume; } + + const glm::vec3& getPosition() const { return _position; } + void setPosition(const glm::vec3& position) { _position = position; } + + float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } - void setAttenuationModifier(unsigned char attenuationModifier) { _attenuationModifier = attenuationModifier; } - void setInjectorSocket(UDPSocket* injectorSocket) { _injectorSocket = injectorSocket; } - void setDestinationSocket(sockaddr* destinationSocket) { _destinationSocket = *destinationSocket; } void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); - - void injectAudio(); - void threadInjectionOfAudio(); private: int16_t* _audioSampleArray; int _numTotalSamples; - float _position[3]; + glm::vec3 _position; float _bearing; - unsigned char _attenuationModifier; + unsigned char _volume; int _indexOfNextSlot; - UDPSocket* _injectorSocket; - sockaddr _destinationSocket; bool _isInjectingAudio; }; From f8dc01a89008e624f95ef5e338846e47badcad90 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 May 2013 12:56:13 -0700 Subject: [PATCH 14/24] removed the - key killing all the planets --- interface/src/Application.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2b3fe3c0f6..a4002cca4c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -538,10 +538,6 @@ void Application::keyPressEvent(QKeyEvent* event) { shiftPaintingColor(); break; - case Qt::Key_Minus: - sendVoxelServerEraseAll(); - break; - case Qt::Key_Percent: sendVoxelServerAddScene(); break; From a2f8d8ae25a404098440fc62cb17dce17295261b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 13:00:40 -0700 Subject: [PATCH 15/24] break audio out of shared into its own library --- audio-mixer/CMakeLists.txt | 5 +---- audio-mixer/src/main.cpp | 1 - eve/CMakeLists.txt | 3 ++- injector/CMakeLists.txt | 12 ++++++---- injector/src/main.cpp | 2 -- interface/CMakeLists.txt | 1 + libraries/audio/CMakeLists.txt | 22 +++++++++++++++++++ .../src/AudioInjectionManager.cpp | 0 .../src/AudioInjectionManager.h | 0 .../{shared => audio}/src/AudioInjector.cpp | 0 .../{shared => audio}/src/AudioInjector.h | 0 .../{shared => audio}/src/AudioRingBuffer.cpp | 0 .../{shared => audio}/src/AudioRingBuffer.h | 0 13 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 libraries/audio/CMakeLists.txt rename libraries/{shared => audio}/src/AudioInjectionManager.cpp (100%) rename libraries/{shared => audio}/src/AudioInjectionManager.h (100%) rename libraries/{shared => audio}/src/AudioInjector.cpp (100%) rename libraries/{shared => audio}/src/AudioInjector.h (100%) rename libraries/{shared => audio}/src/AudioRingBuffer.cpp (100%) rename libraries/{shared => audio}/src/AudioRingBuffer.h (100%) diff --git a/audio-mixer/CMakeLists.txt b/audio-mixer/CMakeLists.txt index 1e6637aeb2..3e2d9939b0 100644 --- a/audio-mixer/CMakeLists.txt +++ b/audio-mixer/CMakeLists.txt @@ -11,7 +11,4 @@ setup_hifi_project(${TARGET_NAME}) # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -# link the threads library -find_package(Threads REQUIRED) -target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 444edd1393..5bb33a9198 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include diff --git a/eve/CMakeLists.txt b/eve/CMakeLists.txt index cb38529b2d..acca9520ed 100644 --- a/eve/CMakeLists.txt +++ b/eve/CMakeLists.txt @@ -17,4 +17,5 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) # link the required hifi libraries include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) -link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt index 6bea5b51d3..ba3393956a 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -3,15 +3,19 @@ cmake_minimum_required(VERSION 2.8) set(ROOT_DIR ..) set(MACRO_DIR ${ROOT_DIR}/cmake/macros) +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") + set(TARGET_NAME injector) include(${MACRO_DIR}/SetupHifiProject.cmake) setup_hifi_project(${TARGET_NAME}) +# set up the external glm library +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) - -# link the threads library -find_package(Threads REQUIRED) -target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/injector/src/main.cpp b/injector/src/main.cpp index dee09de6c8..bf49cb6a99 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -6,7 +6,6 @@ // Copyright (c) 2013 Leonardo Murillo. All rights reserved. // - #include #include #include @@ -15,7 +14,6 @@ #include #include - #include #include #include diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index 56b41fbc69..dac0749f8d 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -71,6 +71,7 @@ include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR}) +link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) # find required libraries find_package(GLM REQUIRED) diff --git a/libraries/audio/CMakeLists.txt b/libraries/audio/CMakeLists.txt new file mode 100644 index 0000000000..686986340f --- /dev/null +++ b/libraries/audio/CMakeLists.txt @@ -0,0 +1,22 @@ +cmake_minimum_required(VERSION 2.8) + +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + +# setup for find modules +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") + +set(TARGET_NAME audio) + +include(${MACRO_DIR}/SetupHifiLibrary.cmake) +setup_hifi_library(${TARGET_NAME}) + +include(${MACRO_DIR}/IncludeGLM.cmake) +include_glm(${TARGET_NAME} ${ROOT_DIR}) + +include(${MACRO_DIR}/LinkHifiLibrary.cmake) +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +# link the threads library +find_package(Threads REQUIRED) +target_link_libraries(${TARGET_NAME} ${CMAKE_THREAD_LIBS_INIT}) \ No newline at end of file diff --git a/libraries/shared/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp similarity index 100% rename from libraries/shared/src/AudioInjectionManager.cpp rename to libraries/audio/src/AudioInjectionManager.cpp diff --git a/libraries/shared/src/AudioInjectionManager.h b/libraries/audio/src/AudioInjectionManager.h similarity index 100% rename from libraries/shared/src/AudioInjectionManager.h rename to libraries/audio/src/AudioInjectionManager.h diff --git a/libraries/shared/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp similarity index 100% rename from libraries/shared/src/AudioInjector.cpp rename to libraries/audio/src/AudioInjector.cpp diff --git a/libraries/shared/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h similarity index 100% rename from libraries/shared/src/AudioInjector.h rename to libraries/audio/src/AudioInjector.h diff --git a/libraries/shared/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp similarity index 100% rename from libraries/shared/src/AudioRingBuffer.cpp rename to libraries/audio/src/AudioRingBuffer.cpp diff --git a/libraries/shared/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h similarity index 100% rename from libraries/shared/src/AudioRingBuffer.h rename to libraries/audio/src/AudioRingBuffer.h From 86ddcea87f673701a4a58ce9051aa3728687d066 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 16 May 2013 13:08:21 -0700 Subject: [PATCH 16/24] Better names for the shaders. --- .../{grainy_voxels.frag => perlin_modulate.frag} | 16 +++++++++++----- .../{grainy_voxels.vert => perlin_modulate.vert} | 6 +++--- interface/src/VoxelSystem.cpp | 14 +++++++------- interface/src/VoxelSystem.h | 2 +- 4 files changed, 22 insertions(+), 16 deletions(-) rename interface/resources/shaders/{grainy_voxels.frag => perlin_modulate.frag} (87%) rename interface/resources/shaders/{grainy_voxels.vert => perlin_modulate.vert} (95%) diff --git a/interface/resources/shaders/grainy_voxels.frag b/interface/resources/shaders/perlin_modulate.frag similarity index 87% rename from interface/resources/shaders/grainy_voxels.frag rename to interface/resources/shaders/perlin_modulate.frag index a01de0c577..eea0da3671 100644 --- a/interface/resources/shaders/grainy_voxels.frag +++ b/interface/resources/shaders/perlin_modulate.frag @@ -1,16 +1,22 @@ +#version 120 + // -// grainy_voxels.frag +// perlin_modulate.frag // fragment shader // // Created by Andrzej Kapolka on 5/15/13. -// Copyright (c) 2012 High Fidelity, Inc. All rights reserved. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#version 120 - // the texture containing our permutations and normals uniform sampler2D permutationNormalTexture; +// the noise frequency +const float frequency = 1024.0; + +// the noise amplitude +const float amplitude = 0.1; + // the position in model space varying vec3 position; @@ -53,5 +59,5 @@ float perlin(vec3 location) { } void main(void) { - gl_FragColor = vec4(gl_Color.rgb * (0.85 + perlin(position * 1024.0) * 0.15), 1.0); + gl_FragColor = vec4(gl_Color.rgb * (1.0 + amplitude*(perlin(position * frequency) - 1.0)), 1.0); } diff --git a/interface/resources/shaders/grainy_voxels.vert b/interface/resources/shaders/perlin_modulate.vert similarity index 95% rename from interface/resources/shaders/grainy_voxels.vert rename to interface/resources/shaders/perlin_modulate.vert index 856b4e7955..5cf87fc5fd 100644 --- a/interface/resources/shaders/grainy_voxels.vert +++ b/interface/resources/shaders/perlin_modulate.vert @@ -1,13 +1,13 @@ +#version 120 + // -// grainy_voxels.vert +// perlin_modulate.vert // vertex shader // // Created by Andrzej Kapolka on 5/15/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#version 120 - // the position in model space varying vec3 position; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7ad967491d..ac74d81c7f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -503,12 +503,12 @@ void VoxelSystem::init() { // create our simple fragment shader switchToResourcesParentIfRequired(); - _grainProgram = new ProgramObject(); - _grainProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/grainy_voxels.vert"); - _grainProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/grainy_voxels.frag"); - _grainProgram->link(); + _perlinModulateProgram = new ProgramObject(); + _perlinModulateProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); + _perlinModulateProgram->addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/perlin_modulate.frag"); + _perlinModulateProgram->link(); - _grainProgram->setUniformValue("permutationNormalTexture", 0); + _perlinModulateProgram->setUniformValue("permutationNormalTexture", 0); // create the permutation/normal texture glGenTextures(1, &_permutationNormalTextureID); @@ -640,7 +640,7 @@ void VoxelSystem::render() { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - _grainProgram->bind(); + _perlinModulateProgram->bind(); glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); // draw the number of voxels we have @@ -648,7 +648,7 @@ void VoxelSystem::render() { glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); glDrawElements(GL_TRIANGLES, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); - _grainProgram->release(); + _perlinModulateProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); // deactivate vertex and color arrays after drawing diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 61ed570563..a3560c1b31 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -135,7 +135,7 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ProgramObject* _grainProgram; + ProgramObject* _perlinModulateProgram; GLuint _permutationNormalTextureID; ViewFrustum* _viewFrustum; From f6cc40362c12c20b40eb11a6cc482d139cc4f2e3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 13:10:48 -0700 Subject: [PATCH 17/24] hook the injector up to the change AudioInjector setup --- injector/src/main.cpp | 15 +++--- libraries/audio/src/AudioInjectionManager.cpp | 44 +--------------- libraries/audio/src/AudioInjector.cpp | 50 ++++++++++++++++++- libraries/audio/src/AudioInjector.h | 2 + 4 files changed, 59 insertions(+), 52 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index bf49cb6a99..9d2fa76c39 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -18,6 +18,7 @@ #include #include #include +#include char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55443; @@ -29,7 +30,7 @@ float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; const char *allowedParameters = ":rb::t::c::a::f:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; -unsigned char attenuationModifier = 255; +unsigned char volume = 255; void usage(void) { @@ -80,7 +81,7 @@ bool processParameters(int parameterCount, char* parameterData[]) break; } case 'a': - ::attenuationModifier = atoi(optarg); + ::volume = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; default: @@ -110,19 +111,17 @@ int main(int argc, char* argv[]) { exit(-1); } else { AudioInjector injector(sourceAudioFile); - injector.setInjectorSocket(&streamSocket); - injector.setDestinationSocket((sockaddr*) &mixerSocket); - injector.setPosition(::floatArguments); + injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); - injector.setAttenuationModifier(::attenuationModifier); + injector.setVolume(::volume); float delay = 0; int usecDelay = 0; while (true) { - injector.injectAudio(); - + injector.injectAudio(&streamSocket, (sockaddr*) &mixerSocket); + if (!::loopAudio) { delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); usecDelay = delay * 1000 * 1000; diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index b9ca3a4150..ce252afd23 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -42,49 +42,7 @@ AudioInjector* AudioInjectionManager::injectorWithCapacity(int capacity) { void* AudioInjectionManager::injectAudioViaThread(void* args) { AudioInjector* injector = (AudioInjector*) args; - if (injector->_audioSampleArray) { - injector->setIsInjectingAudio(true); - - timeval startTime; - - // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte - int leadingBytes = 1 + (sizeof(float) * 4) + 1; - unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; - - dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; - - memcpy(currentPacketPtr, &injector->getPosition(), sizeof(injector->getPosition())); - currentPacketPtr += sizeof(injector->getPosition()); - - *currentPacketPtr = injector->getVolume(); - currentPacketPtr++; - - memcpy(currentPacketPtr, &injector->_bearing, sizeof(injector->_bearing)); - currentPacketPtr += sizeof(injector->_bearing); - - for (int i = 0; i < injector->_numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { - gettimeofday(&startTime, NULL); - - int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; - - if (injector->_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { - numSamplesToCopy = injector->_numTotalSamples - i; - memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); - } - - memcpy(currentPacketPtr, injector->_audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); - - _injectorSocket->send(&_destinationSocket, dataPacket, sizeof(dataPacket)); - - double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); - if (usecToSleep > 0) { - usleep(usecToSleep); - } - } - - injector->_isInjectingAudio = false; - } + injector->injectAudio(_injectorSocket, &_destinationSocket); // if this an injector inside the injection manager's array we're responsible for deletion for (int i = 0; i < MAX_CONCURRENT_INJECTORS; i++) { diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 05530cebe3..fa05570d40 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -9,7 +9,9 @@ #include #include -#include "SharedUtil.h" +#include +#include +#include #include "AudioInjector.h" @@ -55,6 +57,52 @@ AudioInjector::~AudioInjector() { delete[] _audioSampleArray; } +void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket) { + if (_audioSampleArray) { + _isInjectingAudio = true; + + timeval startTime; + + // one byte for header, 3 positional floats, 1 bearing float, 1 attenuation modifier byte + int leadingBytes = 1 + (sizeof(float) * 4) + 1; + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; + + dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; + unsigned char *currentPacketPtr = dataPacket + 1; + + memcpy(currentPacketPtr, &_position, sizeof(_position)); + currentPacketPtr += sizeof(_position); + + *currentPacketPtr = _volume; + currentPacketPtr++; + + memcpy(currentPacketPtr, &_bearing, sizeof(_bearing)); + currentPacketPtr += sizeof(_bearing); + + for (int i = 0; i < _numTotalSamples; i += BUFFER_LENGTH_SAMPLES) { + gettimeofday(&startTime, NULL); + + int numSamplesToCopy = BUFFER_LENGTH_SAMPLES; + + if (_numTotalSamples - i < BUFFER_LENGTH_SAMPLES) { + numSamplesToCopy = _numTotalSamples - i; + memset(currentPacketPtr + numSamplesToCopy, 0, BUFFER_LENGTH_BYTES - (numSamplesToCopy * sizeof(int16_t))); + } + + memcpy(currentPacketPtr, _audioSampleArray + i, numSamplesToCopy * sizeof(int16_t)); + + injectorSocket->send(destinationSocket, dataPacket, sizeof(dataPacket)); + + double usecToSleep = BUFFER_SEND_INTERVAL_USECS - (usecTimestampNow() - usecTimestamp(&startTime)); + if (usecToSleep > 0) { + usleep(usecToSleep); + } + } + + _isInjectingAudio = false; + } +} + void AudioInjector::addSample(const int16_t sample) { if (_indexOfNextSlot != _numTotalSamples) { // only add this sample if we actually have space for it diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index fb5bf86c58..eb22df1177 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -25,6 +25,8 @@ public: AudioInjector(const char* filename); AudioInjector(int maxNumSamples); ~AudioInjector(); + + void injectAudio(UDPSocket* injectorSocket, sockaddr* destinationSocket); bool isInjectingAudio() const { return _isInjectingAudio; } void setIsInjectingAudio(bool isInjectingAudio) { _isInjectingAudio = isInjectingAudio; } From b2709652b444d82cf8ea460de009f99c8a118f40 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 16 May 2013 14:43:46 -0600 Subject: [PATCH 18/24] Tweaks to improve mouse Yaw behavior. --- interface/src/Avatar.cpp | 33 ++++++++++++++++++++++++++------- interface/src/Avatar.h | 2 ++ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 03c803b798..d5a0e514a7 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -101,7 +101,9 @@ Avatar::Avatar(bool isMine) { _sphere = NULL; _handHoldingPosition = glm::vec3(0.0f, 0.0f, 0.0f); _distanceToNearestAvatar = std::numeric_limits::max(); - _gravity = glm::vec3(0.0f, -1.0f, 0.0f); // default + _gravity = glm::vec3(0.0f, -1.0f, 0.0f); + _cumulativeMouseYaw = 0.f; + _isMouseTurningRight = false; initializeSkeleton(); @@ -292,16 +294,33 @@ bool Avatar::getIsNearInteractingOther() { } void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { - // Update pitch and yaw based on mouse behavior + // Update yaw based on mouse behavior const float MOUSE_MOVE_RADIUS = 0.25f; const float MOUSE_ROTATE_SPEED = 7.5f; + const float MAX_YAW_TO_ADD = 180.f; float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; - - if (fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) { - float mouseMag = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; - setBodyYaw(getBodyYaw() - ((mouseLocationX > 0.f) ? mouseMag : -mouseMag)); + + printLog("mouse %d, %d\n", mouseX, mouseY); + + if ((fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) && + (mouseX > 1) && + (mouseX < screenWidth) && + (mouseY > 1) && + (mouseY < screenHeight)) { + float mouseYawAdd = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; + bool rightTurning = (mouseLocationX > 0.f); + if (_isMouseTurningRight == rightTurning) { + _cumulativeMouseYaw += mouseYawAdd; + } else { + _cumulativeMouseYaw = 0; + _isMouseTurningRight = rightTurning; + } + if (_cumulativeMouseYaw < MAX_YAW_TO_ADD) { + setBodyYaw(getBodyYaw() - (rightTurning ? mouseYawAdd : -mouseYawAdd)); + } + } else { + _cumulativeMouseYaw = 0; } - return; } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index b653440461..11ef6a8327 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -200,6 +200,8 @@ private: glm::vec3 _mouseRayOrigin; glm::vec3 _mouseRayDirection; glm::vec3 _cameraPosition; + float _cumulativeMouseYaw; + bool _isMouseTurningRight; //AvatarJointID _jointTouched; From a37b451993bf6d2dc8e8b2f397922c6a2cbce6b6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 14:09:50 -0700 Subject: [PATCH 19/24] add constants for volume byte values --- eve/src/main.cpp | 3 ++- injector/src/main.cpp | 4 +++- libraries/audio/src/AudioInjector.cpp | 6 ++++-- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/eve/src/main.cpp b/eve/src/main.cpp index 4f056174e1..52f307c18f 100644 --- a/eve/src/main.cpp +++ b/eve/src/main.cpp @@ -35,6 +35,7 @@ const int HAND_TIMER_SLEEP_ITERATIONS = 50; const float EVE_PELVIS_HEIGHT = 0.565925f; const float AUDIO_INJECT_PROXIMITY = 0.4f; +const int EVE_VOLUME_BYTE = 190; bool stopReceiveAgentDataThread; @@ -116,7 +117,7 @@ int main(int argc, const char* argv[]) { AudioInjector eveAudioInjector("/etc/highfidelity/eve/resources/eve.raw"); // lower Eve's volume by setting the attentuation modifier (this is a value out of 255) - eveAudioInjector.setVolume(190); + eveAudioInjector.setVolume(EVE_VOLUME_BYTE); // set the position of the audio injector eveAudioInjector.setPosition(eve.getPosition()); diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 9d2fa76c39..df751f50a1 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -23,6 +23,8 @@ char EC2_WEST_AUDIO_SERVER[] = "54.241.92.53"; const int AUDIO_UDP_LISTEN_PORT = 55443; +const int DEFAULT_INJECTOR_VOLUME = 0xFF; + // Command line parameter defaults bool loopAudio = true; float sleepIntervalMin = 1.00; @@ -30,7 +32,7 @@ float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; const char *allowedParameters = ":rb::t::c::a::f:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; -unsigned char volume = 255; +unsigned char volume = DEFAULT_INJECTOR_VOLUME; void usage(void) { diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fa05570d40..a5a696f927 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -15,10 +15,12 @@ #include "AudioInjector.h" +const int MAX_INJECTOR_VOLUME = 255; + AudioInjector::AudioInjector(const char* filename) : _position(), _bearing(0), - _volume(0xFF), + _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) { @@ -45,7 +47,7 @@ AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), _bearing(0), - _volume(0xFF), + _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) { From 442d658835ca6c176085f99990e9cd759216a18d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Thu, 16 May 2013 14:10:48 -0700 Subject: [PATCH 20/24] switch from 255 to 0xFF for max volume constant --- libraries/audio/src/AudioInjector.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index a5a696f927..689b4c6cd9 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -15,7 +15,7 @@ #include "AudioInjector.h" -const int MAX_INJECTOR_VOLUME = 255; +const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), From 191c533ad2124cf9d9e0849fe5b588f20b7b67aa Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 16 May 2013 14:24:18 -0700 Subject: [PATCH 21/24] Provide a gray background for the chat entry, so that we can see what we're typing. --- interface/src/ui/ChatEntry.cpp | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/ChatEntry.cpp b/interface/src/ui/ChatEntry.cpp index ad4cf70ab0..588c394eb1 100644 --- a/interface/src/ui/ChatEntry.cpp +++ b/interface/src/ui/ChatEntry.cpp @@ -13,7 +13,7 @@ using namespace std; -const int MAX_CONTENT_LENGTH = 140; +const int MAX_CONTENT_LENGTH = 80; ChatEntry::ChatEntry() : _cursorPos(0) { } @@ -65,7 +65,7 @@ bool ChatEntry::keyPressEvent(QKeyEvent* event) { event->ignore(); return true; } - if (_contents.size() != MAX_CONTENT_LENGTH) { + if (_contents.size() < MAX_CONTENT_LENGTH) { _contents.insert(_cursorPos, 1, text.at(0).toAscii()); _cursorPos++; } @@ -74,7 +74,19 @@ bool ChatEntry::keyPressEvent(QKeyEvent* event) { } void ChatEntry::render(int screenWidth, int screenHeight) { - drawtext(20, screenHeight - 150, 0.10, 0, 1.0, 0, _contents.c_str(), 1, 1, 1); + // draw a gray background so that we can actually see what we're typing + int bottom = screenHeight - 150, top = screenHeight - 165; + int left = 20, right = left + 600; + + glColor3f(0.2f, 0.2f, 0.2f); + glBegin(GL_QUADS); + glVertex2f(left - 5, bottom + 7); + glVertex2f(right + 5, bottom + 7); + glVertex2f(right + 5, top - 3); + glVertex2f(left - 5, top - 3); + glEnd(); + + drawtext(left, bottom, 0.10, 0, 1.0, 0, _contents.c_str(), 1, 1, 1); float width = 0; for (string::iterator it = _contents.begin(), end = it + _cursorPos; it != end; it++) { @@ -82,7 +94,7 @@ void ChatEntry::render(int screenWidth, int screenHeight) { } glDisable(GL_LINE_SMOOTH); glBegin(GL_LINE_STRIP); - glVertex2f(20 + width, screenHeight - 165); - glVertex2f(20 + width, screenHeight - 150); + glVertex2f(left + width, top + 2); + glVertex2f(left + width, bottom + 2); glEnd(); } From 9f57787ece12eb4eacbeba10948fd6437047c8e2 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 16 May 2013 17:05:45 -0600 Subject: [PATCH 22/24] Fixed jerking on gravity, added mouse pitch, yaw behavior. --- interface/src/Application.cpp | 10 ++++-- interface/src/Avatar.cpp | 50 ++++++++++++++++------------ interface/src/Head.cpp | 3 -- libraries/avatars/src/AvatarData.cpp | 9 +++++ libraries/avatars/src/AvatarData.h | 4 +-- 5 files changed, 46 insertions(+), 30 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1546d8be13..c70b674f38 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -306,13 +306,13 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getAbsoluteHeadYaw(), - _myAvatar.getAbsoluteHeadPitch(), + -_myAvatar.getAbsoluteHeadPitch(), 0.0f); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); _myCamera.setTargetRotation(_myAvatar.getBodyYaw(), - 0.0f, + -_myAvatar.getAbsoluteHeadPitch(), 0.0f); } } @@ -864,7 +864,11 @@ void Application::idle() { } // Update from Mouse - _myAvatar.updateFromMouse(_mouseX, _mouseY, _glWidget->width(), _glWidget->height()); + QPoint mouse = QCursor::pos(); + _myAvatar.updateFromMouse(_glWidget->mapFromGlobal(mouse).x(), + _glWidget->mapFromGlobal(mouse).y(), + _glWidget->width(), + _glWidget->height()); // Read serial port interface devices if (_serialPort.active) { diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index d5a0e514a7..7251c1ab96 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -214,7 +214,6 @@ void Avatar::reset() { _head.leanForward = _head.leanSideways = 0; } - // Update avatar head rotation with sensor data void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterface, glm::vec3* gravity) { float measuredPitchRate = 0.0f; @@ -226,8 +225,6 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa measuredRollRate = serialInterface->getLastRollRate(); // Update avatar head position based on measured gyro rates - const float MAX_PITCH = 45; - const float MIN_PITCH = -45; const float MAX_YAW = 85; const float MIN_YAW = -85; const float MAX_ROLL = 50; @@ -237,7 +234,6 @@ void Avatar::updateHeadFromGyros(float deltaTime, SerialInterface* serialInterfa addHeadYaw(measuredYawRate * deltaTime); addHeadRoll(measuredRollRate * deltaTime); - setHeadPitch(glm::clamp(getHeadPitch(), MIN_PITCH, MAX_PITCH)); setHeadYaw(glm::clamp(getHeadYaw(), MIN_YAW, MAX_YAW)); setHeadRoll(glm::clamp(getHeadRoll(), MIN_ROLL, MAX_ROLL)); @@ -296,31 +292,41 @@ bool Avatar::getIsNearInteractingOther() { void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int screenHeight) { // Update yaw based on mouse behavior const float MOUSE_MOVE_RADIUS = 0.25f; - const float MOUSE_ROTATE_SPEED = 7.5f; + const float MOUSE_ROTATE_SPEED = 5.0f; + const float MOUSE_PITCH_SPEED = 3.0f; const float MAX_YAW_TO_ADD = 180.f; + const int TITLE_BAR_HEIGHT = 46; float mouseLocationX = (float)mouseX / (float)screenWidth - 0.5f; + float mouseLocationY = (float)mouseY / (float)screenHeight - 0.5f; - printLog("mouse %d, %d\n", mouseX, mouseY); - - if ((fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) && - (mouseX > 1) && - (mouseX < screenWidth) && - (mouseY > 1) && - (mouseY < screenHeight)) { - float mouseYawAdd = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; - bool rightTurning = (mouseLocationX > 0.f); - if (_isMouseTurningRight == rightTurning) { - _cumulativeMouseYaw += mouseYawAdd; + if ((mouseX > 1) && (mouseX < screenWidth) && (mouseY > TITLE_BAR_HEIGHT) && (mouseY < screenHeight)) { + // + // Mouse must be inside screen (not at edge) and not on title bar for movement to happen + // + if (fabs(mouseLocationX) > MOUSE_MOVE_RADIUS) { + // Add Yaw + float mouseYawAdd = (fabs(mouseLocationX) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_ROTATE_SPEED; + bool rightTurning = (mouseLocationX > 0.f); + if (_isMouseTurningRight == rightTurning) { + _cumulativeMouseYaw += mouseYawAdd; + } else { + _cumulativeMouseYaw = 0; + _isMouseTurningRight = rightTurning; + } + if (_cumulativeMouseYaw < MAX_YAW_TO_ADD) { + setBodyYaw(getBodyYaw() - (rightTurning ? mouseYawAdd : -mouseYawAdd)); + } } else { _cumulativeMouseYaw = 0; - _isMouseTurningRight = rightTurning; } - if (_cumulativeMouseYaw < MAX_YAW_TO_ADD) { - setBodyYaw(getBodyYaw() - (rightTurning ? mouseYawAdd : -mouseYawAdd)); + if (fabs(mouseLocationY) > MOUSE_MOVE_RADIUS) { + float mousePitchAdd = (fabs(mouseLocationY) - MOUSE_MOVE_RADIUS) / (0.5f - MOUSE_MOVE_RADIUS) * MOUSE_PITCH_SPEED; + bool downPitching = (mouseLocationY > 0.f); + setHeadPitch(getHeadPitch() + (downPitching ? mousePitchAdd : -mousePitchAdd)); } - } else { - _cumulativeMouseYaw = 0; + } + return; } @@ -348,7 +354,7 @@ void Avatar::simulate(float deltaTime) { _avatarTouch.simulate(deltaTime); // apply gravity and collision with the ground/floor - if (USING_AVATAR_GRAVITY) { + if (_isMine && USING_AVATAR_GRAVITY) { if (_position.y > _pelvisStandingHeight + 0.01f) { _velocity += _gravity * (GRAVITY_SCALE * deltaTime); } else if (_position.y < _pelvisStandingHeight) { diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index ebedb44397..8e29c683e2 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -221,9 +221,6 @@ void Head::simulate(float deltaTime, bool isMine) { (deltaTime / AUDIO_AVERAGING_SECS) * audioLoudness; } - - - void Head::render(bool lookingInMirror, float bodyYaw) { int side = 0; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1f4856abf7..ab60088cf8 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -236,4 +236,13 @@ void AvatarData::setBodyRoll(float bodyRoll) { _bodyRoll = bodyRoll; } +void AvatarData::setHeadPitch(float p) { + // Set head pitch and apply limits + const float MAX_PITCH = 60; + const float MIN_PITCH = -60; + _headPitch = glm::clamp(p, MIN_PITCH, MAX_PITCH); +} + + + diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index c66402e21a..f131f82c85 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -73,13 +73,13 @@ public: void setBodyRoll(float bodyRoll); // Head Rotation - void setHeadPitch(float p) {_headPitch = p; } + void setHeadPitch(float p); void setHeadYaw(float y) {_headYaw = y; } void setHeadRoll(float r) {_headRoll = r; }; float getHeadPitch() const { return _headPitch; }; float getHeadYaw() const { return _headYaw; }; float getHeadRoll() const { return _headRoll; }; - void addHeadPitch(float p) {_headPitch -= p; } + void addHeadPitch(float p) { setHeadPitch(_headPitch - p); } void addHeadYaw(float y){_headYaw -= y; } void addHeadRoll(float r){_headRoll += r; } From 26badc56e02fcc1b8aa53f24e91af5fa37b88f4d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Thu, 16 May 2013 16:10:38 -0700 Subject: [PATCH 23/24] Added shadow and outline effects to TextRenderer, use the shadow effect in our text to separate it from the background. --- interface/src/Avatar.cpp | 4 +++- interface/src/Log.cpp | 2 +- interface/src/Util.cpp | 2 +- interface/src/ui/TextRenderer.cpp | 32 ++++++++++++++++++++++++++++--- interface/src/ui/TextRenderer.h | 11 ++++++++++- 5 files changed, 44 insertions(+), 7 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 03c803b798..eda3247cd5 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -753,7 +753,7 @@ void Avatar::setDisplayingHead(bool displayingHead) { } static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24); + static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); return renderer; } @@ -833,6 +833,7 @@ void Avatar::render(bool lookingInMirror, glm::vec3 cameraPosition) { glScalef(chatMessageScale, chatMessageScale, 1.0f); glDisable(GL_LIGHTING); + glDepthMask(false); if (_keyState == NO_KEY_DOWN) { textRenderer()->draw(-width/2, 0, _chatMessage.c_str()); @@ -848,6 +849,7 @@ void Avatar::render(bool lookingInMirror, glm::vec3 cameraPosition) { textRenderer()->draw(width/2 - lastWidth, 0, _chatMessage.c_str() + lastIndex); } glEnable(GL_LIGHTING); + glDepthMask(true); glPopMatrix(); } diff --git a/interface/src/Log.cpp b/interface/src/Log.cpp index 5fcfb51e25..9b57df1694 100644 --- a/interface/src/Log.cpp +++ b/interface/src/Log.cpp @@ -198,7 +198,7 @@ void Log::setCharacterSize(unsigned width, unsigned height) { } static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(FONT_FAMILY); + static TextRenderer* renderer = new TextRenderer(FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); return renderer; } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index bf3c568012..2df1196a86 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -181,7 +181,7 @@ double diffclock(timeval *clock1,timeval *clock2) static TextRenderer* textRenderer(int mono) { static TextRenderer* monoRenderer = new TextRenderer(MONO_FONT_FAMILY); - static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY); + static TextRenderer* proportionalRenderer = new TextRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); return mono ? monoRenderer : proportionalRenderer; } diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 3130463398..df04988bc9 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -19,9 +19,10 @@ Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int wid _textureID(textureID), _location(location), _bounds(bounds), _width(width) { } -TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic) - : _font(family, pointSize, weight, italic), - _metrics(_font), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0) { +TextRenderer::TextRenderer(const char* family, int pointSize, int weight, + bool italic, EffectType effectType, int effectThickness) + : _font(family, pointSize, weight, italic), _metrics(_font), _effectType(effectType), + _effectThickness(effectThickness), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0) { _font.setKerning(false); } @@ -97,6 +98,14 @@ const Glyph& TextRenderer::getGlyph(char c) { glyph = Glyph(0, QPoint(), QRect(), _metrics.width(ch)); return glyph; } + // grow the bounds to account for effect, if any + if (_effectType == SHADOW_EFFECT) { + bounds.adjust(-_effectThickness, 0, 0, _effectThickness); + + } else if (_effectType == OUTLINE_EFFECT) { + bounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness); + } + // grow the bounds to account for antialiasing bounds.adjust(-1, -1, 1, 1); @@ -128,6 +137,23 @@ const Glyph& TextRenderer::getGlyph(char c) { image.fill(0); QPainter painter(&image); painter.setFont(_font); + if (_effectType == SHADOW_EFFECT) { + for (int i = 0; i < _effectThickness; i++) { + painter.drawText(-bounds.x() - i, -bounds.y() + i, ch); + } + } else if (_effectType == OUTLINE_EFFECT) { + QPainterPath path; + QFont font = _font; + font.setStyleStrategy(QFont::ForceOutline); + path.addText(-bounds.x() - 0.5, -bounds.y() + 0.5, font, ch); + QPen pen; + pen.setWidth(_effectThickness); + pen.setJoinStyle(Qt::RoundJoin); + pen.setCapStyle(Qt::RoundCap); + painter.setPen(pen); + painter.setRenderHint(QPainter::Antialiasing); + painter.drawPath(path); + } painter.setPen(QColor(255, 255, 255)); painter.drawText(-bounds.x(), -bounds.y(), ch); } diff --git a/interface/src/ui/TextRenderer.h b/interface/src/ui/TextRenderer.h index 6de0c77bad..6df7186d86 100644 --- a/interface/src/ui/TextRenderer.h +++ b/interface/src/ui/TextRenderer.h @@ -23,7 +23,10 @@ class Glyph; class TextRenderer { public: - TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false); + enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; + + TextRenderer(const char* family, int pointSize = -1, int weight = -1, bool italic = false, + EffectType effect = NO_EFFECT, int effectThickness = 2); ~TextRenderer(); const QFontMetrics& metrics() const { return _metrics; } @@ -42,6 +45,12 @@ private: // the font metrics QFontMetrics _metrics; + + // the type of effect to apply + EffectType _effectType; + + // the thickness of the effect + int _effectThickness; // maps characters to cached glyph info QHash _glyphs; From e55efb81a83142ab3299fa11aabfde93ae1fa625 Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Thu, 16 May 2013 19:12:48 -0600 Subject: [PATCH 24/24] Added acceleration decay of pitch (you look up/straight if you start moving) --- interface/src/Avatar.cpp | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index bb70f230a9..0e7cad3f05 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace std; @@ -29,8 +30,6 @@ const float THRUST_MAG = 1200.0; const float YAW_MAG = 500.0; const float BODY_SPIN_FRICTION = 5.0; const float BODY_UPRIGHT_FORCE = 10.0; -const float BODY_PITCH_WHILE_WALKING = 40.0; -const float BODY_ROLL_WHILE_TURNING = 0.1; const float VELOCITY_DECAY = 5.0; const float MY_HAND_HOLDING_PULL = 0.2; const float YOUR_HAND_HOLDING_PULL = 1.0; @@ -50,7 +49,6 @@ const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float AVATAR_BRAKING_RANGE = 1.6f; const float AVATAR_BRAKING_STRENGTH = 30.0f; -//const float MAX_JOINT_TOUCH_DOT = 0.995f; const float JOINT_TOUCH_RANGE = 0.0005f; float skinColor [] = {1.0, 0.84, 0.66}; @@ -188,15 +186,6 @@ Avatar::Avatar(const Avatar &otherAvatar) { initializeSkeleton(); -/* - if (iris_texture.size() == 0) { - switchToResourcesParentIfRequired(); - unsigned error = lodepng::decode(iris_texture, iris_texture_width, iris_texture_height, iris_texture_file); - if (error != 0) { - printLog("error %u: %s\n", error, lodepng_error_text(error)); - } - } -*/ } Avatar::~Avatar() { @@ -332,7 +321,10 @@ void Avatar::updateFromMouse(int mouseX, int mouseY, int screenWidth, int scree void Avatar::simulate(float deltaTime) { - //figure out if the mouse cursor is over any body spheres... + // copy velocity so we can use it later for acceleration + glm::vec3 oldVelocity = getVelocity(); + + // figure out if the mouse cursor is over any body spheres... checkForMouseRayTouching(); // update balls @@ -403,10 +395,12 @@ void Avatar::simulate(float deltaTime) { // add thrust to velocity _velocity += _thrust * deltaTime; - // calculate speed + // calculate speed _speed = glm::length(_velocity); //pitch and roll the body as a function of forward speed and turning delta + const float BODY_PITCH_WHILE_WALKING = 20.0; + const float BODY_ROLL_WHILE_TURNING = 0.2; float forwardComponentOfVelocity = glm::dot(_orientation.getFront(), _velocity); _bodyPitch += BODY_PITCH_WHILE_WALKING * deltaTime * forwardComponentOfVelocity; _bodyRoll += BODY_ROLL_WHILE_TURNING * deltaTime * _speed * _bodyYawDelta; @@ -442,10 +436,15 @@ void Avatar::simulate(float deltaTime) { } } + // Compute instantaneous acceleration + float acceleration = glm::distance(getVelocity(), oldVelocity) / deltaTime; + const float ACCELERATION_PITCH_DECAY = 0.4f; - - - + // Decay HeadPitch as a function of acceleration, so that you look straight ahead when + // you start moving, but don't do this with an HMD like the Oculus. + if (!OculusManager::isConnected()) { + setHeadPitch(getHeadPitch() * (1.f - acceleration * ACCELERATION_PITCH_DECAY * deltaTime)); + } // Get head position data from network for other people if (!_isMine) { _head.leanSideways = getHeadLeanSideways();