diff --git a/assignment-client/src/audio/AudioMixer.cpp b/assignment-client/src/audio/AudioMixer.cpp index d96fce450a..2dc51b44a0 100644 --- a/assignment-client/src/audio/AudioMixer.cpp +++ b/assignment-client/src/audio/AudioMixer.cpp @@ -33,7 +33,10 @@ #include #include +#include +#include #include +#include #include #include @@ -71,11 +74,18 @@ AudioMixer::AudioMixer(const QByteArray& packet) : _performanceThrottlingRatio(0.0f), _numStatFrames(0), _sumListeners(0), - _sumMixes(0) + _sumMixes(0), + _sourceUnattenuatedZone(NULL), + _listenerUnattenuatedZone(NULL) { } +AudioMixer::~AudioMixer() { + delete _sourceUnattenuatedZone; + delete _listenerUnattenuatedZone; +} + void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, AvatarAudioRingBuffer* listeningNodeBuffer) { float bearingRelativeAngleToSource = 0.0f; @@ -83,7 +93,9 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf int numSamplesDelay = 0; float weakChannelAmplitudeRatio = 1.0f; - if (bufferToAdd != listeningNodeBuffer) { + bool shouldAttenuate = (bufferToAdd != listeningNodeBuffer); + + if (shouldAttenuate) { // if the two buffer pointers do not match then these are different buffers glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); @@ -101,82 +113,88 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf ++_sumMixes; - glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); - - float distanceSquareToSource = glm::dot(relativePosition, relativePosition); - float radius = 0.0f; - - if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) { - InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd; - radius = injectedBuffer->getRadius(); - attenuationCoefficient *= injectedBuffer->getAttenuationRatio(); + if (bufferToAdd->getListenerUnattenuatedZone()) { + shouldAttenuate = !bufferToAdd->getListenerUnattenuatedZone()->contains(listeningNodeBuffer->getPosition()); } - - if (radius == 0 || (distanceSquareToSource > radius * radius)) { - // this is either not a spherical source, or the listener is outside the sphere - - if (radius > 0) { - // this is a spherical source - the distance used for the coefficient - // needs to be the closest point on the boundary to the source - - // ovveride the distance to the node with the distance to the point on the - // boundary of the sphere - distanceSquareToSource -= (radius * radius); - - } else { - // calculate the angle delivery for off-axis attenuation - glm::vec3 rotatedListenerPosition = glm::inverse(bufferToAdd->getOrientation()) * relativePosition; - - float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), - glm::normalize(rotatedListenerPosition)); - - const float MAX_OFF_AXIS_ATTENUATION = 0.2f; - const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; - - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO)); - - // multiply the current attenuation coefficient by the calculated off axis coefficient - attenuationCoefficient *= offAxisCoefficient; + + if (shouldAttenuate) { + glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); + + float distanceSquareToSource = glm::dot(relativePosition, relativePosition); + float radius = 0.0f; + + if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) { + InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd; + radius = injectedBuffer->getRadius(); + attenuationCoefficient *= injectedBuffer->getAttenuationRatio(); + } + + if (radius == 0 || (distanceSquareToSource > radius * radius)) { + // this is either not a spherical source, or the listener is outside the sphere + + if (radius > 0) { + // this is a spherical source - the distance used for the coefficient + // needs to be the closest point on the boundary to the source + + // ovveride the distance to the node with the distance to the point on the + // boundary of the sphere + distanceSquareToSource -= (radius * radius); + + } else { + // calculate the angle delivery for off-axis attenuation + glm::vec3 rotatedListenerPosition = glm::inverse(bufferToAdd->getOrientation()) * relativePosition; + + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), + glm::normalize(rotatedListenerPosition)); + + const float MAX_OFF_AXIS_ATTENUATION = 0.2f; + const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; + + float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO)); + + // multiply the current attenuation coefficient by the calculated off axis coefficient + attenuationCoefficient *= offAxisCoefficient; + } + + glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; + + const float DISTANCE_SCALE = 2.5f; + const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; + const float DISTANCE_LOG_BASE = 2.5f; + const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); + + // calculate the distance coefficient using the distance to this node + float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, + DISTANCE_SCALE_LOG + + (0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); + distanceCoefficient = std::min(1.0f, distanceCoefficient); + + // multiply the current attenuation coefficient by the distance coefficient + attenuationCoefficient *= distanceCoefficient; + + // project the rotated source position vector onto the XZ plane + rotatedSourcePosition.y = 0.0f; + + // produce an oriented angle about the y-axis + bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), + glm::normalize(rotatedSourcePosition), + glm::vec3(0.0f, 1.0f, 0.0f)); + + const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; + + // figure out the number of samples of delay and the ratio of the amplitude + // in the weak channel for audio spatialization + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); + numSamplesDelay = SAMPLE_PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } - - glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; - - const float DISTANCE_SCALE = 2.5f; - const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; - const float DISTANCE_LOG_BASE = 2.5f; - const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); - - // calculate the distance coefficient using the distance to this node - float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, - DISTANCE_SCALE_LOG + - (0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); - distanceCoefficient = std::min(1.0f, distanceCoefficient); - - // multiply the current attenuation coefficient by the distance coefficient - attenuationCoefficient *= distanceCoefficient; - - // project the rotated source position vector onto the XZ plane - rotatedSourcePosition.y = 0.0f; - - // produce an oriented angle about the y-axis - bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), - glm::normalize(rotatedSourcePosition), - glm::vec3(0.0f, 1.0f, 0.0f)); - - const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; - - // figure out the number of samples of delay and the ratio of the amplitude - // in the weak channel for audio spatialization - float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); - numSamplesDelay = SAMPLE_PHASE_DELAY_AT_90 * sinRatio; - weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } } const int16_t* nextOutputStart = bufferToAdd->getNextOutput(); - if (!bufferToAdd->isStereo()) { + if (!bufferToAdd->isStereo() && shouldAttenuate) { // this is a mono buffer, which means it gets full attenuation and spatialization // if the bearing relative angle to source is > 0 then the delayed channel is the right one @@ -285,7 +303,8 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf } else if (i + 1 < numSamplesDelay) { // MMX add two delayed samples __m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], - _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], 0, 0); + _clientSamples[parentIndex + SINGLE_STEREO_OFFSET + delayedChannelOffset], + 0, 0); __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio, delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0); @@ -307,16 +326,29 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf } } } else { - // stereo buffer - do attenuation but no sample delay for spatialization + // this is a stereo buffer or an unattenuated buffer, don't perform spatialization for (int s = 0; s < NETWORK_BUFFER_LENGTH_SAMPLES_STEREO; s += 4) { - // use MMX to clamp four additions at a time - _clientSamples[s] = glm::clamp(_clientSamples[s] + (int) (nextOutputStart[s] * attenuationCoefficient), - MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); - _clientSamples[s + 1] = glm::clamp(_clientSamples[s + 1] + (int) (nextOutputStart[s + 1] * attenuationCoefficient), + + int stereoDivider = bufferToAdd->isStereo() ? 1 : 2; + + if (!shouldAttenuate) { + attenuationCoefficient = 1.0f; + } + + _clientSamples[s] = glm::clamp(_clientSamples[s] + + (int) (nextOutputStart[(s / stereoDivider)] * attenuationCoefficient), + MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); + _clientSamples[s + 1] = glm::clamp(_clientSamples[s + 1] + + (int) (nextOutputStart[(s / stereoDivider) + (1 / stereoDivider)] + * attenuationCoefficient), MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); - _clientSamples[s + 2] = glm::clamp(_clientSamples[s + 2] + (int) (nextOutputStart[s + 2] * attenuationCoefficient), + _clientSamples[s + 2] = glm::clamp(_clientSamples[s + 2] + + (int) (nextOutputStart[(s / stereoDivider) + (2 / stereoDivider)] + * attenuationCoefficient), MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); - _clientSamples[s + 3] = glm::clamp(_clientSamples[s + 3] + (int) (nextOutputStart[s + 3] * attenuationCoefficient), + _clientSamples[s + 3] = glm::clamp(_clientSamples[s + 3] + + (int) (nextOutputStart[(s / stereoDivider) + (3 / stereoDivider)] + * attenuationCoefficient), MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE); } } @@ -412,6 +444,32 @@ void AudioMixer::run() { nodeList->addNodeTypeToInterestSet(NodeType::Agent); nodeList->linkedDataCreateCallback = attachNewBufferToNode; + + // check the payload to see if we have any unattenuated zones + const QString UNATTENUATED_ZONE_REGEX_STRING = "--unattenuated-zone ([\\d.,-]+)"; + QRegExp unattenuatedZoneMatch(UNATTENUATED_ZONE_REGEX_STRING); + + if (unattenuatedZoneMatch.indexIn(_payload) != -1) { + QString unattenuatedZoneString = unattenuatedZoneMatch.cap(1); + QStringList zoneStringList = unattenuatedZoneString.split(','); + + glm::vec3 sourceCorner(zoneStringList[0].toFloat(), zoneStringList[1].toFloat(), zoneStringList[2].toFloat()); + glm::vec3 sourceDimensions(zoneStringList[3].toFloat(), zoneStringList[4].toFloat(), zoneStringList[5].toFloat()); + + glm::vec3 listenerCorner(zoneStringList[6].toFloat(), zoneStringList[7].toFloat(), zoneStringList[8].toFloat()); + glm::vec3 listenerDimensions(zoneStringList[9].toFloat(), zoneStringList[10].toFloat(), zoneStringList[11].toFloat()); + + _sourceUnattenuatedZone = new AABox(sourceCorner, sourceDimensions); + _listenerUnattenuatedZone = new AABox(listenerCorner, listenerDimensions); + + glm::vec3 sourceCenter = _sourceUnattenuatedZone->calcCenter(); + glm::vec3 destinationCenter = _listenerUnattenuatedZone->calcCenter(); + + qDebug() << "There is an unattenuated zone with source center at" + << QString("%1, %2, %3").arg(sourceCenter.x).arg(sourceCenter.y).arg(sourceCenter.z); + qDebug() << "Buffers inside this zone will not be attenuated inside a box with center at" + << QString("%1, %2, %3").arg(destinationCenter.x).arg(destinationCenter.y).arg(destinationCenter.z); + } int nextFrame = 0; QElapsedTimer timer; @@ -429,7 +487,9 @@ void AudioMixer::run() { foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { if (node->getLinkedData()) { - ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); + ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES, + _sourceUnattenuatedZone, + _listenerUnattenuatedZone); } } diff --git a/assignment-client/src/audio/AudioMixer.h b/assignment-client/src/audio/AudioMixer.h index 659227dffb..39f8cf63ae 100644 --- a/assignment-client/src/audio/AudioMixer.h +++ b/assignment-client/src/audio/AudioMixer.h @@ -12,8 +12,8 @@ #ifndef hifi_AudioMixer_h #define hifi_AudioMixer_h +#include #include - #include class PositionalAudioRingBuffer; @@ -26,6 +26,7 @@ class AudioMixer : public ThreadedAssignment { Q_OBJECT public: AudioMixer(const QByteArray& packet); + ~AudioMixer(); public slots: /// threaded run of assignment void run(); @@ -51,6 +52,8 @@ private: int _numStatFrames; int _sumListeners; int _sumMixes; + AABox* _sourceUnattenuatedZone; + AABox* _listenerUnattenuatedZone; }; #endif // hifi_AudioMixer_h diff --git a/assignment-client/src/audio/AudioMixerClientData.cpp b/assignment-client/src/audio/AudioMixerClientData.cpp index 9494e927a9..2f78a4ac78 100644 --- a/assignment-client/src/audio/AudioMixerClientData.cpp +++ b/assignment-client/src/audio/AudioMixerClientData.cpp @@ -98,7 +98,8 @@ int AudioMixerClientData::parseData(const QByteArray& packet) { return 0; } -void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) { +void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples, + AABox* checkSourceZone, AABox* listenerZone) { for (int i = 0; i < _ringBuffers.size(); i++) { if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) { // this is a ring buffer that is ready to go @@ -108,6 +109,12 @@ void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSam // calculate the average loudness for the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL // that would be mixed in _ringBuffers[i]->updateNextOutputTrailingLoudness(); + + if (checkSourceZone && checkSourceZone->contains(_ringBuffers[i]->getPosition())) { + _ringBuffers[i]->setListenerUnattenuatedZone(listenerZone); + } else { + _ringBuffers[i]->setListenerUnattenuatedZone(NULL); + } } } } diff --git a/assignment-client/src/audio/AudioMixerClientData.h b/assignment-client/src/audio/AudioMixerClientData.h index 70b653301b..e52b09e134 100644 --- a/assignment-client/src/audio/AudioMixerClientData.h +++ b/assignment-client/src/audio/AudioMixerClientData.h @@ -12,8 +12,7 @@ #ifndef hifi_AudioMixerClientData_h #define hifi_AudioMixerClientData_h -#include - +#include #include #include @@ -28,7 +27,8 @@ public: AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const; int parseData(const QByteArray& packet); - void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples); + void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples, + AABox* checkSourceZone = NULL, AABox* listenerZone = NULL); void pushBuffersAfterFrameSend(); private: QList _ringBuffers; diff --git a/libraries/audio/src/PositionalAudioRingBuffer.cpp b/libraries/audio/src/PositionalAudioRingBuffer.cpp index bb47c6de9e..1cc4147175 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.cpp +++ b/libraries/audio/src/PositionalAudioRingBuffer.cpp @@ -28,14 +28,12 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer:: _willBeAddedToMix(false), _shouldLoopbackForNode(false), _shouldOutputStarveDebug(true), - _isStereo(isStereo) + _isStereo(isStereo), + _listenerUnattenuatedZone(NULL) { } -PositionalAudioRingBuffer::~PositionalAudioRingBuffer() { -} - int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { // skip the packet header (includes the source UUID) diff --git a/libraries/audio/src/PositionalAudioRingBuffer.h b/libraries/audio/src/PositionalAudioRingBuffer.h index 17a663d5f6..00362c245a 100644 --- a/libraries/audio/src/PositionalAudioRingBuffer.h +++ b/libraries/audio/src/PositionalAudioRingBuffer.h @@ -12,9 +12,10 @@ #ifndef hifi_PositionalAudioRingBuffer_h #define hifi_PositionalAudioRingBuffer_h -#include #include +#include + #include "AudioRingBuffer.h" class PositionalAudioRingBuffer : public AudioRingBuffer { @@ -25,7 +26,6 @@ public: }; PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false); - ~PositionalAudioRingBuffer(); int parseData(const QByteArray& packet); int parsePositionalData(const QByteArray& positionalByteArray); @@ -47,6 +47,9 @@ public: const glm::vec3& getPosition() const { return _position; } const glm::quat& getOrientation() const { return _orientation; } + AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; } + void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; } + protected: // disallow copying of PositionalAudioRingBuffer objects PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); @@ -61,6 +64,7 @@ protected: bool _isStereo; float _nextOutputTrailingLoudness; + AABox* _listenerUnattenuatedZone; }; #endif // hifi_PositionalAudioRingBuffer_h diff --git a/libraries/octree/src/AABox.h b/libraries/octree/src/AABox.h deleted file mode 100644 index ef0e535b38..0000000000 --- a/libraries/octree/src/AABox.h +++ /dev/null @@ -1,69 +0,0 @@ -// -// AABox.h -// libraries/octree/src -// -// Created by Brad Hefta-Gaub on 04/11/13. -// Copyright 2013 High Fidelity, Inc. -// -// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards -// Simple axis aligned box class. -// -// 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_AABox_h -#define hifi_AABox_h - -#include - -#include "BoxBase.h" - -class AACube; - -class AABox { - -public: - AABox(const glm::vec3& corner, float size); - AABox(const glm::vec3& corner, const glm::vec3& dimensions); - AABox(); - ~AABox() {}; - - void setBox(const glm::vec3& corner, const glm::vec3& scale); - - void setBox(const glm::vec3& corner, float scale); - glm::vec3 getVertexP(const glm::vec3& normal) const; - glm::vec3 getVertexN(const glm::vec3& normal) const; - void scale(float scale); - const glm::vec3& getCorner() const { return _corner; } - const glm::vec3& getScale() const { return _scale; } - const glm::vec3& getDimensions() const { return _scale; } - - glm::vec3 calcCenter() const; - glm::vec3 calcTopFarLeft() const; - glm::vec3 getVertex(BoxVertex vertex) const; - bool contains(const glm::vec3& point) const; - bool contains(const AABox& otherBox) const; - bool touches(const AABox& otherBox) const; - - bool contains(const AACube& otherCube) const; - bool touches(const AACube& otherCube) const; - - bool expandedContains(const glm::vec3& point, float expansion) const; - bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; - bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; - bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; - -private: - glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; - glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; - glm::vec4 getPlane(BoxFace face) const; - - static BoxFace getOppositeFace(BoxFace face); - - glm::vec3 _corner; - glm::vec3 _scale; -}; - -#endif // hifi_AABox_h diff --git a/libraries/octree/src/AABox.cpp b/libraries/shared/src/AABox.cpp similarity index 100% rename from libraries/octree/src/AABox.cpp rename to libraries/shared/src/AABox.cpp diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h new file mode 100644 index 0000000000..71ee7c73d3 --- /dev/null +++ b/libraries/shared/src/AABox.h @@ -0,0 +1,71 @@ +// +// AABox.h +// libraries/octree/src +// +// Created by Brad Hefta-Gaub on 04/11/13. +// Copyright 2013 High Fidelity, Inc. +// +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// Simple axis aligned box class. +// +// 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_AABox_h +#define hifi_AABox_h + +#include + +#include "BoxBase.h" + +class AACube; + +class AABox { + +public: + AABox(const glm::vec3& corner, float size); + AABox(const glm::vec3& corner, const glm::vec3& dimensions); + AABox(); + ~AABox() {}; + + void setBox(const glm::vec3& corner, const glm::vec3& scale); + + void setBox(const glm::vec3& corner, float scale); + glm::vec3 getVertexP(const glm::vec3& normal) const; + glm::vec3 getVertexN(const glm::vec3& normal) const; + void scale(float scale); + const glm::vec3& getCorner() const { return _corner; } + const glm::vec3& getScale() const { return _scale; } + const glm::vec3& getDimensions() const { return _scale; } + + glm::vec3 calcCenter() const; + glm::vec3 calcTopFarLeft() const; + glm::vec3 getVertex(BoxVertex vertex) const; + bool contains(const glm::vec3& point) const; + bool contains(const AABox& otherBox) const; + bool touches(const AABox& otherBox) const; + + bool contains(const AACube& otherCube) const; + bool touches(const AACube& otherCube) const; + + bool expandedContains(const glm::vec3& point, float expansion) const; + bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; + bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; + + bool isNull() const { return _scale == glm::vec3(0.0f, 0.0f, 0.0f); } + +private: + glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; + glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; + glm::vec4 getPlane(BoxFace face) const; + + static BoxFace getOppositeFace(BoxFace face); + + glm::vec3 _corner; + glm::vec3 _scale; +}; + +#endif // hifi_AABox_h diff --git a/libraries/octree/src/AACube.cpp b/libraries/shared/src/AACube.cpp similarity index 100% rename from libraries/octree/src/AACube.cpp rename to libraries/shared/src/AACube.cpp diff --git a/libraries/octree/src/AACube.h b/libraries/shared/src/AACube.h similarity index 100% rename from libraries/octree/src/AACube.h rename to libraries/shared/src/AACube.h diff --git a/libraries/octree/src/BoxBase.h b/libraries/shared/src/BoxBase.h similarity index 100% rename from libraries/octree/src/BoxBase.h rename to libraries/shared/src/BoxBase.h