Merge branch 'master' of https://github.com/worklist/hifi into experimentalStoreModel

Conflicts:
	libraries/octree/src/AABox.h
This commit is contained in:
ZappoMan 2014-06-18 15:27:36 -07:00
commit 28c7c24399
12 changed files with 238 additions and 164 deletions

View file

@ -33,7 +33,10 @@
#include <glm/gtx/vector_angle.hpp> #include <glm/gtx/vector_angle.hpp>
#include <QtCore/QCoreApplication> #include <QtCore/QCoreApplication>
#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject> #include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>
#include <QtCore/QTimer> #include <QtCore/QTimer>
#include <Logging.h> #include <Logging.h>
@ -71,11 +74,18 @@ AudioMixer::AudioMixer(const QByteArray& packet) :
_performanceThrottlingRatio(0.0f), _performanceThrottlingRatio(0.0f),
_numStatFrames(0), _numStatFrames(0),
_sumListeners(0), _sumListeners(0),
_sumMixes(0) _sumMixes(0),
_sourceUnattenuatedZone(NULL),
_listenerUnattenuatedZone(NULL)
{ {
} }
AudioMixer::~AudioMixer() {
delete _sourceUnattenuatedZone;
delete _listenerUnattenuatedZone;
}
void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd, void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuffer* bufferToAdd,
AvatarAudioRingBuffer* listeningNodeBuffer) { AvatarAudioRingBuffer* listeningNodeBuffer) {
float bearingRelativeAngleToSource = 0.0f; float bearingRelativeAngleToSource = 0.0f;
@ -83,7 +93,9 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
int numSamplesDelay = 0; int numSamplesDelay = 0;
float weakChannelAmplitudeRatio = 1.0f; 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 // if the two buffer pointers do not match then these are different buffers
glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition(); glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition();
@ -101,82 +113,88 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
++_sumMixes; ++_sumMixes;
glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation()); if (bufferToAdd->getListenerUnattenuatedZone()) {
shouldAttenuate = !bufferToAdd->getListenerUnattenuatedZone()->contains(listeningNodeBuffer->getPosition());
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)) { if (shouldAttenuate) {
// this is either not a spherical source, or the listener is outside the sphere glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation());
if (radius > 0) { float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
// this is a spherical source - the distance used for the coefficient float radius = 0.0f;
// needs to be the closest point on the boundary to the source
if (bufferToAdd->getType() == PositionalAudioRingBuffer::Injector) {
// ovveride the distance to the node with the distance to the point on the InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) bufferToAdd;
// boundary of the sphere radius = injectedBuffer->getRadius();
distanceSquareToSource -= (radius * radius); attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
}
} else {
// calculate the angle delivery for off-axis attenuation if (radius == 0 || (distanceSquareToSource > radius * radius)) {
glm::vec3 rotatedListenerPosition = glm::inverse(bufferToAdd->getOrientation()) * relativePosition; // this is either not a spherical source, or the listener is outside the sphere
float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), if (radius > 0) {
glm::normalize(rotatedListenerPosition)); // this is a spherical source - the distance used for the coefficient
// needs to be the closest point on the boundary to the source
const float MAX_OFF_AXIS_ATTENUATION = 0.2f;
const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; // ovveride the distance to the node with the distance to the point on the
// boundary of the sphere
float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + distanceSquareToSource -= (radius * radius);
(OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / PI_OVER_TWO));
} else {
// multiply the current attenuation coefficient by the calculated off axis coefficient // calculate the angle delivery for off-axis attenuation
attenuationCoefficient *= offAxisCoefficient; 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(); 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 // 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 // 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) { } else if (i + 1 < numSamplesDelay) {
// MMX add two delayed samples // MMX add two delayed samples
__m64 bufferSamples = _mm_set_pi16(_clientSamples[parentIndex + delayedChannelOffset], __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, __m64 addSamples = _mm_set_pi16(delayNextOutputStart[i] * attenuationAndWeakChannelRatio,
delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0); delayNextOutputStart[i + 1] * attenuationAndWeakChannelRatio, 0, 0);
@ -307,16 +326,29 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
} }
} }
} else { } 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) { 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), int stereoDivider = bufferToAdd->isStereo() ? 1 : 2;
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
_clientSamples[s + 1] = glm::clamp(_clientSamples[s + 1] + (int) (nextOutputStart[s + 1] * attenuationCoefficient), 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); 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); 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); MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
} }
} }
@ -412,6 +444,32 @@ void AudioMixer::run() {
nodeList->addNodeTypeToInterestSet(NodeType::Agent); nodeList->addNodeTypeToInterestSet(NodeType::Agent);
nodeList->linkedDataCreateCallback = attachNewBufferToNode; 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; int nextFrame = 0;
QElapsedTimer timer; QElapsedTimer timer;
@ -429,7 +487,9 @@ void AudioMixer::run() {
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
if (node->getLinkedData()) { if (node->getLinkedData()) {
((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES); ((AudioMixerClientData*) node->getLinkedData())->checkBuffersBeforeFrameSend(JITTER_BUFFER_SAMPLES,
_sourceUnattenuatedZone,
_listenerUnattenuatedZone);
} }
} }

View file

@ -12,8 +12,8 @@
#ifndef hifi_AudioMixer_h #ifndef hifi_AudioMixer_h
#define hifi_AudioMixer_h #define hifi_AudioMixer_h
#include <AABox.h>
#include <AudioRingBuffer.h> #include <AudioRingBuffer.h>
#include <ThreadedAssignment.h> #include <ThreadedAssignment.h>
class PositionalAudioRingBuffer; class PositionalAudioRingBuffer;
@ -26,6 +26,7 @@ class AudioMixer : public ThreadedAssignment {
Q_OBJECT Q_OBJECT
public: public:
AudioMixer(const QByteArray& packet); AudioMixer(const QByteArray& packet);
~AudioMixer();
public slots: public slots:
/// threaded run of assignment /// threaded run of assignment
void run(); void run();
@ -51,6 +52,8 @@ private:
int _numStatFrames; int _numStatFrames;
int _sumListeners; int _sumListeners;
int _sumMixes; int _sumMixes;
AABox* _sourceUnattenuatedZone;
AABox* _listenerUnattenuatedZone;
}; };
#endif // hifi_AudioMixer_h #endif // hifi_AudioMixer_h

View file

@ -98,7 +98,8 @@ int AudioMixerClientData::parseData(const QByteArray& packet) {
return 0; return 0;
} }
void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples) { void AudioMixerClientData::checkBuffersBeforeFrameSend(int jitterBufferLengthSamples,
AABox* checkSourceZone, AABox* listenerZone) {
for (int i = 0; i < _ringBuffers.size(); i++) { for (int i = 0; i < _ringBuffers.size(); i++) {
if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) { if (_ringBuffers[i]->shouldBeAddedToMix(jitterBufferLengthSamples)) {
// this is a ring buffer that is ready to go // 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 // calculate the average loudness for the next NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL
// that would be mixed in // that would be mixed in
_ringBuffers[i]->updateNextOutputTrailingLoudness(); _ringBuffers[i]->updateNextOutputTrailingLoudness();
if (checkSourceZone && checkSourceZone->contains(_ringBuffers[i]->getPosition())) {
_ringBuffers[i]->setListenerUnattenuatedZone(listenerZone);
} else {
_ringBuffers[i]->setListenerUnattenuatedZone(NULL);
}
} }
} }
} }

View file

@ -12,8 +12,7 @@
#ifndef hifi_AudioMixerClientData_h #ifndef hifi_AudioMixerClientData_h
#define hifi_AudioMixerClientData_h #define hifi_AudioMixerClientData_h
#include <vector> #include <AABox.h>
#include <NodeData.h> #include <NodeData.h>
#include <PositionalAudioRingBuffer.h> #include <PositionalAudioRingBuffer.h>
@ -28,7 +27,8 @@ public:
AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const; AvatarAudioRingBuffer* getAvatarAudioRingBuffer() const;
int parseData(const QByteArray& packet); int parseData(const QByteArray& packet);
void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples); void checkBuffersBeforeFrameSend(int jitterBufferLengthSamples,
AABox* checkSourceZone = NULL, AABox* listenerZone = NULL);
void pushBuffersAfterFrameSend(); void pushBuffersAfterFrameSend();
private: private:
QList<PositionalAudioRingBuffer*> _ringBuffers; QList<PositionalAudioRingBuffer*> _ringBuffers;

View file

@ -28,14 +28,12 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer(PositionalAudioRingBuffer::
_willBeAddedToMix(false), _willBeAddedToMix(false),
_shouldLoopbackForNode(false), _shouldLoopbackForNode(false),
_shouldOutputStarveDebug(true), _shouldOutputStarveDebug(true),
_isStereo(isStereo) _isStereo(isStereo),
_listenerUnattenuatedZone(NULL)
{ {
} }
PositionalAudioRingBuffer::~PositionalAudioRingBuffer() {
}
int PositionalAudioRingBuffer::parseData(const QByteArray& packet) { int PositionalAudioRingBuffer::parseData(const QByteArray& packet) {
// skip the packet header (includes the source UUID) // skip the packet header (includes the source UUID)

View file

@ -12,9 +12,10 @@
#ifndef hifi_PositionalAudioRingBuffer_h #ifndef hifi_PositionalAudioRingBuffer_h
#define hifi_PositionalAudioRingBuffer_h #define hifi_PositionalAudioRingBuffer_h
#include <vector>
#include <glm/gtx/quaternion.hpp> #include <glm/gtx/quaternion.hpp>
#include <AABox.h>
#include "AudioRingBuffer.h" #include "AudioRingBuffer.h"
class PositionalAudioRingBuffer : public AudioRingBuffer { class PositionalAudioRingBuffer : public AudioRingBuffer {
@ -25,7 +26,6 @@ public:
}; };
PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false); PositionalAudioRingBuffer(PositionalAudioRingBuffer::Type type, bool isStereo = false);
~PositionalAudioRingBuffer();
int parseData(const QByteArray& packet); int parseData(const QByteArray& packet);
int parsePositionalData(const QByteArray& positionalByteArray); int parsePositionalData(const QByteArray& positionalByteArray);
@ -47,6 +47,9 @@ public:
const glm::vec3& getPosition() const { return _position; } const glm::vec3& getPosition() const { return _position; }
const glm::quat& getOrientation() const { return _orientation; } const glm::quat& getOrientation() const { return _orientation; }
AABox* getListenerUnattenuatedZone() const { return _listenerUnattenuatedZone; }
void setListenerUnattenuatedZone(AABox* listenerUnattenuatedZone) { _listenerUnattenuatedZone = listenerUnattenuatedZone; }
protected: protected:
// disallow copying of PositionalAudioRingBuffer objects // disallow copying of PositionalAudioRingBuffer objects
PositionalAudioRingBuffer(const PositionalAudioRingBuffer&); PositionalAudioRingBuffer(const PositionalAudioRingBuffer&);
@ -61,6 +64,7 @@ protected:
bool _isStereo; bool _isStereo;
float _nextOutputTrailingLoudness; float _nextOutputTrailingLoudness;
AABox* _listenerUnattenuatedZone;
}; };
#endif // hifi_PositionalAudioRingBuffer_h #endif // hifi_PositionalAudioRingBuffer_h

View file

@ -1,73 +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 <glm/glm.hpp>
#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;
};
inline bool operator==(const AABox& a, const AABox& b) {
return a.getCorner() == b.getCorner() && a.getDimensions() == b.getDimensions();
}
#endif // hifi_AABox_h

View file

@ -0,0 +1,75 @@
//
// 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 <glm/glm.hpp>
#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;
};
inline bool operator==(const AABox& a, const AABox& b) {
return a.getCorner() == b.getCorner() && a.getDimensions() == b.getDimensions();
}
#endif // hifi_AABox_h