From 974c88442c7d10479bc61a54493cbd8833d3fc1c Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Fri, 29 Aug 2014 14:36:11 -0700 Subject: [PATCH 01/35] new audio format object --- libraries/audio/src/AudioFormat.h | 84 +++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 libraries/audio/src/AudioFormat.h diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h new file mode 100644 index 0000000000..0ded25d0c3 --- /dev/null +++ b/libraries/audio/src/AudioFormat.h @@ -0,0 +1,84 @@ +// +// AudioFormat.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/28/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioFormat_h +#define hifi_AudioFormat_h + +#ifndef _FLOAT32_T +#define _FLOAT32_T +typedef float float32_t; +#endif + +#ifndef _FLOAT64_T +#define _FLOAT64_T +typedef double float64_t; +#endif + +// +// Audio format structure (uncompressed streams only) +// + +struct AudioFormat { + + struct Flags { + uint32_t _isFloat : 1; + uint32_t _isSigned : 1; + uint32_t _isInterleaved : 1; + uint32_t _isBigEndian : 1; + uint32_t _isPacked : 1; + uint32_t _reserved : 27; + } _flags; + + uint32_t _bytesPerFrame; + uint32_t _channelsPerFrame; + uint32_t _bitsPerChannel; + float64_t _sampleRate; + + AudioFormat() { + std::memset(this, 0, sizeof(*this)); + } + ~AudioFormat() { } + + AudioFormat& operator=(const AudioFormat& fmt) { + std::memcpy(this, &fmt, sizeof(*this)); + return *this; + } + + bool operator==(const AudioFormat& fmt) { + return std::memcmp(this, &fmt, sizeof(*this)) == 0; + } + + bool operator!=(const AudioFormat& fmt) { + return std::memcmp(this, &fmt, sizeof(*this)) != 0; + } + + void setCanonicalFloat32(uint32_t channels) { + assert(channels > 0 && channels <= 2); + _sampleRate = SAMPLE_RATE; + _bitsPerChannel = sizeof(float32_t) * 8; + _channelsPerFrame = channels; + _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; + _flags._isFloat = true; + _flags._isInterleaved = _channelsPerFrame > 1; + } + + void setCanonicalInt16(uint32_t channels) { + assert(channels > 0 && channels <= 2); + _sampleRate = SAMPLE_RATE; + _bitsPerChannel = sizeof(int16_t) * 8; + _channelsPerFrame = channels; + _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; + _flags._isSigned = true; + _flags._isInterleaved = _channelsPerFrame > 1; + } +}; + +#endif // hifi_AudioFormat_h From 68fa44f845aa5b45c851079f47eb7bf050101d5a Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Fri, 5 Sep 2014 18:30:39 -0700 Subject: [PATCH 02/35] audio menu changes to support tone and noise generators --- interface/src/Menu.cpp | 24 ++++++++++++++++++++++-- interface/src/Menu.h | 4 +++- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 0dcfd60051..c2620c1e46 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -544,11 +544,31 @@ Menu::Menu() : 0, this, SLOT(muteEnvironment())); - addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioToneInjection, + + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioSourceInject, 0, false, appInstance->getAudio(), - SLOT(toggleToneInjection())); + SLOT(toggleAudioSourceInject())); + QMenu* audioSourceMenu = audioDebugMenu->addMenu("Generated Audio Source"); + { + QAction *pinkNoise = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourcePinkNoise, + 0, + false, + appInstance->getAudio(), + SLOT(selectAudioSourcePinkNoise())); + + QAction *sine440 = addCheckableActionToQMenuAndActionHash(audioSourceMenu, MenuOption::AudioSourceSine440, + 0, + true, + appInstance->getAudio(), + SLOT(selectAudioSourceSine440)); + + QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu); + audioSourceGroup->addAction(pinkNoise); + audioSourceGroup->addAction(sine440); + } + addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScope, Qt::CTRL | Qt::Key_P, false, appInstance->getAudio(), diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 1d57da2891..a00da23b7b 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -346,7 +346,9 @@ namespace MenuOption { const QString AudioSpatialProcessingSlightlyRandomSurfaces = "Slightly Random Surfaces"; const QString AudioSpatialProcessingStereoSource = "Stereo Source"; const QString AudioSpatialProcessingWithDiffusions = "With Diffusions"; - const QString AudioToneInjection = "Inject Test Tone"; + const QString AudioSourceInject = "Generated Audio"; + const QString AudioSourcePinkNoise = "Pink Noise"; + const QString AudioSourceSine440 = "Sine 440hz"; const QString Avatars = "Avatars"; const QString AvatarsReceiveShadows = "Avatars Receive Shadows"; const QString Bandwidth = "Bandwidth Display"; From c6911274f610c2f2e7da903d7827f3ca61ecdf3e Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:14:47 -0700 Subject: [PATCH 03/35] new tone generator audio source object --- libraries/audio/src/AudioSourceTone.cpp | 20 +++++++ libraries/audio/src/AudioSourceTone.h | 69 +++++++++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 libraries/audio/src/AudioSourceTone.cpp create mode 100644 libraries/audio/src/AudioSourceTone.h diff --git a/libraries/audio/src/AudioSourceTone.cpp b/libraries/audio/src/AudioSourceTone.cpp new file mode 100644 index 0000000000..80a6aed48e --- /dev/null +++ b/libraries/audio/src/AudioSourceTone.cpp @@ -0,0 +1,20 @@ +// +// AudioSourceTone.cpp +// hifi +// +// Created by Craig Hansen-Sturm on 8/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceTone.h" + +uint32_t AudioSourceTone::_frameOffset = 0; diff --git a/libraries/audio/src/AudioSourceTone.h b/libraries/audio/src/AudioSourceTone.h new file mode 100644 index 0000000000..fb9d6be0fe --- /dev/null +++ b/libraries/audio/src/AudioSourceTone.h @@ -0,0 +1,69 @@ +// +// AudioSourceTone.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioSourceTone_h +#define hifi_AudioSourceTone_h + +class AudioSourceTone +{ + static uint32_t _frameOffset; + float32_t _frequency; + float32_t _sampleRate; + float32_t _omega; + +public: + AudioSourceTone() { + initialize(); + } + + ~AudioSourceTone() { + finalize(); + } + + void initialize() { + _frameOffset = 0; + setParameters(SAMPLE_RATE, 220.0f); + } + + void finalize() { + } + + void reset() { + _frameOffset = 0; + } + + void setParameters(const float32_t sampleRate, const float32_t frequency) { + _sampleRate = std::max(sampleRate, 1.0f); + _frequency = std::max(frequency, 1.0f); + _omega = _frequency / _sampleRate * TWO_PI; + } + + void getParameters(float32_t& sampleRate, float32_t& frequency) { + sampleRate = _sampleRate; + frequency = _frequency; + } + + void render(AudioBufferFloat32& frameBuffer) { + + // note: this is a placeholder implementation. final version will not include any transcendental ops in our render loop + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) { + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + samples[j][i] = sinf((i + _frameOffset) * _omega); + } + } + _frameOffset += frameBuffer.getFrameCount(); + } +}; + +#endif + From 3a9a4a64024068644068fc069e31fa7bdc552de8 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:16:00 -0700 Subject: [PATCH 04/35] new pink noise generator audio source object --- libraries/audio/src/AudioSourceNoise.cpp | 21 +++++ libraries/audio/src/AudioSourceNoise.h | 103 +++++++++++++++++++++++ 2 files changed, 124 insertions(+) create mode 100644 libraries/audio/src/AudioSourceNoise.cpp create mode 100644 libraries/audio/src/AudioSourceNoise.h diff --git a/libraries/audio/src/AudioSourceNoise.cpp b/libraries/audio/src/AudioSourceNoise.cpp new file mode 100644 index 0000000000..6cfdf82fd9 --- /dev/null +++ b/libraries/audio/src/AudioSourceNoise.cpp @@ -0,0 +1,21 @@ +// +// AudioSourceNoise.cpp +// hifi +// +// Created by Craig Hansen-Sturm on 8/10/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include +#include +#include +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceNoise.h" + +template<> +uint32_t AudioSourcePinkNoise::_randomSeed = 1974; // a truly random number diff --git a/libraries/audio/src/AudioSourceNoise.h b/libraries/audio/src/AudioSourceNoise.h new file mode 100644 index 0000000000..88340628e9 --- /dev/null +++ b/libraries/audio/src/AudioSourceNoise.h @@ -0,0 +1,103 @@ +// +// AudioSourceNoise.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// +// Adapted from code by Phil Burk http://www.firstpr.com.au/dsp/pink-noise/ +// + +#ifndef hifi_AudioSourceNoise_h +#define hifi_AudioSourceNoise_h + +template< const uint16_t N = 30> +class AudioSourceNoise +{ + static const uint16_t _randomRows = N; + static const uint16_t _randomBits = 24; + static const uint16_t _randomShift = (sizeof(int32_t) * 8) - _randomBits; + + static uint32_t _randomSeed; + + int32_t _rows[_randomRows]; + int32_t _runningSum; // used to optimize summing of generators. + uint16_t _index; // incremented each sample. + uint16_t _indexMask; // index wrapped by ANDing with this mask. + float32_t _scale; // used to scale within range of -1.0 to +1.0 + + static uint32_t generateRandomNumber() { + _randomSeed = (_randomSeed * 196314165) + 907633515; + return _randomSeed >> _randomShift; + } + +public: + AudioSourceNoise() { + initialize(); + } + + ~AudioSourceNoise() { + finalize(); + } + + void initialize() { + std::memset(_rows, 0, _randomRows * sizeof(int32_t)); + + _runningSum = 0; + _index = 0; + _indexMask = (1 << _randomRows) - 1; + _scale = 1.0f / ((_randomRows + 1) * (1 << (_randomBits - 1))); + } + + void finalize() { + } + + void reset() { + initialize(); + } + + void setParameters(void) { + } + + void getParameters(void) { + } + + void render(AudioBufferFloat32& frameBuffer) { + + uint32_t randomNumber; + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); ++i) { + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + + _index = (_index + 1) & _indexMask; // increment and mask index. + if (_index != 0) { // if index is zero, don't update any random values. + + uint32_t numZeros = 0; // determine how many trailing zeros in _index + uint32_t tmp = _index; + while ((tmp & 1) == 0) { + tmp >>= 1; + numZeros++; + } + // replace the indexed _rows random value. subtract and add back to _runningSum instead + // of adding all the random values together. only one value changes each time. + _runningSum -= _rows[numZeros]; + randomNumber = generateRandomNumber(); + _runningSum += randomNumber; + _rows[numZeros] = randomNumber; + } + + // add extra white noise value and scale between -1.0 and +1.0 + samples[j][i] = (_runningSum + generateRandomNumber()) * _scale; + } + } + } +}; + +typedef AudioSourceNoise<> AudioSourcePinkNoise; + +#endif // AudioSourceNoise_h + From f439475f3ce6cfb622edaab5526b86037621cbee Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:18:04 -0700 Subject: [PATCH 05/35] new audio gain/mute object --- libraries/audio/src/AudioGain.h | 75 +++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 libraries/audio/src/AudioGain.h diff --git a/libraries/audio/src/AudioGain.h b/libraries/audio/src/AudioGain.h new file mode 100644 index 0000000000..c2cc64cba5 --- /dev/null +++ b/libraries/audio/src/AudioGain.h @@ -0,0 +1,75 @@ +// +// AudioGain.h +// hifi +// +// Created by Craig Hansen-Sturm on 9/1/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioGain_h +#define hifi_AudioGain_h + +class AudioGain +{ + float32_t _gain; + bool _mute; + +public: + AudioGain() { + initialize(); + } + + ~AudioGain() { + finalize(); + } + + void initialize() { + setParameters(1.0f,0.0f); + } + + void finalize() { + } + + void reset() { + initialize(); + } + + void setParameters(const float gain, const float mute) { + _gain = std::min(std::max(gain, 0.0f), 1.0f); + _mute = mute != 0.0f; + + } + + void getParameters(float& gain, float& mute) { + gain = _gain; + mute = _mute ? 1.0f : 0.0f; + } + + void render(AudioBufferFloat32& frameBuffer) { + if (_mute) { + frameBuffer.zeroFrames(); + return; + } + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); i += 8) { + samples[j][i + 0] *= _gain; + samples[j][i + 1] *= _gain; + samples[j][i + 2] *= _gain; + samples[j][i + 3] *= _gain; + samples[j][i + 4] *= _gain; + samples[j][i + 5] *= _gain; + samples[j][i + 6] *= _gain; + samples[j][i + 7] *= _gain; + } + } + } +}; + +#endif // AudioGain_h + + From 0b33c344fffbcc83eaf55bc6e5010549297b0dd0 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:18:35 -0700 Subject: [PATCH 06/35] new audio buffer object --- libraries/audio/src/AudioBuffer.h | 174 ++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 libraries/audio/src/AudioBuffer.h diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h new file mode 100644 index 0000000000..dd0030ecd8 --- /dev/null +++ b/libraries/audio/src/AudioBuffer.h @@ -0,0 +1,174 @@ +// +// AudioBuffer.h +// hifi +// +// Created by Craig Hansen-Sturm on 8/29/14. +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_AudioBuffer_h +#define hifi_AudioBuffer_h + +#include + +template< typename T > +class AudioFrameBuffer { + + uint16_t _channelCount; + uint16_t _frameCount; + uint16_t _frameCountMax; + + T** _frameBuffer; + + void allocateFrames() { + _frameBuffer = new T*[_channelCount]; + if (_frameBuffer) { + for (uint16_t i = 0; i < _channelCount; ++i) { + _frameBuffer[i] = new T[_frameCountMax]; + } + } + } + + void deallocateFrames() { + if (_frameBuffer) { + for (uint16_t i = 0; i < _channelCount; ++i) { + delete _frameBuffer[i]; + } + delete _frameBuffer; + } + _frameBuffer = NULL; + } + +public: + + AudioFrameBuffer() + : _channelCount(0) + , _frameCount(0) + , _frameCountMax(0) + , _frameBuffer(NULL) { + } + + AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) + : _channelCount(channelCount) + , _frameCount(frameCount) + , _frameCountMax(frameCount) + , _frameBuffer(NULL) { + allocateFrames(); + } + + ~AudioFrameBuffer() { + finalize(); + } + + void initialize(const uint16_t channelCount, const uint16_t frameCount) { + if (_frameBuffer) { + finalize(); + } + _channelCount = channelCount; + _frameCount = frameCount; + _frameCountMax = frameCount; + allocateFrames(); + } + + void finalize() { + deallocateFrames(); + _channelCount = 0; + _frameCount = 0; + } + + T**& getFrameData() { + return _frameBuffer; + } + + uint16_t getChannelCount() { + return _channelCount; + } + + uint16_t getFrameCount() { + return _frameCount; + } + + void zeroFrames() { + if (!_frameBuffer) { + return; + } + for (uint16_t i = 0; i < _channelCount; ++i) { + std::memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); + } + } + + template< typename S > + void copyFrames(uint16_t channelCount, const uint16_t frameCount, S* frames, const bool copyOut = false) { + if ( !_frameBuffer || !frames) { + return; + } + assert(channelCount == _channelCount); + assert(frameCount <= _frameCountMax); + + _frameCount = frameCount; // we allow copying fewer frames than we've allocated + + if (copyOut) { + S* dst = frames; + + if(typeid(T) == typeid(S)) { // source and destination types are the same + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + *dst++ = _frameBuffer[j][i]; + } + } + } + else { + if(typeid(T) == typeid(float32_t) && + typeid(S) == typeid(int16_t)) { + + const int scale = (2 << ((8 * sizeof(S)) - 1)); + + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + *dst++ = (S)(_frameBuffer[j][i] * scale); + } + } + } + else { + assert(0); // currently unsupported conversion + } + } + } + else { // copyIn + S* src = frames; + + if(typeid(T) == typeid(S)) { // source and destination types are the same + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + _frameBuffer[j][i] = *src++; + } + } + } + else { + if(typeid(T) == typeid(float32_t) && + typeid(S) == typeid(int16_t)) { + + const int scale = (2 << ((8 * sizeof(S)) - 1)); + + for (int i = 0; i < _frameCount; ++i) { + for (int j = 0; j < _channelCount; ++j) { + _frameBuffer[j][i] = ((T)(*src++)) / scale; + } + } + } + else { + assert(0); // currently unsupported conversion + } + } + } + } +}; + +typedef AudioFrameBuffer< float32_t > AudioBufferFloat32; +typedef AudioFrameBuffer< int32_t > AudioBufferSInt32; + +#endif // hifi_AudioBuffer_h + From 8ecf0870e7c7ff8325e9835155a9e5417d3e9359 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:20:14 -0700 Subject: [PATCH 07/35] dependency on new audiobuffer and audioformat objects --- libraries/audio/src/PositionalAudioStream.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/audio/src/PositionalAudioStream.h b/libraries/audio/src/PositionalAudioStream.h index a7f59aebde..f5f1b9027a 100644 --- a/libraries/audio/src/PositionalAudioStream.h +++ b/libraries/audio/src/PositionalAudioStream.h @@ -16,6 +16,8 @@ #include #include "InboundAudioStream.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" #include "AudioFilter.h" #include "AudioFilterBank.h" From 5bab1ee7f58d49d4bea8334afbef7d563b7bc603 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:22:27 -0700 Subject: [PATCH 08/35] dependency on new audiobuffer and audioformat objects/render call now uses audiobuffers --- libraries/audio/src/AudioFilterBank.cpp | 3 +++ libraries/audio/src/AudioFilterBank.h | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioFilterBank.cpp b/libraries/audio/src/AudioFilterBank.cpp index a7b969540a..6599b29a01 100644 --- a/libraries/audio/src/AudioFilterBank.cpp +++ b/libraries/audio/src/AudioFilterBank.cpp @@ -9,9 +9,12 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include #include #include #include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" #include "AudioFilter.h" #include "AudioFilterBank.h" diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index c523736a57..2ea29cb3a9 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -64,7 +64,7 @@ public: // // public interface // - void initialize(const float sampleRate, const int frameCount) { + void initialize(const float sampleRate, const int frameCount = 0) { finalize(); for (int i = 0; i < _channelCount; ++i) { @@ -141,6 +141,17 @@ public: } } + void render(AudioBufferFloat32& frameBuffer) { + + float32_t** samples = frameBuffer.getFrameData(); + for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { + for (int i = 0; i < _filterCount; ++i) { + _filters[i][j].render( samples[j], samples[j], frameBuffer.getFrameCount() ); + } + } + + } + void reset() { for (int i = 0; i < _filterCount; ++i) { for (int j = 0; j < _channelCount; ++j) { From 7a5ec429d19509b51856142ab65f8936c387d1a5 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:29:48 -0700 Subject: [PATCH 09/35] audio rendering loop now uses input-gain, tone-generator, noise-generator, and post-generator-gain objects / audiobuffer object now shared between all new audio objects / zero buffer copy between new objects / inline tone-generator code removed / new audio options for generators --- interface/src/Audio.cpp | 82 ++++++++++++++++++++++++++++------------- interface/src/Audio.h | 36 +++++++++++++++--- 2 files changed, 88 insertions(+), 30 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 8a788df831..3c13d3825d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -40,6 +40,7 @@ #include #include "Audio.h" + #include "Menu.h" #include "Util.h" #include "PositionalAudioStream.h" @@ -82,7 +83,7 @@ Audio::Audio(QObject* parent) : _noiseGateSampleCounter(0), _noiseGateOpen(false), _noiseGateEnabled(true), - _toneInjectionEnabled(false), + _audioSourceInjectEnabled(false), _noiseGateFramesToClose(0), _totalInputAudioSamples(0), _collisionSoundMagnitude(0.0f), @@ -102,6 +103,8 @@ Audio::Audio(QObject* parent) : _framesPerScope(DEFAULT_FRAMES_PER_SCOPE), _samplesPerScope(NETWORK_SAMPLES_PER_FRAME * _framesPerScope), _peqEnabled(false), + _noiseSourceEnabled(false), + _toneSourceEnabled(true), _scopeInput(0), _scopeOutputLeft(0), _scopeOutputRight(0), @@ -137,6 +140,10 @@ void Audio::reset() { _receivedAudioStream.reset(); resetStats(); _peq.reset(); + _noiseSource.reset(); + _toneSource.reset(); + _sourceGain.reset(); + _inputGain.reset(); } void Audio::resetStats() { @@ -424,14 +431,25 @@ void Audio::start() { qDebug() << "Unable to set up audio output because of a problem with output format."; } - _peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() ); - + _inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 2 ); + _peq.initialize( _inputFormat.sampleRate() ); + _inputGain.initialize(); + _sourceGain.initialize(); + _noiseSource.initialize(); + _toneSource.initialize(); + _sourceGain.setParameters(0.25f,0.0f); + _inputGain.setParameters(1.0f,0.0f); } void Audio::stop() { + _inputFrameBuffer.finalize(); _peq.finalize(); - + _inputGain.finalize(); + _sourceGain.finalize(); + _noiseSource.finalize(); + _toneSource.finalize(); + // "switch" to invalid devices in order to shut down the state switchInputToAudioDevice(QAudioDeviceInfo()); switchOutputToAudioDevice(QAudioDeviceInfo()); @@ -477,14 +495,30 @@ void Audio::handleAudioInput() { QByteArray inputByteArray = _inputDevice->readAll(); + int16_t* inputBuffer = (int16_t*)inputByteArray.data(); + const int inputFrameCount = inputByteArray.size() / sizeof(int16_t); + + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, false /*copy in*/); + + _inputGain.render(_inputFrameBuffer); // input/mic gain+mute + + // Add audio source injection if enabled + if (_audioSourceInjectEnabled && !_muted) { + + if (_toneSourceEnabled) { // sine generator + _toneSource.render(_inputFrameBuffer); + } + else if(_noiseSourceEnabled) { // pink noise generator + _noiseSource.render(_inputFrameBuffer); + } + _sourceGain.render(_inputFrameBuffer); // post gain + } if (_peqEnabled && !_muted) { - // we wish to pre-filter our captured input, prior to loopback - - int16_t* ioBuffer = (int16_t*)inputByteArray.data(); - - _peq.render(ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t)); + _peq.render(_inputFrameBuffer); // 3-band parametric eq } + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, true /*copy out*/); + if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { // if this person wants local loopback add that to the locally injected audio @@ -522,7 +556,7 @@ void Audio::handleAudioInput() { int16_t* inputAudioSamples = new int16_t[inputSamplesRequired]; _inputRingBuffer.readSamples(inputAudioSamples, inputSamplesRequired); - + const int numNetworkBytes = _isStereoInput ? NETWORK_BUFFER_LENGTH_BYTES_STEREO : NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL; const int numNetworkSamples = _isStereoInput ? NETWORK_BUFFER_LENGTH_SAMPLES_STEREO : NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; @@ -599,20 +633,8 @@ void Audio::handleAudioInput() { _dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset; } - // Add tone injection if enabled - const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI; - const float QUARTER_VOLUME = 8192.0f; - if (_toneInjectionEnabled) { - loudness = 0.0f; - for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) { - networkAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample)); - loudness += fabsf(networkAudioSamples[i]); - } - } - _lastInputLoudness = fabs(loudness / NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL); - // If Noise Gate is enabled, check and turn the gate on and off - if (!_toneInjectionEnabled && _noiseGateEnabled) { + if (!_audioSourceInjectEnabled && _noiseGateEnabled) { float averageOfAllSampleFrames = 0.0f; _noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness; if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) { @@ -1041,8 +1063,18 @@ void Audio::processProceduralAudio(int16_t* monoInput, int numSamples) { } } -void Audio::toggleToneInjection() { - _toneInjectionEnabled = !_toneInjectionEnabled; +void Audio::toggleAudioSourceInject() { + _audioSourceInjectEnabled = !_audioSourceInjectEnabled; +} + +void Audio::selectAudioSourcePinkNoise() { + _noiseSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourcePinkNoise); + _toneSourceEnabled = !_noiseSourceEnabled; +} + +void Audio::selectAudioSourceSine440() { + _toneSourceEnabled = Menu::getInstance()->isOptionChecked(MenuOption::AudioSourceSine440); + _noiseSourceEnabled = !_toneSourceEnabled; } void Audio::toggleAudioSpatialProcessing() { diff --git a/interface/src/Audio.h b/interface/src/Audio.h index b5069f3b3a..f73e0331de 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -20,6 +20,12 @@ #include "Recorder.h" #include "RingBufferHistory.h" #include "MovingMinMaxAvg.h" +#include "AudioRingBuffer.h" +#include "AudioFormat.h" +#include "AudioBuffer.h" +#include "AudioSourceTone.h" +#include "AudioSourceNoise.h" +#include "AudioGain.h" #include "AudioFilter.h" #include "AudioFilterBank.h" @@ -116,7 +122,9 @@ public slots: void audioMixerKilled(); void toggleMute(); void toggleAudioNoiseReduction(); - void toggleToneInjection(); + void toggleAudioSourceInject(); + void selectAudioSourcePinkNoise(); + void selectAudioSourceSine440(); void toggleScope(); void toggleScopePause(); void toggleStats(); @@ -199,7 +207,8 @@ private: int _noiseGateSampleCounter; bool _noiseGateOpen; bool _noiseGateEnabled; - bool _toneInjectionEnabled; + bool _audioSourceInjectEnabled; + int _noiseGateFramesToClose; int _totalInputAudioSamples; @@ -282,10 +291,27 @@ private: int _framesPerScope; int _samplesPerScope; - // Multi-band parametric EQ - bool _peqEnabled; - AudioFilterPEQ3m _peq; + // Input framebuffer + AudioBufferFloat32 _inputFrameBuffer; + + // Input gain + AudioGain _inputGain; + + // Post tone/pink noise generator gain + AudioGain _sourceGain; + // Pink noise source + bool _noiseSourceEnabled; + AudioSourcePinkNoise _noiseSource; + + // Tone source + bool _toneSourceEnabled; + AudioSourceTone _toneSource; + + // Multi-band parametric EQ + bool _peqEnabled; + AudioFilterPEQ3m _peq; + QMutex _guard; QByteArray* _scopeInput; QByteArray* _scopeOutputLeft; From 1eba20bc3bd44feaa208752aa45cd2f6714d4287 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:32:13 -0700 Subject: [PATCH 10/35] minor cleanup --- libraries/audio/src/AudioFormat.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h index 0ded25d0c3..da082ead94 100644 --- a/libraries/audio/src/AudioFormat.h +++ b/libraries/audio/src/AudioFormat.h @@ -23,7 +23,7 @@ typedef double float64_t; #endif // -// Audio format structure (uncompressed streams only) +// Audio format structure (currently for uncompressed streams only) // struct AudioFormat { @@ -62,7 +62,7 @@ struct AudioFormat { void setCanonicalFloat32(uint32_t channels) { assert(channels > 0 && channels <= 2); - _sampleRate = SAMPLE_RATE; + _sampleRate = SAMPLE_RATE; // todo: create audio constants header _bitsPerChannel = sizeof(float32_t) * 8; _channelsPerFrame = channels; _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; @@ -72,7 +72,7 @@ struct AudioFormat { void setCanonicalInt16(uint32_t channels) { assert(channels > 0 && channels <= 2); - _sampleRate = SAMPLE_RATE; + _sampleRate = SAMPLE_RATE; // todo: create audio constants header _bitsPerChannel = sizeof(int16_t) * 8; _channelsPerFrame = channels; _bytesPerFrame = _channelsPerFrame * _bitsPerChannel / 8; From f309875069e0060d99df535e6fcf7a5e7cd7af06 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:50:37 -0700 Subject: [PATCH 11/35] formatting/renaming --- interface/src/Audio.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 3c13d3825d..0d114b7208 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -495,10 +495,10 @@ void Audio::handleAudioInput() { QByteArray inputByteArray = _inputDevice->readAll(); - int16_t* inputBuffer = (int16_t*)inputByteArray.data(); + int16_t* inputFrameData = (int16_t*)inputByteArray.data(); const int inputFrameCount = inputByteArray.size() / sizeof(int16_t); - _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, false /*copy in*/); + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, false /*copy in*/); _inputGain.render(_inputFrameBuffer); // input/mic gain+mute @@ -517,7 +517,7 @@ void Audio::handleAudioInput() { _peq.render(_inputFrameBuffer); // 3-band parametric eq } - _inputFrameBuffer.copyFrames(1, inputFrameCount, inputBuffer, true /*copy out*/); + _inputFrameBuffer.copyFrames(1, inputFrameCount, inputFrameData, true /*copy out*/); if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { // if this person wants local loopback add that to the locally injected audio From e2f3392f09517a5a350b70a75c61772d819b39e3 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 02:51:11 -0700 Subject: [PATCH 12/35] formatting/renaming --- libraries/audio/src/AudioFilterBank.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index 2ea29cb3a9..46d781075a 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -149,7 +149,6 @@ public: _filters[i][j].render( samples[j], samples[j], frameBuffer.getFrameCount() ); } } - } void reset() { From e64c81420e0c0da2fd40cb6d68963b0e2bca2b81 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 03:29:14 -0700 Subject: [PATCH 13/35] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioFormat.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/libraries/audio/src/AudioFormat.h b/libraries/audio/src/AudioFormat.h index da082ead94..9548138f58 100644 --- a/libraries/audio/src/AudioFormat.h +++ b/libraries/audio/src/AudioFormat.h @@ -42,22 +42,23 @@ struct AudioFormat { uint32_t _bitsPerChannel; float64_t _sampleRate; + AudioFormat() { - std::memset(this, 0, sizeof(*this)); + memset(this, 0, sizeof(*this)); } ~AudioFormat() { } AudioFormat& operator=(const AudioFormat& fmt) { - std::memcpy(this, &fmt, sizeof(*this)); + memcpy(this, &fmt, sizeof(*this)); return *this; } bool operator==(const AudioFormat& fmt) { - return std::memcmp(this, &fmt, sizeof(*this)) == 0; + return memcmp(this, &fmt, sizeof(*this)) == 0; } bool operator!=(const AudioFormat& fmt) { - return std::memcmp(this, &fmt, sizeof(*this)) != 0; + return memcmp(this, &fmt, sizeof(*this)) != 0; } void setCanonicalFloat32(uint32_t channels) { From 76adb952a30da1287f5c0e4d9036472d13c3714b Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 03:57:11 -0700 Subject: [PATCH 14/35] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index dd0030ecd8..7c244f47bf 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -96,7 +96,7 @@ public: return; } for (uint16_t i = 0; i < _channelCount; ++i) { - std::memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); + memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); } } From 2700d8c59d8f76d2427750d9118da86f0e0de51f Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Sat, 6 Sep 2014 04:05:52 -0700 Subject: [PATCH 15/35] ubuntu build fix (remove std::memset ...) --- libraries/audio/src/AudioSourceNoise.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioSourceNoise.h b/libraries/audio/src/AudioSourceNoise.h index 88340628e9..26cb21a065 100644 --- a/libraries/audio/src/AudioSourceNoise.h +++ b/libraries/audio/src/AudioSourceNoise.h @@ -44,7 +44,7 @@ public: } void initialize() { - std::memset(_rows, 0, _randomRows * sizeof(int32_t)); + memset(_rows, 0, _randomRows * sizeof(int32_t)); _runningSum = 0; _index = 0; From a824712ee6cdb05b1afecbd3bcb390686a9b2145 Mon Sep 17 00:00:00 2001 From: Chris Collins Date: Mon, 8 Sep 2014 10:55:45 -0700 Subject: [PATCH 16/35] Changed list model icon Changed list-model.svg icon to be consistent with the other icons --- examples/editModels.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/editModels.js b/examples/editModels.js index 9f73b30682..cec1bff783 100644 --- a/examples/editModels.js +++ b/examples/editModels.js @@ -1147,10 +1147,10 @@ var toolBar = (function () { }, true, false); browseModelsButton = toolBar.addTool({ - imageURL: toolIconUrl + "list-icon.png", + imageURL: toolIconUrl + "list-icon.svg", width: toolWidth, height: toolHeight, - alpha: 0.7, + alpha: 0.9, visible: true }); From 431fcbcf6c7ba2eaaed97f690f34d72f83380210 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 8 Sep 2014 11:18:14 -0700 Subject: [PATCH 17/35] coding standard / SLOT selectAudioSourceSine440 linkage / tone gen amplitude parameter --- interface/src/Menu.cpp | 2 +- libraries/audio/src/AudioBuffer.h | 20 ++++++++++---------- libraries/audio/src/AudioFilter.h | 10 +++++----- libraries/audio/src/AudioFilterBank.h | 6 +++--- libraries/audio/src/AudioSourceTone.h | 9 ++++++--- 5 files changed, 25 insertions(+), 22 deletions(-) diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 5f6abe9527..c863c098c2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -563,7 +563,7 @@ Menu::Menu() : 0, true, appInstance->getAudio(), - SLOT(selectAudioSourceSine440)); + SLOT(selectAudioSourceSine440())); QActionGroup* audioSourceGroup = new QActionGroup(audioSourceMenu); audioSourceGroup->addAction(pinkNoise); diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 7c244f47bf..0644139f80 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -44,18 +44,18 @@ class AudioFrameBuffer { public: - AudioFrameBuffer() - : _channelCount(0) - , _frameCount(0) - , _frameCountMax(0) - , _frameBuffer(NULL) { + AudioFrameBuffer() : + _channelCount(0), + _frameCount(0), + _frameCountMax(0), + _frameBuffer(NULL) { } - AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) - : _channelCount(channelCount) - , _frameCount(frameCount) - , _frameCountMax(frameCount) - , _frameBuffer(NULL) { + AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) : + _channelCount(channelCount), + _frameCount(frameCount), + _frameCountMax(frameCount), + _frameBuffer(NULL) { allocateFrames(); } diff --git a/libraries/audio/src/AudioFilter.h b/libraries/audio/src/AudioFilter.h index c2de3860db..c9458f280e 100644 --- a/libraries/audio/src/AudioFilter.h +++ b/libraries/audio/src/AudioFilter.h @@ -37,11 +37,11 @@ public: // // ctor/dtor // - AudioBiquad() - : _xm1(0.) - , _xm2(0.) - , _ym1(0.) - , _ym2(0.) { + AudioBiquad() : + _xm1(0.), + _xm2(0.), + _ym1(0.), + _ym2(0.) { setParameters(0.,0.,0.,0.,0.); } diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index 46d781075a..b9546999d9 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -49,9 +49,9 @@ public: // // ctor/dtor // - AudioFilterBank() - : _sampleRate(0.) - , _frameCount(0) { + AudioFilterBank() : + _sampleRate(0.0f), + _frameCount(0) { for (int i = 0; i < _channelCount; ++i) { _buffer[ i ] = NULL; } diff --git a/libraries/audio/src/AudioSourceTone.h b/libraries/audio/src/AudioSourceTone.h index fb9d6be0fe..5ebe1ba2a9 100644 --- a/libraries/audio/src/AudioSourceTone.h +++ b/libraries/audio/src/AudioSourceTone.h @@ -16,6 +16,7 @@ class AudioSourceTone { static uint32_t _frameOffset; float32_t _frequency; + float32_t _amplitude; float32_t _sampleRate; float32_t _omega; @@ -30,7 +31,7 @@ public: void initialize() { _frameOffset = 0; - setParameters(SAMPLE_RATE, 220.0f); + setParameters(SAMPLE_RATE, 220.0f, 0.9f); } void finalize() { @@ -40,15 +41,17 @@ public: _frameOffset = 0; } - void setParameters(const float32_t sampleRate, const float32_t frequency) { + void setParameters(const float32_t sampleRate, const float32_t frequency, const float32_t amplitude) { _sampleRate = std::max(sampleRate, 1.0f); _frequency = std::max(frequency, 1.0f); + _amplitude = std::max(amplitude, 1.0f); _omega = _frequency / _sampleRate * TWO_PI; } - void getParameters(float32_t& sampleRate, float32_t& frequency) { + void getParameters(float32_t& sampleRate, float32_t& frequency, float32_t& amplitude) { sampleRate = _sampleRate; frequency = _frequency; + amplitude = _amplitude; } void render(AudioBufferFloat32& frameBuffer) { From 5b88e47810f28c8e78845bfa4458e5abd9cbda7d Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 8 Sep 2014 11:31:39 -0700 Subject: [PATCH 18/35] Head movement and hydra/hand movement separated to headMove.js and hydraMove.js --- examples/headMove.js | 77 +++++++++++++++++++++++++++++++++++++++++++ examples/hydraMove.js | 65 +++--------------------------------- 2 files changed, 81 insertions(+), 61 deletions(-) create mode 100644 examples/headMove.js diff --git a/examples/headMove.js b/examples/headMove.js new file mode 100644 index 0000000000..704557b6e7 --- /dev/null +++ b/examples/headMove.js @@ -0,0 +1,77 @@ +// +// headMove.js +// examples +// +// Created by Philip Rosedale on September 8, 2014 +// Copyright 2014 High Fidelity, Inc. +// +// Press the spacebar and move/turn your head to move around. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +var debug = false; + +var movingWithHead = false; +var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw; + +var HEAD_MOVE_DEAD_ZONE = 0.0; +var HEAD_STRAFE_DEAD_ZONE = 0.0; +var HEAD_ROTATE_DEAD_ZONE = 0.0; +var HEAD_THRUST_FWD_SCALE = 12000.0; +var HEAD_THRUST_STRAFE_SCALE = 1000.0; +var HEAD_YAW_RATE = 2.0; +var HEAD_PITCH_RATE = 1.0; +var HEAD_ROLL_THRUST_SCALE = 75.0; +var HEAD_PITCH_LIFT_THRUST = 3.0; + +function moveWithHead(deltaTime) { + if (movingWithHead) { + var deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; + var deltaPitch = MyAvatar.getHeadDeltaPitch() - headStartDeltaPitch; + + var bodyLocalCurrentHeadVector = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); + bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.angleAxis(-deltaYaw, {x:0, y: 1, z:0}), bodyLocalCurrentHeadVector); + var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition); + headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); + headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion + + // Thrust based on leaning forward and side-to-side + if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) { + MyAvatar.addThrust(Vec3.multiply(Quat.getFront(Camera.getOrientation()), -headDelta.z * HEAD_THRUST_FWD_SCALE * deltaTime)); + } + if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) { + MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), headDelta.x * HEAD_THRUST_STRAFE_SCALE * deltaTime)); + } + if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) { + var orientation = Quat.multiply(Quat.angleAxis(deltaYaw * HEAD_YAW_RATE * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation); + MyAvatar.orientation = orientation; + } + // Thrust Up/Down based on head pitch + MyAvatar.addThrust(Vec3.multiply({ x:0, y:1, z:0 }, (MyAvatar.getHeadFinalPitch() - headStartFinalPitch) * HEAD_PITCH_LIFT_THRUST * deltaTime)); + // For head trackers, adjust pitch by head pitch + MyAvatar.headPitch += deltaPitch * HEAD_PITCH_RATE * deltaTime; + // Thrust strafe based on roll ange + MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), -(MyAvatar.getHeadFinalRoll() - headStartRoll) * HEAD_ROLL_THRUST_SCALE * deltaTime)); + } +} + +Controller.keyPressEvent.connect(function(event) { + if (event.text == "SPACE" && !movingWithHead) { + movingWithHead = true; + headStartPosition = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); + headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); + headStartFinalPitch = MyAvatar.getHeadFinalPitch(); + headStartRoll = MyAvatar.getHeadFinalRoll(); + headStartYaw = MyAvatar.getHeadFinalYaw(); + } +}); +Controller.keyReleaseEvent.connect(function(event) { + if (event.text == "SPACE") { + movingWithHead = false; + } +}); + +Script.update.connect(moveWithHead); + diff --git a/examples/hydraMove.js b/examples/hydraMove.js index 853c18ebce..236cecab18 100644 --- a/examples/hydraMove.js +++ b/examples/hydraMove.js @@ -2,7 +2,9 @@ // hydraMove.js // examples // -// Created by Brad Hefta-Gaub on 2/10/14. +// Created by Brad Hefta-Gaub on February 10, 2014 +// Updated by Philip Rosedale on September 8, 2014 +// // Copyright 2014 High Fidelity, Inc. // // This is an example script that demonstrates use of the Controller and MyAvatar classes to implement @@ -34,8 +36,7 @@ var grabbingWithRightHand = false; var wasGrabbingWithRightHand = false; var grabbingWithLeftHand = false; var wasGrabbingWithLeftHand = false; -var movingWithHead = false; -var headStartPosition, headStartDeltaPitch, headStartFinalPitch, headStartRoll, headStartYaw; + var EPSILON = 0.000001; var velocity = { x: 0, y: 0, z: 0}; var THRUST_MAG_UP = 100.0; @@ -243,47 +244,6 @@ function handleGrabBehavior(deltaTime) { wasGrabbingWithLeftHand = grabbingWithLeftHand; } -var HEAD_MOVE_DEAD_ZONE = 0.0; -var HEAD_STRAFE_DEAD_ZONE = 0.0; -var HEAD_ROTATE_DEAD_ZONE = 0.0; -var HEAD_THRUST_FWD_SCALE = 12000.0; -var HEAD_THRUST_STRAFE_SCALE = 1000.0; -var HEAD_YAW_RATE = 2.0; -var HEAD_PITCH_RATE = 1.0; -var HEAD_ROLL_THRUST_SCALE = 75.0; -var HEAD_PITCH_LIFT_THRUST = 3.0; - -function moveWithHead(deltaTime) { - if (movingWithHead) { - var deltaYaw = MyAvatar.getHeadFinalYaw() - headStartYaw; - var deltaPitch = MyAvatar.getHeadDeltaPitch() - headStartDeltaPitch; - - var bodyLocalCurrentHeadVector = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); - bodyLocalCurrentHeadVector = Vec3.multiplyQbyV(Quat.angleAxis(-deltaYaw, {x:0, y: 1, z:0}), bodyLocalCurrentHeadVector); - var headDelta = Vec3.subtract(bodyLocalCurrentHeadVector, headStartPosition); - headDelta = Vec3.multiplyQbyV(Quat.inverse(Camera.getOrientation()), headDelta); - headDelta.y = 0.0; // Don't respond to any of the vertical component of head motion - - // Thrust based on leaning forward and side-to-side - if (Math.abs(headDelta.z) > HEAD_MOVE_DEAD_ZONE) { - MyAvatar.addThrust(Vec3.multiply(Quat.getFront(Camera.getOrientation()), -headDelta.z * HEAD_THRUST_FWD_SCALE * deltaTime)); - } - if (Math.abs(headDelta.x) > HEAD_STRAFE_DEAD_ZONE) { - MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), headDelta.x * HEAD_THRUST_STRAFE_SCALE * deltaTime)); - } - if (Math.abs(deltaYaw) > HEAD_ROTATE_DEAD_ZONE) { - var orientation = Quat.multiply(Quat.angleAxis(deltaYaw * HEAD_YAW_RATE * deltaTime, {x:0, y: 1, z:0}), MyAvatar.orientation); - MyAvatar.orientation = orientation; - } - // Thrust Up/Down based on head pitch - MyAvatar.addThrust(Vec3.multiply({ x:0, y:1, z:0 }, (MyAvatar.getHeadFinalPitch() - headStartFinalPitch) * HEAD_PITCH_LIFT_THRUST * deltaTime)); - // For head trackers, adjust pitch by head pitch - MyAvatar.headPitch += deltaPitch * HEAD_PITCH_RATE * deltaTime; - // Thrust strafe based on roll ange - MyAvatar.addThrust(Vec3.multiply(Quat.getRight(Camera.getOrientation()), -(MyAvatar.getHeadFinalRoll() - headStartRoll) * HEAD_ROLL_THRUST_SCALE * deltaTime)); - } -} - // Update for joysticks and move button function flyWithHydra(deltaTime) { var thrustJoystickPosition = Controller.getJoystickPosition(THRUST_CONTROLLER); @@ -318,12 +278,10 @@ function flyWithHydra(deltaTime) { MyAvatar.orientation = Quat.multiply(orientation, deltaOrientation); // change the headPitch based on our x controller - //pitch += viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime; var newPitch = MyAvatar.headPitch + (viewJoystickPosition.y * JOYSTICK_PITCH_MAG * deltaTime); MyAvatar.headPitch = newPitch; } handleGrabBehavior(deltaTime); - moveWithHead(deltaTime); displayDebug(); } @@ -340,19 +298,4 @@ function scriptEnding() { } Script.scriptEnding.connect(scriptEnding); -Controller.keyPressEvent.connect(function(event) { - if (event.text == "SPACE" && !movingWithHead) { - movingWithHead = true; - headStartPosition = Vec3.subtract(MyAvatar.getHeadPosition(), MyAvatar.position); - headStartDeltaPitch = MyAvatar.getHeadDeltaPitch(); - headStartFinalPitch = MyAvatar.getHeadFinalPitch(); - headStartRoll = MyAvatar.getHeadFinalRoll(); - headStartYaw = MyAvatar.getHeadFinalYaw(); - } -}); -Controller.keyReleaseEvent.connect(function(event) { - if (event.text == "SPACE") { - movingWithHead = false; - } -}); From 0b02376594e9d41dbade4c00f826ce8ca172765c Mon Sep 17 00:00:00 2001 From: Philip Rosedale Date: Mon, 8 Sep 2014 11:39:04 -0700 Subject: [PATCH 19/35] Add head-driven movement to default scripts --- examples/defaultScripts.js | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index d7d704b02b..b655c25b27 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -13,4 +13,5 @@ Script.load("editVoxels.js"); Script.load("editModels.js"); Script.load("selectAudioDevice.js"); Script.load("hydraMove.js"); +Script.load("headMove.js"); Script.load("inspect.js"); From 5b996046ba0842351a6bbfd4e90f740044acfac0 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 8 Sep 2014 12:05:29 -0700 Subject: [PATCH 20/35] Hot FIX: stereo input devices shouldn't trigger an assert --- libraries/audio/src/AudioBuffer.h | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 0644139f80..2ef39430c1 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -18,15 +18,16 @@ template< typename T > class AudioFrameBuffer { uint16_t _channelCount; + uint16_t _channelCountMax; uint16_t _frameCount; uint16_t _frameCountMax; T** _frameBuffer; void allocateFrames() { - _frameBuffer = new T*[_channelCount]; + _frameBuffer = new T*[_channelCountMax]; if (_frameBuffer) { - for (uint16_t i = 0; i < _channelCount; ++i) { + for (uint16_t i = 0; i < _channelCountMax; ++i) { _frameBuffer[i] = new T[_frameCountMax]; } } @@ -34,7 +35,7 @@ class AudioFrameBuffer { void deallocateFrames() { if (_frameBuffer) { - for (uint16_t i = 0; i < _channelCount; ++i) { + for (uint16_t i = 0; i < _channelCountMax; ++i) { delete _frameBuffer[i]; } delete _frameBuffer; @@ -53,6 +54,7 @@ public: AudioFrameBuffer(const uint16_t channelCount, const uint16_t frameCount) : _channelCount(channelCount), + _channelCountMax(channelCount), _frameCount(frameCount), _frameCountMax(frameCount), _frameBuffer(NULL) { @@ -68,6 +70,7 @@ public: finalize(); } _channelCount = channelCount; + _channelCountMax = channelCount; _frameCount = frameCount; _frameCountMax = frameCount; allocateFrames(); @@ -76,7 +79,9 @@ public: void finalize() { deallocateFrames(); _channelCount = 0; + _channelCountMax = 0; _frameCount = 0; + _frameCountMax = 0; } T**& getFrameData() { @@ -95,7 +100,7 @@ public: if (!_frameBuffer) { return; } - for (uint16_t i = 0; i < _channelCount; ++i) { + for (uint16_t i = 0; i < _channelCountMax; ++i) { memset(_frameBuffer[i], 0, sizeof(T)*_frameCountMax); } } @@ -105,10 +110,11 @@ public: if ( !_frameBuffer || !frames) { return; } - assert(channelCount == _channelCount); + assert(channelCount <= _channelCountMax); assert(frameCount <= _frameCountMax); _frameCount = frameCount; // we allow copying fewer frames than we've allocated + _channelCount = channelCount; // we allow copying fewer channels that we've allocated if (copyOut) { S* dst = frames; From f60cea793528807251f8ff8393dec7f5d28ffc30 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 12:10:53 -0700 Subject: [PATCH 21/35] Double the point size on "Retina" displays. --- interface/src/ui/TextRenderer.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 18279d3914..5e7666594a 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -9,11 +9,14 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include +#include #include #include #include #include #include +#include #include "InterfaceConfig.h" #include "TextRenderer.h" @@ -25,10 +28,17 @@ 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, EffectType effectType, int effectThickness, QColor color) - : _font(family, pointSize, weight, italic), _metrics(_font), _effectType(effectType), - _effectThickness(effectThickness), _x(IMAGE_SIZE), _y(IMAGE_SIZE), _rowHeight(0), _color(color) { +TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic, + EffectType effectType, int effectThickness, QColor color) : + _font(family, pointSize * QApplication::desktop()->windowHandle()->devicePixelRatio(), weight, italic), + _metrics(_font), + _effectType(effectType), + _effectThickness(effectThickness), + _x(IMAGE_SIZE), + _y(IMAGE_SIZE), + _rowHeight(0), + _color(color) { + _font.setKerning(false); } From 2d41540dbc77871fbd7c7d0adcb77b81cdf10825 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 12:23:13 -0700 Subject: [PATCH 22/35] Fix for default point size. --- interface/src/ui/TextRenderer.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 5e7666594a..d24acbe270 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -30,7 +30,7 @@ Glyph::Glyph(int textureID, const QPoint& location, const QRect& bounds, int wid TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool italic, EffectType effectType, int effectThickness, QColor color) : - _font(family, pointSize * QApplication::desktop()->windowHandle()->devicePixelRatio(), weight, italic), + _font(family, pointSize, weight, italic), _metrics(_font), _effectType(effectType), _effectThickness(effectThickness), @@ -40,6 +40,12 @@ TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool i _color(color) { _font.setKerning(false); + + // double the font size for "Retina" displays + float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); + if (ratio != 1.0f) { + _font.setPointSize(_font.pointSize() * ratio); + } } TextRenderer::~TextRenderer() { From b9c91b4cfcf0dfa21f97a56932ce28cbe8471f1b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 12:26:28 -0700 Subject: [PATCH 23/35] Fix for metrics. --- interface/src/ui/TextRenderer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index d24acbe270..3e5bde52a4 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -45,6 +45,8 @@ TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool i float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); if (ratio != 1.0f) { _font.setPointSize(_font.pointSize() * ratio); + _metrics = QFontMetrics(_font); + _effectThickness *= ratio; } } From 15025bf8d87c10c3cce8e2558b027aa5096cb61f Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Sep 2014 13:08:08 -0700 Subject: [PATCH 24/35] fix for flickering avatars --- interface/src/avatar/Avatar.cpp | 20 ++++---------------- interface/src/avatar/Avatar.h | 3 --- interface/src/avatar/MyAvatar.cpp | 15 ++++++++++++--- interface/src/avatar/MyAvatar.h | 1 + libraries/avatars/src/AvatarData.cpp | 5 +++-- 5 files changed, 20 insertions(+), 24 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index b5b238b9d7..ca32adb6ba 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -50,7 +50,7 @@ Avatar::Avatar() : AvatarData(), _skeletonModel(this), _bodyYawDelta(0.0f), - _lastPosition(0.0f), + _lastPosition(_position), _velocity(0.0f), _lastVelocity(0.0f), _acceleration(0.0f), @@ -204,7 +204,9 @@ void Avatar::simulate(float deltaTime) { _displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01f ? _displayNameTargetAlpha : _displayNameAlpha; } - _position += _velocity * deltaTime; + // NOTE: we shouldn't extrapolate an Avatar instance forward in time... + // until velocity is in AvatarData update message. + //_position += _velocity * deltaTime; measureMotionDerivatives(deltaTime); } @@ -223,20 +225,6 @@ void Avatar::measureMotionDerivatives(float deltaTime) { _lastOrientation = getOrientation(); } -void Avatar::setPosition(const glm::vec3 position, bool overideReferential) { - AvatarData::setPosition(position, overideReferential); - _lastPosition = position; - _velocity = glm::vec3(0.0f); - _lastVelocity = glm::vec3(0.0f); -} - -void Avatar::slamPosition(const glm::vec3& newPosition) { - _position = newPosition; - _lastPosition = newPosition; - _velocity = glm::vec3(0.0f); - _lastVelocity = glm::vec3(0.0f); -} - void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { _mouseRayOrigin = origin; _mouseRayDirection = direction; diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 43b5150a48..b055e83491 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -161,9 +161,6 @@ public: /// \param vector position to be scaled. Will store the result void scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const; - void setPosition(const glm::vec3 position, bool overideReferential = false); - void slamPosition(const glm::vec3& newPosition); - public slots: void updateCollisionGroups(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 4b0e4eef5a..6472ba2efa 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -609,6 +609,13 @@ void MyAvatar::setGravity(const glm::vec3& gravity) { // so it continues to point opposite to the previous gravity setting. } +void MyAvatar::slamPosition(const glm::vec3& newPosition) { + AvatarData::setPosition(newPosition); + _lastPosition = _position; + _velocity = glm::vec3(0.0f); + _lastVelocity = glm::vec3(0.0f); +} + AnimationHandlePointer MyAvatar::addAnimationHandle() { AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); _animationHandles.append(handle); @@ -797,9 +804,11 @@ void MyAvatar::loadData(QSettings* settings) { getHead()->setBasePitch(loadSetting(settings, "headPitch", 0.0f)); - _position.x = loadSetting(settings, "position_x", START_LOCATION.x); - _position.y = loadSetting(settings, "position_y", START_LOCATION.y); - _position.z = loadSetting(settings, "position_z", START_LOCATION.z); + glm::vec3 newPosition; + newPosition.x = loadSetting(settings, "position_x", START_LOCATION.x); + newPosition.y = loadSetting(settings, "position_y", START_LOCATION.y); + newPosition.z = loadSetting(settings, "position_z", START_LOCATION.z); + slamPosition(newPosition); getHead()->setPupilDilation(loadSetting(settings, "pupilDilation", 0.0f)); diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index d7b955ce06..be828e0c91 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -57,6 +57,7 @@ public: void setLeanScale(float scale) { _leanScale = scale; } void setLocalGravity(glm::vec3 gravity); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } + void slamPosition(const glm::vec3& position); // getters float getLeanScale() const { return _leanScale; } diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 264d8ac580..200a6af6c7 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -35,7 +35,8 @@ using namespace std; AvatarData::AvatarData() : _sessionUUID(), - _handPosition(0,0,0), + _position(0.0f), + _handPosition(0.0f), _referential(NULL), _bodyYaw(-90.f), _bodyPitch(0.0f), @@ -326,7 +327,7 @@ int AvatarData::parseDataAtOffset(const QByteArray& packet, int offset) { } return maxAvailableSize; } - _position = position; + setPosition(position); // rotation (NOTE: This needs to become a quaternion to save two bytes) float yaw, pitch, roll; From dc396e5687120ef50ac3847d0cfecb8130c2fe95 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 13:36:02 -0700 Subject: [PATCH 25/35] Starting on bringing the overlay back to device-independent coordinates. --- interface/src/ui/ApplicationOverlay.cpp | 2 +- interface/src/ui/TextRenderer.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index ccb32e286a..60951dbaf1 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -99,7 +99,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { glPushMatrix(); glLoadIdentity(); - gluOrtho2D(0, glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), 0); + gluOrtho2D(0, glWidget->width(), glWidget->height(), 0); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index 3e5bde52a4..d6eaec9608 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -43,7 +43,7 @@ TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool i // double the font size for "Retina" displays float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); - if (ratio != 1.0f) { + if (ratio != 1.0f && false) { _font.setPointSize(_font.pointSize() * ratio); _metrics = QFontMetrics(_font); _effectThickness *= ratio; From 1ef91264824868e61a398a39fa160f3296a314fc Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 13:59:19 -0700 Subject: [PATCH 26/35] Migrating to device-independent coordinates. --- interface/src/Application.cpp | 43 ++++++---------- interface/src/Application.h | 2 - interface/src/Camera.cpp | 4 +- interface/src/GLCanvas.cpp | 8 --- interface/src/GLCanvas.h | 3 -- interface/src/devices/PrioVR.cpp | 4 +- interface/src/devices/SixenseManager.cpp | 6 +-- .../ControllerScriptingInterface.cpp | 2 +- interface/src/ui/ApplicationOverlay.cpp | 50 +++++++++---------- interface/src/ui/NodeBounds.cpp | 4 +- interface/src/ui/Stats.cpp | 12 ++--- 11 files changed, 57 insertions(+), 81 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5f446fcf2f..cd637a180f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1152,8 +1152,7 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { showMouse = false; } - QMouseEvent deviceEvent = getDeviceEvent(event, deviceID); - _controllerScriptingInterface.emitMouseMoveEvent(&deviceEvent, deviceID); // send events to any registered scripts + _controllerScriptingInterface.emitMouseMoveEvent(event, deviceID); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isMouseCaptured()) { @@ -1168,13 +1167,12 @@ void Application::mouseMoveEvent(QMouseEvent* event, unsigned int deviceID) { _seenMouseMove = true; } - _mouseX = deviceEvent.x(); - _mouseY = deviceEvent.y(); + _mouseX = event->x(); + _mouseY = event->y(); } void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { - QMouseEvent deviceEvent = getDeviceEvent(event, deviceID); - _controllerScriptingInterface.emitMousePressEvent(&deviceEvent); // send events to any registered scripts + _controllerScriptingInterface.emitMousePressEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isMouseCaptured()) { @@ -1184,8 +1182,8 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { if (event->button() == Qt::LeftButton) { - _mouseX = deviceEvent.x(); - _mouseY = deviceEvent.y(); + _mouseX = event->x(); + _mouseY = event->y(); _mouseDragStartedX = _mouseX; _mouseDragStartedY = _mouseY; _mousePressed = true; @@ -1207,8 +1205,7 @@ void Application::mousePressEvent(QMouseEvent* event, unsigned int deviceID) { } void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { - QMouseEvent deviceEvent = getDeviceEvent(event, deviceID); - _controllerScriptingInterface.emitMouseReleaseEvent(&deviceEvent); // send events to any registered scripts + _controllerScriptingInterface.emitMouseReleaseEvent(event); // send events to any registered scripts // if one of our scripts have asked to capture this event, then stop processing it if (_controllerScriptingInterface.isMouseCaptured()) { @@ -1217,8 +1214,8 @@ void Application::mouseReleaseEvent(QMouseEvent* event, unsigned int deviceID) { if (activeWindow() == _window) { if (event->button() == Qt::LeftButton) { - _mouseX = deviceEvent.x(); - _mouseY = deviceEvent.y(); + _mouseX = event->x(); + _mouseY = event->y(); _mousePressed = false; checkBandwidthMeterClick(); if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { @@ -1417,7 +1414,7 @@ void Application::checkBandwidthMeterClick() { if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth) && glm::compMax(glm::abs(glm::ivec2(_mouseX - _mouseDragStartedX, _mouseY - _mouseDragStartedY))) <= BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH - && _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->getDeviceWidth(), _glWidget->getDeviceHeight())) { + && _bandwidthMeter.isWithinArea(_mouseX, _mouseY, _glWidget->width(), _glWidget->height())) { // The bandwidth meter is visible, the click didn't get dragged too far and // we actually hit the bandwidth meter @@ -1735,8 +1732,8 @@ void Application::init() { _voxelShader.init(); _pointShader.init(); - _mouseX = _glWidget->getDeviceWidth() / 2; - _mouseY = _glWidget->getDeviceHeight() / 2; + _mouseX = _glWidget->width() / 2; + _mouseY = _glWidget->height() / 2; QCursor::setPos(_mouseX, _mouseY); // TODO: move _myAvatar out of Application. Move relevant code to MyAvataar or AvatarManager @@ -1891,8 +1888,8 @@ void Application::updateMouseRay() { // if the mouse pointer isn't visible, act like it's at the center of the screen float x = 0.5f, y = 0.5f; if (!_mouseHidden) { - x = _mouseX / (float)_glWidget->getDeviceWidth(); - y = _mouseY / (float)_glWidget->getDeviceHeight(); + x = _mouseX / (float)_glWidget->width(); + y = _mouseY / (float)_glWidget->height(); } _viewFrustum.computePickRay(x, y, _mouseRayOrigin, _mouseRayDirection); @@ -2332,14 +2329,6 @@ int Application::sendNackPackets() { return packetsSent; } -QMouseEvent Application::getDeviceEvent(QMouseEvent* event, unsigned int deviceID) { - if (deviceID > 0) { - return *event; - } - return QMouseEvent(event->type(), QPointF(_glWidget->getDeviceX(event->x()), _glWidget->getDeviceY(event->y())), - event->windowPos(), event->screenPos(), event->button(), event->buttons(), event->modifiers()); -} - void Application::queryOctree(NodeType_t serverType, PacketType packetType, NodeToJurisdictionMap& jurisdictions) { //qDebug() << ">>> inside... queryOctree()... _viewFrustum.getFieldOfView()=" << _viewFrustum.getFieldOfView(); @@ -3291,8 +3280,8 @@ void Application::deleteVoxelAt(const VoxelDetail& voxel) { void Application::resetSensors() { - _mouseX = _glWidget->getDeviceWidth() / 2; - _mouseY = _glWidget->getDeviceHeight() / 2; + _mouseX = _glWidget->width() / 2; + _mouseY = _glWidget->height() / 2; _faceplus.reset(); _faceshift.reset(); diff --git a/interface/src/Application.h b/interface/src/Application.h index f46eef881c..f48d88d7a4 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -436,8 +436,6 @@ private: int sendNackPackets(); - QMouseEvent getDeviceEvent(QMouseEvent* event, unsigned int deviceID); - MainWindow* _window; GLCanvas* _glWidget; // our GLCanvas has a couple extra features diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index c4df0f7f2a..4a924b4ec3 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -262,8 +262,8 @@ CameraScriptableObject::CameraScriptableObject(Camera* camera, ViewFrustum* view } PickRay CameraScriptableObject::computePickRay(float x, float y) { - float screenWidth = Application::getInstance()->getGLWidget()->getDeviceWidth(); - float screenHeight = Application::getInstance()->getGLWidget()->getDeviceHeight(); + float screenWidth = Application::getInstance()->getGLWidget()->width(); + float screenHeight = Application::getInstance()->getGLWidget()->height(); PickRay result; if (OculusManager::isConnected()) { result.origin = _camera->getPosition(); diff --git a/interface/src/GLCanvas.cpp b/interface/src/GLCanvas.cpp index e63e79f1f0..108b9ba829 100644 --- a/interface/src/GLCanvas.cpp +++ b/interface/src/GLCanvas.cpp @@ -43,14 +43,6 @@ int GLCanvas::getDeviceHeight() const { return height() * (windowHandle() ? windowHandle()->devicePixelRatio() : 1.0f); } -int GLCanvas::getDeviceX(int x) const { - return x * getDeviceWidth() / width(); -} - -int GLCanvas::getDeviceY(int y) const { - return y * getDeviceHeight() / height(); -} - void GLCanvas::initializeGL() { Application::getInstance()->initializeGL(); setAttribute(Qt::WA_AcceptTouchEvents); diff --git a/interface/src/GLCanvas.h b/interface/src/GLCanvas.h index 22cdaae75f..0d381fa0bf 100644 --- a/interface/src/GLCanvas.h +++ b/interface/src/GLCanvas.h @@ -26,9 +26,6 @@ public: int getDeviceHeight() const; QSize getDeviceSize() const { return QSize(getDeviceWidth(), getDeviceHeight()); } - int getDeviceX(int x) const; - int getDeviceY(int y) const; - protected: QTimer _frameTimer; diff --git a/interface/src/devices/PrioVR.cpp b/interface/src/devices/PrioVR.cpp index b4a11231ed..d6c74e4a5d 100644 --- a/interface/src/devices/PrioVR.cpp +++ b/interface/src/devices/PrioVR.cpp @@ -209,8 +209,8 @@ void PrioVR::renderCalibrationCountdown() { } static TextRenderer textRenderer(MONO_FONT_FAMILY, 18, QFont::Bold, false, TextRenderer::OUTLINE_EFFECT, 2); QByteArray text = "Assume T-Pose in " + QByteArray::number(secondsRemaining) + "..."; - textRenderer.draw((Application::getInstance()->getGLWidget()->getDeviceWidth() - - textRenderer.computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->getDeviceHeight() / 2, + textRenderer.draw((Application::getInstance()->getGLWidget()->width() - + textRenderer.computeWidth(text.constData())) / 2, Application::getInstance()->getGLWidget()->height() / 2, text); #endif } diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index 86c4b17cb2..417b0619f8 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -396,10 +396,10 @@ void SixenseManager::emulateMouse(PalmData* palm, int index) { float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = widget->getDeviceWidth() * getCursorPixelRangeMult(); + float cursorRange = widget->width() * getCursorPixelRangeMult(); - pos.setX(widget->getDeviceWidth() / 2.0f + cursorRange * xAngle); - pos.setY(widget->getDeviceHeight() / 2.0f + cursorRange * yAngle); + pos.setX(widget->width() / 2.0f + cursorRange * xAngle); + pos.setY(widget->height() / 2.0f + cursorRange * yAngle); } diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 0ebcfea987..b58568c365 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -257,7 +257,7 @@ void ControllerScriptingInterface::releaseJoystick(int joystickIndex) { glm::vec2 ControllerScriptingInterface::getViewportDimensions() const { GLCanvas* widget = Application::getInstance()->getGLWidget(); - return glm::vec2(widget->getDeviceWidth(), widget->getDeviceHeight()); + return glm::vec2(widget->width(), widget->height()); } AbstractInputController* ControllerScriptingInterface::createInputController(const QString& deviceName, const QString& tracker) { diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 60951dbaf1..20ed1d9d58 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -106,7 +106,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { renderAudioMeter(); if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)) { - myAvatar->renderHeadMouse(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); + myAvatar->renderHeadMouse(glWidget->width(), glWidget->height()); } renderStatsAndLogs(); @@ -305,8 +305,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { float u = asin(collisionPos.x) / (_textureFov)+0.5f; float v = 1.0 - (asin(collisionPos.y) / (_textureFov)+0.5f); - rv.setX(u * glWidget->getDeviceWidth()); - rv.setY(v * glWidget->getDeviceHeight()); + rv.setX(u * glWidget->width()); + rv.setY(v * glWidget->height()); } } else { //if they did not click on the overlay, just set the coords to INT_MAX @@ -323,8 +323,8 @@ QPoint ApplicationOverlay::getPalmClickLocation(const PalmData *palm) const { ndcSpacePos = glm::vec3(clipSpacePos) / clipSpacePos.w; } - rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * glWidget->getDeviceWidth()); - rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->getDeviceHeight()); + rv.setX(((ndcSpacePos.x + 1.0) / 2.0) * glWidget->width()); + rv.setY((1.0 - ((ndcSpacePos.y + 1.0) / 2.0)) * glWidget->height()); } return rv; } @@ -496,11 +496,11 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as //draw the mouse pointer glBindTexture(GL_TEXTURE_2D, _crosshairTexture); - const float reticleSize = 40.0f / application->getGLWidget()->getDeviceWidth() * quadWidth; + const float reticleSize = 40.0f / application->getGLWidget()->width() * quadWidth; x -= reticleSize / 2.0f; y += reticleSize / 2.0f; - const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->getDeviceWidth()) * quadWidth; - const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->getDeviceHeight())) * quadHeight; + const float mouseX = (application->getMouseX() / (float)application->getGLWidget()->width()) * quadWidth; + const float mouseY = (1.0 - (application->getMouseY() / (float)application->getGLWidget()->height())) * quadHeight; glBegin(GL_QUADS); @@ -671,14 +671,14 @@ void ApplicationOverlay::renderControllerPointers() { float yAngle = 0.5f - ((atan2(direction.z, direction.y) + M_PI_2)); // Get the pixel range over which the xAngle and yAngle are scaled - float cursorRange = glWidget->getDeviceWidth() * application->getSixenseManager()->getCursorPixelRangeMult(); + float cursorRange = glWidget->width() * application->getSixenseManager()->getCursorPixelRangeMult(); - mouseX = (glWidget->getDeviceWidth() / 2.0f + cursorRange * xAngle); - mouseY = (glWidget->getDeviceHeight() / 2.0f + cursorRange * yAngle); + mouseX = (glWidget->width() / 2.0f + cursorRange * xAngle); + mouseY = (glWidget->height() / 2.0f + cursorRange * yAngle); } //If the cursor is out of the screen then don't render it - if (mouseX < 0 || mouseX >= glWidget->getDeviceWidth() || mouseY < 0 || mouseY >= glWidget->getDeviceHeight()) { + if (mouseX < 0 || mouseX >= glWidget->width() || mouseY < 0 || mouseY >= glWidget->height()) { _reticleActive[index] = false; continue; } @@ -709,8 +709,8 @@ void ApplicationOverlay::renderPointersOculus(const glm::vec3& eyePos) { GLCanvas* glWidget = application->getGLWidget(); glm::vec3 cursorVerts[4]; - const int widgetWidth = glWidget->getDeviceWidth(); - const int widgetHeight = glWidget->getDeviceHeight(); + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); const float reticleSize = 50.0f; @@ -850,8 +850,8 @@ void ApplicationOverlay::renderMagnifier(int mouseX, int mouseY, float sizeMult, Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); - const int widgetWidth = glWidget->getDeviceWidth(); - const int widgetHeight = glWidget->getDeviceHeight(); + const int widgetWidth = glWidget->width(); + const int widgetHeight = glWidget->height(); const float magnifyWidth = MAGNIFY_WIDTH * sizeMult; const float magnifyHeight = MAGNIFY_HEIGHT * sizeMult; @@ -968,7 +968,7 @@ void ApplicationOverlay::renderAudioMeter() { float collisionSoundMagnitude = audio->getCollisionSoundMagnitude(); const float VISIBLE_COLLISION_SOUND_MAGNITUDE = 0.5f; if (collisionSoundMagnitude > VISIBLE_COLLISION_SOUND_MAGNITUDE) { - renderCollisionOverlay(glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), + renderCollisionOverlay(glWidget->width(), glWidget->height(), audio->getCollisionSoundMagnitude()); } } @@ -1019,16 +1019,16 @@ void ApplicationOverlay::renderAudioMeter() { if ((audio->getTimeSinceLastClip() > 0.f) && (audio->getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) { const float MAX_MAGNITUDE = 0.7f; float magnitude = MAX_MAGNITUDE * (1 - audio->getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME); - renderCollisionOverlay(glWidget->getDeviceWidth(), glWidget->getDeviceHeight(), magnitude, 1.0f); + renderCollisionOverlay(glWidget->width(), glWidget->height(), magnitude, 1.0f); } audio->renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP, audioMeterY, Menu::getInstance()->isOptionChecked(MenuOption::Mirror)); - audio->renderScope(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); + audio->renderScope(glWidget->width(), glWidget->height()); - audio->renderStats(WHITE_TEXT, glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); + audio->renderStats(WHITE_TEXT, glWidget->width(), glWidget->height()); glBegin(GL_QUADS); if (isClipping) { @@ -1108,8 +1108,8 @@ void ApplicationOverlay::renderStatsAndLogs() { application->getPacketsPerSecond(), application->getBytesPerSecond(), voxelPacketsToProcess); // Bandwidth meter if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) { - Stats::drawBackground(0x33333399, glWidget->getDeviceWidth() - 296, glWidget->getDeviceHeight() - 68, 296, 68); - bandwidthMeter->render(glWidget->getDeviceWidth(), glWidget->getDeviceHeight()); + Stats::drawBackground(0x33333399, glWidget->width() - 296, glWidget->height() - 68, 296, 68); + bandwidthMeter->render(glWidget->width(), glWidget->height()); } } @@ -1122,7 +1122,7 @@ void ApplicationOverlay::renderStatsAndLogs() { (Menu::getInstance()->isOptionChecked(MenuOption::Stats) && Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) ? 80 : 20; - drawText(glWidget->getDeviceWidth() - 100, glWidget->getDeviceHeight() - timerBottom, + drawText(glWidget->width() - 100, glWidget->height() - timerBottom, 0.30f, 0.0f, 0, frameTimer, WHITE_TEXT); } nodeBoundsDisplay.drawOverlay(); @@ -1247,8 +1247,8 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder() { if (nodeList && !nodeList->getDomainHandler().isConnected()) { GLCanvas* glWidget = Application::getInstance()->getGLWidget(); - int right = glWidget->getDeviceWidth(); - int bottom = glWidget->getDeviceHeight(); + int right = glWidget->width(); + int bottom = glWidget->height(); glColor3f(CONNECTION_STATUS_BORDER_COLOR[0], CONNECTION_STATUS_BORDER_COLOR[1], diff --git a/interface/src/ui/NodeBounds.cpp b/interface/src/ui/NodeBounds.cpp index a17aed6c42..e3bd3a5cc3 100644 --- a/interface/src/ui/NodeBounds.cpp +++ b/interface/src/ui/NodeBounds.cpp @@ -41,8 +41,8 @@ void NodeBounds::draw() { // itself after the cursor disappears. Application* application = Application::getInstance(); GLCanvas* glWidget = application->getGLWidget(); - float mouseX = application->getMouseX() / (float)glWidget->getDeviceWidth(); - float mouseY = application->getMouseY() / (float)glWidget->getDeviceHeight(); + float mouseX = application->getMouseX() / (float)glWidget->width(); + float mouseY = application->getMouseY() / (float)glWidget->height(); glm::vec3 mouseRayOrigin; glm::vec3 mouseRayDirection; application->getViewFrustum()->computePickRay(mouseX, mouseY, mouseRayOrigin, mouseRayDirection); diff --git a/interface/src/ui/Stats.cpp b/interface/src/ui/Stats.cpp index 76a803e2b8..6b7d499bf9 100644 --- a/interface/src/ui/Stats.cpp +++ b/interface/src/ui/Stats.cpp @@ -57,7 +57,7 @@ Stats::Stats(): _metavoxelReceiveTotal(0) { GLCanvas* glWidget = Application::getInstance()->getGLWidget(); - resetWidth(glWidget->getDeviceWidth(), 0); + resetWidth(glWidget->width(), 0); } void Stats::toggleExpanded() { @@ -114,7 +114,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD // top-right stats click lines = _expanded ? 11 : 3; statsHeight = lines * STATS_PELS_PER_LINE + 10; - statsWidth = glWidget->getDeviceWidth() - statsX; + statsWidth = glWidget->width() - statsX; if (mouseX > statsX && mouseX < statsX + statsWidth && mouseY > statsY && mouseY < statsY + statsHeight) { toggleExpanded(); return; @@ -123,7 +123,7 @@ void Stats::checkClick(int mouseX, int mouseY, int mouseDragStartedX, int mouseD void Stats::resetWidth(int width, int horizontalOffset) { GLCanvas* glWidget = Application::getInstance()->getGLWidget(); - int extraSpace = glWidget->getDeviceWidth() - horizontalOffset -2 + int extraSpace = glWidget->width() - horizontalOffset -2 - STATS_GENERAL_MIN_WIDTH - (Menu::getInstance()->isOptionChecked(MenuOption::TestPing) ? STATS_PING_MIN_WIDTH -1 : 0) - STATS_GEO_MIN_WIDTH @@ -147,7 +147,7 @@ void Stats::resetWidth(int width, int horizontalOffset) { _pingStatsWidth += (int) extraSpace / panels; } _geoStatsWidth += (int) extraSpace / panels; - _voxelStatsWidth += glWidget->getDeviceWidth() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); + _voxelStatsWidth += glWidget->width() - (_generalStatsWidth + _pingStatsWidth + _geoStatsWidth + 3); } } @@ -210,7 +210,7 @@ void Stats::display( std::stringstream voxelStats; if (_lastHorizontalOffset != horizontalOffset) { - resetWidth(glWidget->getDeviceWidth(), horizontalOffset); + resetWidth(glWidget->width(), horizontalOffset); _lastHorizontalOffset = horizontalOffset; } @@ -410,7 +410,7 @@ void Stats::display( } } - drawBackground(backgroundColor, horizontalOffset, 0, glWidget->getDeviceWidth() - horizontalOffset, + drawBackground(backgroundColor, horizontalOffset, 0, glWidget->width() - horizontalOffset, lines * STATS_PELS_PER_LINE + 10); horizontalOffset += 5; From 5a6f8015f66df4d2013ad85f412466e062140584 Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 8 Sep 2014 14:05:47 -0700 Subject: [PATCH 27/35] unroll audio gain rendering loop --- libraries/audio/src/AudioGain.h | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioGain.h b/libraries/audio/src/AudioGain.h index c2cc64cba5..c3fa299b02 100644 --- a/libraries/audio/src/AudioGain.h +++ b/libraries/audio/src/AudioGain.h @@ -56,7 +56,7 @@ public: float32_t** samples = frameBuffer.getFrameData(); for (uint16_t j = 0; j < frameBuffer.getChannelCount(); ++j) { - for (uint16_t i = 0; i < frameBuffer.getFrameCount(); i += 8) { + for (uint16_t i = 0; i < frameBuffer.getFrameCount(); i += 32) { samples[j][i + 0] *= _gain; samples[j][i + 1] *= _gain; samples[j][i + 2] *= _gain; @@ -65,6 +65,30 @@ public: samples[j][i + 5] *= _gain; samples[j][i + 6] *= _gain; samples[j][i + 7] *= _gain; + samples[j][i + 8] *= _gain; + samples[j][i + 9] *= _gain; + samples[j][i + 10] *= _gain; + samples[j][i + 11] *= _gain; + samples[j][i + 12] *= _gain; + samples[j][i + 13] *= _gain; + samples[j][i + 14] *= _gain; + samples[j][i + 15] *= _gain; + samples[j][i + 16] *= _gain; + samples[j][i + 17] *= _gain; + samples[j][i + 18] *= _gain; + samples[j][i + 19] *= _gain; + samples[j][i + 20] *= _gain; + samples[j][i + 21] *= _gain; + samples[j][i + 22] *= _gain; + samples[j][i + 23] *= _gain; + samples[j][i + 24] *= _gain; + samples[j][i + 25] *= _gain; + samples[j][i + 26] *= _gain; + samples[j][i + 27] *= _gain; + samples[j][i + 28] *= _gain; + samples[j][i + 29] *= _gain; + samples[j][i + 30] *= _gain; + samples[j][i + 31] *= _gain; } } } From e9964c71c9bd65f6c9118252c302421b1f792b69 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 14:13:28 -0700 Subject: [PATCH 28/35] Fix for rear view mirror. --- interface/src/Application.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index cd637a180f..2f3c67ea36 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -3030,8 +3031,15 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { _mirrorCamera.update(1.0f/_fps); // set the bounds of rear mirror view - glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); - glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); + if (billboard) { + glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); + glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); + } else { + float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); + int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; + glViewport(x, _glWidget->getDeviceHeight() - y - height, width, height); + glScissor(x, _glWidget->getDeviceHeight() - y - height, width, height); + } bool updateViewFrustum = false; updateProjectionMatrix(_mirrorCamera, updateViewFrustum); glEnable(GL_SCISSOR_TEST); From 04eca22a5029cdd8cc31daccfb778efc6557ae7b Mon Sep 17 00:00:00 2001 From: Craig Hansen-Sturm Date: Mon, 8 Sep 2014 14:28:53 -0700 Subject: [PATCH 29/35] allocate 4x initial input buffer size --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 0d114b7208..83b3ff299d 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -431,7 +431,7 @@ void Audio::start() { qDebug() << "Unable to set up audio output because of a problem with output format."; } - _inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 2 ); + _inputFrameBuffer.initialize( _inputFormat.channelCount(), _audioInput->bufferSize() * 4 ); _peq.initialize( _inputFormat.sampleRate() ); _inputGain.initialize(); _sourceGain.initialize(); From 5dfa22f3fde991a9f0ee2f225d938194baea788c Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 15:11:25 -0700 Subject: [PATCH 30/35] Adjusting font sizes. --- interface/src/ui/TextRenderer.cpp | 39 +++++++++++++++++-------------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/interface/src/ui/TextRenderer.cpp b/interface/src/ui/TextRenderer.cpp index d6eaec9608..4ced8c1f2e 100644 --- a/interface/src/ui/TextRenderer.cpp +++ b/interface/src/ui/TextRenderer.cpp @@ -40,14 +40,6 @@ TextRenderer::TextRenderer(const char* family, int pointSize, int weight, bool i _color(color) { _font.setKerning(false); - - // double the font size for "Retina" displays - float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); - if (ratio != 1.0f && false) { - _font.setPointSize(_font.pointSize() * ratio); - _metrics = QFontMetrics(_font); - _effectThickness *= ratio; - } } TextRenderer::~TextRenderer() { @@ -91,7 +83,7 @@ int TextRenderer::draw(int x, int y, const char* str) { int bottom = y + glyph.bounds().y(); int top = y + glyph.bounds().y() + glyph.bounds().height(); - float scale = 1.0 / IMAGE_SIZE; + float scale = QApplication::desktop()->windowHandle()->devicePixelRatio() / IMAGE_SIZE; float ls = glyph.location().x() * scale; float rs = (glyph.location().x() + glyph.bounds().width()) * scale; float bt = glyph.location().y() * scale; @@ -137,21 +129,25 @@ const Glyph& TextRenderer::getGlyph(char c) { } // we use 'J' as a representative size for the solid block character QChar ch = (c == SOLID_BLOCK_CHAR) ? QChar('J') : QChar(c); - QRect bounds = _metrics.boundingRect(ch); - if (bounds.isEmpty()) { + QRect baseBounds = _metrics.boundingRect(ch); + if (baseBounds.isEmpty()) { 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); + baseBounds.adjust(-_effectThickness, 0, 0, _effectThickness); } else if (_effectType == OUTLINE_EFFECT) { - bounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness); + baseBounds.adjust(-_effectThickness, -_effectThickness, _effectThickness, _effectThickness); } // grow the bounds to account for antialiasing - bounds.adjust(-1, -1, 1, 1); + baseBounds.adjust(-1, -1, 1, 1); + + // adjust bounds for device pixel scaling + float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); + QRect bounds(baseBounds.x() * ratio, baseBounds.y() * ratio, baseBounds.width() * ratio, baseBounds.height() * ratio); if (_x + bounds.width() > IMAGE_SIZE) { // we can't fit it on the current row; move to next @@ -180,9 +176,16 @@ const Glyph& TextRenderer::getGlyph(char c) { } else { image.fill(0); QPainter painter(&image); - painter.setFont(_font); + QFont font = _font; + if (ratio == 1.0f) { + painter.setFont(_font); + } else { + QFont enlargedFont = _font; + enlargedFont.setPointSize(_font.pointSize() * ratio); + painter.setFont(enlargedFont); + } if (_effectType == SHADOW_EFFECT) { - for (int i = 0; i < _effectThickness; i++) { + for (int i = 0; i < _effectThickness * ratio; i++) { painter.drawText(-bounds.x() - 1 - i, -bounds.y() + 1 + i, ch); } } else if (_effectType == OUTLINE_EFFECT) { @@ -191,7 +194,7 @@ const Glyph& TextRenderer::getGlyph(char c) { font.setStyleStrategy(QFont::ForceOutline); path.addText(-bounds.x() - 0.5, -bounds.y() + 0.5, font, ch); QPen pen; - pen.setWidth(_effectThickness); + pen.setWidth(_effectThickness * ratio); pen.setJoinStyle(Qt::RoundJoin); pen.setCapStyle(Qt::RoundCap); painter.setPen(pen); @@ -203,7 +206,7 @@ const Glyph& TextRenderer::getGlyph(char c) { } glTexSubImage2D(GL_TEXTURE_2D, 0, _x, _y, bounds.width(), bounds.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.constBits()); - glyph = Glyph(_currentTextureID, QPoint(_x, _y), bounds, _metrics.width(ch)); + glyph = Glyph(_currentTextureID, QPoint(_x / ratio, _y / ratio), baseBounds, _metrics.width(ch)); _x += bounds.width(); _rowHeight = qMax(_rowHeight, bounds.height()); From f2535d4df84be4730c229135f608517088d59c93 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 15:23:08 -0700 Subject: [PATCH 31/35] Adjust avatar names for device pixel ratio. --- interface/src/avatar/Avatar.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ca32adb6ba..ea18193e2b 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -11,6 +11,9 @@ #include +#include +#include + #include #include #include @@ -864,6 +867,13 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { void Avatar::setDisplayName(const QString& displayName) { AvatarData::setDisplayName(displayName); _displayNameBoundingRect = textRenderer(DISPLAYNAME)->metrics().tightBoundingRect(displayName); + + // adjust for device pixel ratio + float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); + if (ratio != 1.0f) { + _displayNameBoundingRect = QRect(_displayNameBoundingRect.x() * ratio, _displayNameBoundingRect.y() * ratio, + _displayNameBoundingRect.width() * ratio, _displayNameBoundingRect.height() * ratio); + } } void Avatar::setBillboard(const QByteArray& billboard) { From 6fc1c2540cb47520bc63748575df39fd1641103a Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 8 Sep 2014 15:24:02 -0700 Subject: [PATCH 32/35] fix residual velocity on teleport --- interface/src/location/LocationManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/location/LocationManager.cpp b/interface/src/location/LocationManager.cpp index 551e08a8bc..67e1b899ee 100644 --- a/interface/src/location/LocationManager.cpp +++ b/interface/src/location/LocationManager.cpp @@ -205,7 +205,7 @@ bool LocationManager::goToDestination(QString destination) { MyAvatar::sendKillAvatar(); qDebug("Going To Location: %f, %f, %f...", x, y, z); - myAvatar->setPosition(newAvatarPos); + myAvatar->slamPosition(newAvatarPos); emit myAvatar->transformChanged(); } From f69324f2703e6e01edb1fb6d06673aaf1281c3af Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 15:29:36 -0700 Subject: [PATCH 33/35] Fix for display name. --- interface/src/avatar/Avatar.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index ea18193e2b..5c7e89fc37 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -658,7 +658,8 @@ void Avatar::renderDisplayName() { if (success) { double textWindowHeight = abs(result1[1] - result0[1]); - float scaleFactor = (textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f; + float scaleFactor = QApplication::desktop()->windowHandle()->devicePixelRatio() * + ((textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f); glScalef(scaleFactor, scaleFactor, 1.0); glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis @@ -867,13 +868,6 @@ void Avatar::setAttachmentData(const QVector& attachmentData) { void Avatar::setDisplayName(const QString& displayName) { AvatarData::setDisplayName(displayName); _displayNameBoundingRect = textRenderer(DISPLAYNAME)->metrics().tightBoundingRect(displayName); - - // adjust for device pixel ratio - float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); - if (ratio != 1.0f) { - _displayNameBoundingRect = QRect(_displayNameBoundingRect.x() * ratio, _displayNameBoundingRect.y() * ratio, - _displayNameBoundingRect.width() * ratio, _displayNameBoundingRect.height() * ratio); - } } void Avatar::setBillboard(const QByteArray& billboard) { From a9eb35448aae914f9da7bede00021a1224fec28d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 15:39:20 -0700 Subject: [PATCH 34/35] Comment fix. --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 2f3c67ea36..7c7c455d1d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3035,6 +3035,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { glViewport(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); glScissor(region.x(), _glWidget->getDeviceHeight() - region.y() - region.height(), region.width(), region.height()); } else { + // if not rendering the billboard, the region is in device independent coordinates; must convert to device float ratio = QApplication::desktop()->windowHandle()->devicePixelRatio(); int x = region.x() * ratio, y = region.y() * ratio, width = region.width() * ratio, height = region.height() * ratio; glViewport(x, _glWidget->getDeviceHeight() - y - height, width, height); From a777566b0153b30397180db65a46a288446c67b4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 8 Sep 2014 18:50:30 -0700 Subject: [PATCH 35/35] Support for loading (16-bit, unsigned, little-endian, square) raw depth maps with configurable offset/scale (defaults to normalized). --- interface/src/ui/MetavoxelEditor.cpp | 87 ++++++++++++++++++++++++++-- interface/src/ui/MetavoxelEditor.h | 7 +++ 2 files changed, 90 insertions(+), 4 deletions(-) diff --git a/interface/src/ui/MetavoxelEditor.cpp b/interface/src/ui/MetavoxelEditor.cpp index 1b0fc227aa..cf839f6800 100644 --- a/interface/src/ui/MetavoxelEditor.cpp +++ b/interface/src/ui/MetavoxelEditor.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include + // include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL #include "InterfaceConfig.h" @@ -37,6 +39,8 @@ #include "Application.h" #include "MetavoxelEditor.h" +using namespace std; + enum GridPlane { GRID_PLANE_XY, GRID_PLANE_XZ, GRID_PLANE_YZ }; @@ -959,7 +963,8 @@ void HeightfieldTool::render() { } ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : - HeightfieldTool(editor, "Import Heightfield") { + HeightfieldTool(editor, "Import Heightfield"), + _loadingImage(false) { _form->addRow("Block Size:", _blockSize = new QSpinBox()); _blockSize->setPrefix("2^"); @@ -970,6 +975,32 @@ ImportHeightfieldTool::ImportHeightfieldTool(MetavoxelEditor* editor) : &ImportHeightfieldTool::updatePreview); _form->addRow("Height:", _height = new QPushButton()); connect(_height, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectHeightFile); + + _form->addRow(_rawOptions = new QWidget()); + QHBoxLayout* rawLayout = new QHBoxLayout(); + _rawOptions->setLayout(rawLayout); + _rawOptions->setVisible(false); + + rawLayout->addStretch(1); + rawLayout->addWidget(new QLabel("Scale:")); + rawLayout->addWidget(_heightScale = new QDoubleSpinBox()); + const double MAX_OFFSET_SCALE = 100000.0; + _heightScale->setMaximum(MAX_OFFSET_SCALE); + _heightScale->setSingleStep(0.0001); + _heightScale->setDecimals(4); + _heightScale->setValue(1.0); + connect(_heightScale, static_cast(&QDoubleSpinBox::valueChanged), this, + &ImportHeightfieldTool::updateHeightImage); + + rawLayout->addSpacing(15); + rawLayout->addWidget(new QLabel("Offset:")); + rawLayout->addWidget(_heightOffset = new QDoubleSpinBox()); + _heightOffset->setMinimum(-MAX_OFFSET_SCALE); + _heightOffset->setMaximum(MAX_OFFSET_SCALE); + _heightOffset->setDecimals(4); + connect(_heightOffset, static_cast(&QDoubleSpinBox::valueChanged), this, + &ImportHeightfieldTool::updateHeightImage); + _form->addRow("Color:", _color = new QPushButton()); connect(_color, &QAbstractButton::clicked, this, &ImportHeightfieldTool::selectColorFile); @@ -1012,22 +1043,50 @@ void ImportHeightfieldTool::apply() { } } +const float EIGHT_BIT_MAXIMUM = 255.0f; + void ImportHeightfieldTool::selectHeightFile() { - QString filename = QFileDialog::getOpenFileName(this, "Select Height Image", QString(), "Images (*.png *.jpg)"); + QString filename = QFileDialog::getOpenFileName(this, "Select Height Image", QString(), + "Images (*.png *.jpg *.bmp *.raw)"); if (filename.isNull()) { return; } + if (filename.toLower().endsWith(".raw")) { + QFile input(filename); + input.open(QIODevice::ReadOnly); + QDataStream in(&input); + in.setByteOrder(QDataStream::LittleEndian); + _rawHeight.clear(); + int minHeight = numeric_limits::max(); + int maxHeight = numeric_limits::min(); + while (!in.atEnd()) { + quint16 height; + in >> height; + _rawHeight.append(height); + minHeight = qMin(minHeight, (int)height); + maxHeight = qMax(maxHeight, (int)height); + } + _height->setText(filename); + _rawOptions->setVisible(true); + _loadingImage = true; + _heightScale->setValue((EIGHT_BIT_MAXIMUM - 1.0f) / (maxHeight - minHeight)); + _heightOffset->setValue(-minHeight * _heightScale->value() + 1.0); + _loadingImage = false; + updateHeightImage(); + return; + } if (!_heightImage.load(filename)) { QMessageBox::warning(this, "Invalid Image", "The selected image could not be read."); return; } + _rawOptions->setVisible(false); _heightImage = _heightImage.convertToFormat(QImage::Format_RGB888); _height->setText(filename); updatePreview(); } void ImportHeightfieldTool::selectColorFile() { - QString filename = QFileDialog::getOpenFileName(this, "Select Color Image", QString(), "Images (*.png *.jpg)"); + QString filename = QFileDialog::getOpenFileName(this, "Select Color Image", QString(), "Images (*.png *.jpg *.bmp)"); if (filename.isNull()) { return; } @@ -1040,6 +1099,26 @@ void ImportHeightfieldTool::selectColorFile() { updatePreview(); } +void ImportHeightfieldTool::updateHeightImage() { + if (_loadingImage) { + return; + } + int size = glm::sqrt(_rawHeight.size()); + _heightImage = QImage(size, size, QImage::Format_RGB888); + const quint16* src = _rawHeight.constData(); + float scale = _heightScale->value(), offset = _heightOffset->value(); + for (int y = 0; y < size; y++) { + uchar* dest = _heightImage.scanLine(y); + for (const quint16* end = src + size; src != end; src++) { + uchar height = glm::clamp(*src * scale + offset, 1.0f, EIGHT_BIT_MAXIMUM); + *dest++ = height; + *dest++ = height; + *dest++ = height; + } + } + updatePreview(); +} + void ImportHeightfieldTool::updatePreview() { QVector buffers; if (_heightImage.width() > 0 && _heightImage.height() > 0) { @@ -1061,7 +1140,7 @@ void ImportHeightfieldTool::updatePreview() { uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * DataBlock::COLOR_BYTES; char* dest = height.data() + (y + offsetY) * heightSize + offsetX; for (int x = 0; x < columns; x++) { - *dest++ = *src; + *dest++ = qMax((uchar)1, *src); src += DataBlock::COLOR_BYTES; } } diff --git a/interface/src/ui/MetavoxelEditor.h b/interface/src/ui/MetavoxelEditor.h index 447d2197cd..b5adab4193 100644 --- a/interface/src/ui/MetavoxelEditor.h +++ b/interface/src/ui/MetavoxelEditor.h @@ -291,6 +291,7 @@ private slots: void selectHeightFile(); void selectColorFile(); + void updateHeightImage(); void updatePreview(); void renderPreview(); @@ -299,8 +300,14 @@ private: QSpinBox* _blockSize; QPushButton* _height; + QWidget* _rawOptions; + QDoubleSpinBox* _heightScale; + QDoubleSpinBox* _heightOffset; + bool _loadingImage; + QPushButton* _color; + QVector _rawHeight; QImage _heightImage; QImage _colorImage;