mirror of
https://github.com/overte-org/overte.git
synced 2025-04-25 22:56:29 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi into improved_undo
This commit is contained in:
commit
2494e589a9
17 changed files with 429 additions and 122 deletions
|
@ -449,7 +449,7 @@ void DomainServer::sendDomainListToNode(const SharedNodePointer& node, const Hif
|
||||||
if (nodeInterestList.size() > 0) {
|
if (nodeInterestList.size() > 0) {
|
||||||
|
|
||||||
DTLSServerSession* dtlsSession = _isUsingDTLS ? _dtlsSessions[senderSockAddr] : NULL;
|
DTLSServerSession* dtlsSession = _isUsingDTLS ? _dtlsSessions[senderSockAddr] : NULL;
|
||||||
unsigned int dataMTU = dtlsSession ? gnutls_dtls_get_data_mtu(*dtlsSession->getGnuTLSSession()) : MAX_PACKET_SIZE;
|
int dataMTU = dtlsSession ? (int)gnutls_dtls_get_data_mtu(*dtlsSession->getGnuTLSSession()) : MAX_PACKET_SIZE;
|
||||||
|
|
||||||
// if the node has any interest types, send back those nodes as well
|
// if the node has any interest types, send back those nodes as well
|
||||||
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
foreach (const SharedNodePointer& otherNode, nodeList->getNodeHash()) {
|
||||||
|
|
|
@ -480,7 +480,7 @@ void Audio::handleAudioInput() {
|
||||||
float thisSample = 0;
|
float thisSample = 0;
|
||||||
int samplesOverNoiseGate = 0;
|
int samplesOverNoiseGate = 0;
|
||||||
|
|
||||||
const float NOISE_GATE_HEIGHT = 7.f;
|
const float NOISE_GATE_HEIGHT = 7.0f;
|
||||||
const int NOISE_GATE_WIDTH = 5;
|
const int NOISE_GATE_WIDTH = 5;
|
||||||
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
const int NOISE_GATE_CLOSE_FRAME_DELAY = 5;
|
||||||
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
const int NOISE_GATE_FRAMES_TO_AVERAGE = 5;
|
||||||
|
@ -490,7 +490,7 @@ void Audio::handleAudioInput() {
|
||||||
//
|
//
|
||||||
// Check clipping, adjust DC offset, and check if should open noise gate
|
// Check clipping, adjust DC offset, and check if should open noise gate
|
||||||
//
|
//
|
||||||
float measuredDcOffset = 0.f;
|
float measuredDcOffset = 0.0f;
|
||||||
// Increment the time since the last clip
|
// Increment the time since the last clip
|
||||||
if (_timeSinceLastClip >= 0.0f) {
|
if (_timeSinceLastClip >= 0.0f) {
|
||||||
_timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE;
|
_timeSinceLastClip += (float) NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL / (float) SAMPLE_RATE;
|
||||||
|
@ -500,7 +500,7 @@ void Audio::handleAudioInput() {
|
||||||
measuredDcOffset += monoAudioSamples[i];
|
measuredDcOffset += monoAudioSamples[i];
|
||||||
monoAudioSamples[i] -= (int16_t) _dcOffset;
|
monoAudioSamples[i] -= (int16_t) _dcOffset;
|
||||||
thisSample = fabsf(monoAudioSamples[i]);
|
thisSample = fabsf(monoAudioSamples[i]);
|
||||||
if (thisSample >= (32767.f * CLIPPING_THRESHOLD)) {
|
if (thisSample >= (32767.0f * CLIPPING_THRESHOLD)) {
|
||||||
_timeSinceLastClip = 0.0f;
|
_timeSinceLastClip = 0.0f;
|
||||||
}
|
}
|
||||||
loudness += thisSample;
|
loudness += thisSample;
|
||||||
|
@ -511,18 +511,18 @@ void Audio::handleAudioInput() {
|
||||||
}
|
}
|
||||||
|
|
||||||
measuredDcOffset /= NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
measuredDcOffset /= NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||||
if (_dcOffset == 0.f) {
|
if (_dcOffset == 0.0f) {
|
||||||
// On first frame, copy over measured offset
|
// On first frame, copy over measured offset
|
||||||
_dcOffset = measuredDcOffset;
|
_dcOffset = measuredDcOffset;
|
||||||
} else {
|
} else {
|
||||||
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
_dcOffset = DC_OFFSET_AVERAGING * _dcOffset + (1.0f - DC_OFFSET_AVERAGING) * measuredDcOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add tone injection if enabled
|
// Add tone injection if enabled
|
||||||
const float TONE_FREQ = 220.f / SAMPLE_RATE * TWO_PI;
|
const float TONE_FREQ = 220.0f / SAMPLE_RATE * TWO_PI;
|
||||||
const float QUARTER_VOLUME = 8192.f;
|
const float QUARTER_VOLUME = 8192.0f;
|
||||||
if (_toneInjectionEnabled) {
|
if (_toneInjectionEnabled) {
|
||||||
loudness = 0.f;
|
loudness = 0.0f;
|
||||||
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
for (int i = 0; i < NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||||
monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample));
|
monoAudioSamples[i] = QUARTER_VOLUME * sinf(TONE_FREQ * (float)(i + _proceduralEffectSample));
|
||||||
loudness += fabsf(monoAudioSamples[i]);
|
loudness += fabsf(monoAudioSamples[i]);
|
||||||
|
@ -532,7 +532,7 @@ void Audio::handleAudioInput() {
|
||||||
|
|
||||||
// If Noise Gate is enabled, check and turn the gate on and off
|
// If Noise Gate is enabled, check and turn the gate on and off
|
||||||
if (!_toneInjectionEnabled && _noiseGateEnabled) {
|
if (!_toneInjectionEnabled && _noiseGateEnabled) {
|
||||||
float averageOfAllSampleFrames = 0.f;
|
float averageOfAllSampleFrames = 0.0f;
|
||||||
_noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness;
|
_noiseSampleFrames[_noiseGateSampleCounter++] = _lastInputLoudness;
|
||||||
if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
|
if (_noiseGateSampleCounter == NUMBER_OF_NOISE_SAMPLE_FRAMES) {
|
||||||
float smallestSample = FLT_MAX;
|
float smallestSample = FLT_MAX;
|
||||||
|
@ -659,9 +659,9 @@ void Audio::addReceivedAudioToBuffer(const QByteArray& audioByteArray) {
|
||||||
_stdev.reset();
|
_stdev.reset();
|
||||||
// Set jitter buffer to be a multiple of the measured standard deviation
|
// Set jitter buffer to be a multiple of the measured standard deviation
|
||||||
const int MAX_JITTER_BUFFER_SAMPLES = _ringBuffer.getSampleCapacity() / 2;
|
const int MAX_JITTER_BUFFER_SAMPLES = _ringBuffer.getSampleCapacity() / 2;
|
||||||
const float NUM_STANDARD_DEVIATIONS = 3.f;
|
const float NUM_STANDARD_DEVIATIONS = 3.0f;
|
||||||
if (Menu::getInstance()->getAudioJitterBufferSamples() == 0) {
|
if (Menu::getInstance()->getAudioJitterBufferSamples() == 0) {
|
||||||
float newJitterBufferSamples = (NUM_STANDARD_DEVIATIONS * _measuredJitter) / 1000.f * SAMPLE_RATE;
|
float newJitterBufferSamples = (NUM_STANDARD_DEVIATIONS * _measuredJitter) / 1000.0f * SAMPLE_RATE;
|
||||||
setJitterBufferSamples(glm::clamp((int)newJitterBufferSamples, 0, MAX_JITTER_BUFFER_SAMPLES));
|
setJitterBufferSamples(glm::clamp((int)newJitterBufferSamples, 0, MAX_JITTER_BUFFER_SAMPLES));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -900,10 +900,10 @@ void Audio::toggleAudioSpatialProcessing() {
|
||||||
void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
||||||
float sample;
|
float sample;
|
||||||
const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f;
|
const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f;
|
||||||
const float COLLISION_SOUND_MAX_VOLUME = 1000.f;
|
const float COLLISION_SOUND_MAX_VOLUME = 1000.0f;
|
||||||
const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f);
|
const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f);
|
||||||
const float DOWN_TWO_OCTAVES = 4.f;
|
const float DOWN_TWO_OCTAVES = 4.0f;
|
||||||
const float DOWN_FOUR_OCTAVES = 16.f;
|
const float DOWN_FOUR_OCTAVES = 16.0f;
|
||||||
float t;
|
float t;
|
||||||
if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) {
|
if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) {
|
||||||
for (int i = 0; i < numSamples; i++) {
|
for (int i = 0; i < numSamples; i++) {
|
||||||
|
@ -933,12 +933,12 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
||||||
_proceduralEffectSample += numSamples;
|
_proceduralEffectSample += numSamples;
|
||||||
|
|
||||||
// Add a drum sound
|
// Add a drum sound
|
||||||
const float MAX_VOLUME = 32000.f;
|
const float MAX_VOLUME = 32000.0f;
|
||||||
const float MAX_DURATION = 2.f;
|
const float MAX_DURATION = 2.0f;
|
||||||
const float MIN_AUDIBLE_VOLUME = 0.001f;
|
const float MIN_AUDIBLE_VOLUME = 0.001f;
|
||||||
const float NOISE_MAGNITUDE = 0.02f;
|
const float NOISE_MAGNITUDE = 0.02f;
|
||||||
float frequency = (_drumSoundFrequency / SAMPLE_RATE) * TWO_PI;
|
float frequency = (_drumSoundFrequency / SAMPLE_RATE) * TWO_PI;
|
||||||
if (_drumSoundVolume > 0.f) {
|
if (_drumSoundVolume > 0.0f) {
|
||||||
for (int i = 0; i < numSamples; i++) {
|
for (int i = 0; i < numSamples; i++) {
|
||||||
t = (float) _drumSoundSample + (float) i;
|
t = (float) _drumSoundSample + (float) i;
|
||||||
sample = sinf(t * frequency);
|
sample = sinf(t * frequency);
|
||||||
|
@ -958,12 +958,12 @@ void Audio::addProceduralSounds(int16_t* monoInput, int numSamples) {
|
||||||
_localProceduralSamples[i] = glm::clamp(_localProceduralSamples[i] + collisionSample,
|
_localProceduralSamples[i] = glm::clamp(_localProceduralSamples[i] + collisionSample,
|
||||||
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
MIN_SAMPLE_VALUE, MAX_SAMPLE_VALUE);
|
||||||
|
|
||||||
_drumSoundVolume *= (1.f - _drumSoundDecay);
|
_drumSoundVolume *= (1.0f - _drumSoundDecay);
|
||||||
}
|
}
|
||||||
_drumSoundSample += numSamples;
|
_drumSoundSample += numSamples;
|
||||||
_drumSoundDuration = glm::clamp(_drumSoundDuration - (AUDIO_CALLBACK_MSECS / 1000.f), 0.f, MAX_DURATION);
|
_drumSoundDuration = glm::clamp(_drumSoundDuration - (AUDIO_CALLBACK_MSECS / 1000.0f), 0.0f, MAX_DURATION);
|
||||||
if (_drumSoundDuration == 0.f || (_drumSoundVolume < MIN_AUDIBLE_VOLUME)) {
|
if (_drumSoundDuration == 0.0f || (_drumSoundVolume < MIN_AUDIBLE_VOLUME)) {
|
||||||
_drumSoundVolume = 0.f;
|
_drumSoundVolume = 0.0f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -996,7 +996,7 @@ void Audio::renderToolBox(int x, int y, bool boxed) {
|
||||||
|
|
||||||
if (boxed) {
|
if (boxed) {
|
||||||
|
|
||||||
bool isClipping = ((getTimeSinceLastClip() > 0.f) && (getTimeSinceLastClip() < 1.f));
|
bool isClipping = ((getTimeSinceLastClip() > 0.0f) && (getTimeSinceLastClip() < 1.0f));
|
||||||
const int BOX_LEFT_PADDING = 5;
|
const int BOX_LEFT_PADDING = 5;
|
||||||
const int BOX_TOP_PADDING = 10;
|
const int BOX_TOP_PADDING = 10;
|
||||||
const int BOX_WIDTH = 266;
|
const int BOX_WIDTH = 266;
|
||||||
|
@ -1007,9 +1007,9 @@ void Audio::renderToolBox(int x, int y, bool boxed) {
|
||||||
glBindTexture(GL_TEXTURE_2D, _boxTextureId);
|
glBindTexture(GL_TEXTURE_2D, _boxTextureId);
|
||||||
|
|
||||||
if (isClipping) {
|
if (isClipping) {
|
||||||
glColor3f(1.f,0.f,0.f);
|
glColor3f(1.0f, 0.0f, 0.0f);
|
||||||
} else {
|
} else {
|
||||||
glColor3f(.41f,.41f,.41f);
|
glColor3f(0.41f, 0.41f, 0.41f);
|
||||||
}
|
}
|
||||||
glBegin(GL_QUADS);
|
glBegin(GL_QUADS);
|
||||||
|
|
||||||
|
@ -1086,10 +1086,8 @@ void Audio::addBufferToScope(
|
||||||
// Short int pointer to mapped samples in byte array
|
// Short int pointer to mapped samples in byte array
|
||||||
int16_t* destination = (int16_t*) byteArray.data();
|
int16_t* destination = (int16_t*) byteArray.data();
|
||||||
|
|
||||||
for (int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) {
|
for (unsigned int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) {
|
||||||
|
|
||||||
sample = (float)source[i * sourceNumberOfChannels + sourceChannel];
|
sample = (float)source[i * sourceNumberOfChannels + sourceChannel];
|
||||||
|
|
||||||
if (sample > 0) {
|
if (sample > 0) {
|
||||||
value = (int16_t)(multiplier * logf(sample));
|
value = (int16_t)(multiplier * logf(sample));
|
||||||
} else if (sample < 0) {
|
} else if (sample < 0) {
|
||||||
|
@ -1097,7 +1095,6 @@ void Audio::addBufferToScope(
|
||||||
} else {
|
} else {
|
||||||
value = 0;
|
value = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
destination[i + frameOffset] = value;
|
destination[i + frameOffset] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -335,15 +335,17 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f));
|
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.0f));
|
||||||
radius *= COLLISION_RADIUS_SCALAR;
|
radius *= COLLISION_RADIUS_SCALAR;
|
||||||
}
|
}
|
||||||
|
if (_collisionFlags) {
|
||||||
if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) {
|
updateShapePositions();
|
||||||
updateCollisionWithEnvironment(deltaTime, radius);
|
if (_collisionFlags & COLLISION_GROUP_ENVIRONMENT) {
|
||||||
}
|
updateCollisionWithEnvironment(deltaTime, radius);
|
||||||
if (_collisionFlags & COLLISION_GROUP_VOXELS) {
|
}
|
||||||
updateCollisionWithVoxels(deltaTime, radius);
|
if (_collisionFlags & COLLISION_GROUP_VOXELS) {
|
||||||
}
|
updateCollisionWithVoxels(deltaTime, radius);
|
||||||
if (_collisionFlags & COLLISION_GROUP_AVATARS) {
|
}
|
||||||
updateCollisionWithAvatars(deltaTime);
|
if (_collisionFlags & COLLISION_GROUP_AVATARS) {
|
||||||
|
updateCollisionWithAvatars(deltaTime);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -795,19 +797,21 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CollisionList myCollisions(64);
|
||||||
|
|
||||||
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
|
void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
|
||||||
const float VOXEL_ELASTICITY = 0.4f;
|
myCollisions.clear();
|
||||||
const float VOXEL_DAMPING = 0.0f;
|
const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape();
|
||||||
const float VOXEL_COLLISION_FREQUENCY = 0.5f;
|
if (Application::getInstance()->getVoxelTree()->findShapeCollisions(&boundingShape, myCollisions)) {
|
||||||
glm::vec3 penetration;
|
const float VOXEL_ELASTICITY = 0.4f;
|
||||||
float pelvisFloatingHeight = getPelvisFloatingHeight();
|
const float VOXEL_DAMPING = 0.0f;
|
||||||
if (Application::getInstance()->getVoxelTree()->findCapsulePenetration(
|
for (int i = 0; i < myCollisions.size(); ++i) {
|
||||||
_position - glm::vec3(0.0f, pelvisFloatingHeight - radius, 0.0f),
|
CollisionInfo* collision = myCollisions[i];
|
||||||
_position + glm::vec3(0.0f, getSkeletonHeight() - pelvisFloatingHeight + radius, 0.0f), radius, penetration)) {
|
applyHardCollision(collision->_penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
||||||
_lastCollisionPosition = _position;
|
}
|
||||||
updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
|
const float VOXEL_COLLISION_FREQUENCY = 0.5f;
|
||||||
applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);
|
updateCollisionSound(myCollisions[0]->_penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {
|
void MyAvatar::applyHardCollision(const glm::vec3& penetration, float elasticity, float damping) {
|
||||||
|
@ -912,7 +916,6 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
||||||
// no need to compute a bunch of stuff if we have one or fewer avatars
|
// no need to compute a bunch of stuff if we have one or fewer avatars
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
updateShapePositions();
|
|
||||||
float myBoundingRadius = getBoundingRadius();
|
float myBoundingRadius = getBoundingRadius();
|
||||||
|
|
||||||
const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE);
|
const float BODY_COLLISION_RESOLUTION_FACTOR = glm::max(1.0f, deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE);
|
||||||
|
|
|
@ -193,6 +193,8 @@ public:
|
||||||
/// Sets blended vertices computed in a separate thread.
|
/// Sets blended vertices computed in a separate thread.
|
||||||
void setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
void setBlendedVertices(const QVector<glm::vec3>& vertices, const QVector<glm::vec3>& normals);
|
||||||
|
|
||||||
|
const CapsuleShape& getBoundingShape() const { return _boundingShape; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
|
@ -39,7 +39,8 @@ ScriptEditorWidget::ScriptEditorWidget() :
|
||||||
setTitleBarWidget(new QWidget());
|
setTitleBarWidget(new QWidget());
|
||||||
QFontMetrics fm(_scriptEditorWidgetUI->scriptEdit->font());
|
QFontMetrics fm(_scriptEditorWidgetUI->scriptEdit->font());
|
||||||
_scriptEditorWidgetUI->scriptEdit->setTabStopWidth(fm.width('0') * 4);
|
_scriptEditorWidgetUI->scriptEdit->setTabStopWidth(fm.width('0') * 4);
|
||||||
ScriptHighlighting* highlighting = new ScriptHighlighting(_scriptEditorWidgetUI->scriptEdit->document());
|
// We create a new ScriptHighligting QObject and provide it with a parent so this is NOT a memory leak.
|
||||||
|
new ScriptHighlighting(_scriptEditorWidgetUI->scriptEdit->document());
|
||||||
QTimer::singleShot(0, _scriptEditorWidgetUI->scriptEdit, SLOT(setFocus()));
|
QTimer::singleShot(0, _scriptEditorWidgetUI->scriptEdit, SLOT(setFocus()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,18 +20,20 @@
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|
||||||
#include "CoverageMap.h"
|
|
||||||
#include <GeometryUtil.h>
|
#include <GeometryUtil.h>
|
||||||
#include "OctalCode.h"
|
#include <OctalCode.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
#include <Shape.h>
|
||||||
|
#include <ShapeCollider.h>
|
||||||
|
|
||||||
//#include "Tags.h"
|
//#include "Tags.h"
|
||||||
|
|
||||||
#include "ViewFrustum.h"
|
#include "CoverageMap.h"
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
#include "OctreeElementBag.h"
|
#include "OctreeElementBag.h"
|
||||||
#include "Octree.h"
|
#include "Octree.h"
|
||||||
|
#include "ViewFrustum.h"
|
||||||
|
|
||||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) {
|
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale) {
|
||||||
return voxelSizeScale / powf(2, renderLevel);
|
return voxelSizeScale / powf(2, renderLevel);
|
||||||
|
@ -676,6 +678,13 @@ public:
|
||||||
bool found;
|
bool found;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ShapeArgs {
|
||||||
|
public:
|
||||||
|
const Shape* shape;
|
||||||
|
CollisionList& collisions;
|
||||||
|
bool found;
|
||||||
|
};
|
||||||
|
|
||||||
bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) {
|
bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) {
|
||||||
CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData);
|
CapsuleArgs* args = static_cast<CapsuleArgs*>(extraData);
|
||||||
|
|
||||||
|
@ -697,6 +706,27 @@ bool findCapsulePenetrationOp(OctreeElement* node, void* extraData) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool findShapeCollisionsOp(OctreeElement* node, void* extraData) {
|
||||||
|
ShapeArgs* args = static_cast<ShapeArgs*>(extraData);
|
||||||
|
|
||||||
|
// coarse check against bounds
|
||||||
|
AABox cube = node->getAABox();
|
||||||
|
cube.scale(TREE_SCALE);
|
||||||
|
if (!cube.expandedContains(args->shape->getPosition(), args->shape->getBoundingRadius())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!node->isLeaf()) {
|
||||||
|
return true; // recurse on children
|
||||||
|
}
|
||||||
|
if (node->hasContent()) {
|
||||||
|
if (ShapeCollider::collideShapeWithAACube(args->shape, cube.calcCenter(), cube.getScale(), args->collisions)) {
|
||||||
|
args->found = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
|
bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
|
||||||
glm::vec3& penetration, Octree::lockType lockType) {
|
glm::vec3& penetration, Octree::lockType lockType) {
|
||||||
|
|
||||||
|
@ -727,6 +757,29 @@ bool Octree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end
|
||||||
return args.found;
|
return args.found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Octree::findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType lockType) {
|
||||||
|
|
||||||
|
ShapeArgs args = { shape, collisions, false };
|
||||||
|
|
||||||
|
bool gotLock = false;
|
||||||
|
if (lockType == Octree::Lock) {
|
||||||
|
lockForRead();
|
||||||
|
gotLock = true;
|
||||||
|
} else if (lockType == Octree::TryLock) {
|
||||||
|
gotLock = tryLockForRead();
|
||||||
|
if (!gotLock) {
|
||||||
|
return args.found; // if we wanted to tryLock, and we couldn't then just bail...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
recurseTreeWithOperation(findShapeCollisionsOp, &args);
|
||||||
|
|
||||||
|
if (gotLock) {
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
return args.found;
|
||||||
|
}
|
||||||
|
|
||||||
class GetElementEnclosingArgs {
|
class GetElementEnclosingArgs {
|
||||||
public:
|
public:
|
||||||
OctreeElement* element;
|
OctreeElement* element;
|
||||||
|
|
|
@ -21,6 +21,7 @@ class Octree;
|
||||||
class OctreeElement;
|
class OctreeElement;
|
||||||
class OctreeElementBag;
|
class OctreeElementBag;
|
||||||
class OctreePacketData;
|
class OctreePacketData;
|
||||||
|
class Shape;
|
||||||
|
|
||||||
|
|
||||||
#include "JurisdictionMap.h"
|
#include "JurisdictionMap.h"
|
||||||
|
@ -30,6 +31,8 @@ class OctreePacketData;
|
||||||
#include "OctreePacketData.h"
|
#include "OctreePacketData.h"
|
||||||
#include "OctreeSceneStats.h"
|
#include "OctreeSceneStats.h"
|
||||||
|
|
||||||
|
#include <CollisionInfo.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
|
@ -246,6 +249,8 @@ public:
|
||||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius,
|
||||||
glm::vec3& penetration, Octree::lockType lockType = Octree::TryLock);
|
glm::vec3& penetration, Octree::lockType lockType = Octree::TryLock);
|
||||||
|
|
||||||
|
bool findShapeCollisions(const Shape* shape, CollisionList& collisions, Octree::lockType = Octree::TryLock);
|
||||||
|
|
||||||
OctreeElement* getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType = Octree::TryLock);
|
OctreeElement* getElementEnclosingPoint(const glm::vec3& point, Octree::lockType lockType = Octree::TryLock);
|
||||||
|
|
||||||
// Note: this assumes the fileFormat is the HIO individual voxels code files
|
// Note: this assumes the fileFormat is the HIO individual voxels code files
|
||||||
|
|
|
@ -21,10 +21,10 @@
|
||||||
|
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "SharedUtil.h"
|
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
#include "OctreeElement.h"
|
#include "OctreeElement.h"
|
||||||
#include "Octree.h"
|
#include "Octree.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
quint64 OctreeElement::_voxelMemoryUsage = 0;
|
quint64 OctreeElement::_voxelMemoryUsage = 0;
|
||||||
quint64 OctreeElement::_octcodeMemoryUsage = 0;
|
quint64 OctreeElement::_octcodeMemoryUsage = 0;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "Plane.h"
|
#include "Plane.h"
|
||||||
|
|
||||||
#include "OctreeConstants.h"
|
#include "OctreeConstants.h"
|
||||||
#include "OctreeProjectedPolygon.h"
|
#include "OctreeProjectedPolygon.h"
|
||||||
|
|
||||||
|
|
|
@ -48,3 +48,6 @@ void CollisionList::clear() {
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollisionInfo* CollisionList::operator[](int index) {
|
||||||
|
return (index > -1 && index < _size) ? &(_collisions[index]) : NULL;
|
||||||
|
}
|
||||||
|
|
|
@ -95,6 +95,8 @@ public:
|
||||||
/// Clear valid collisions.
|
/// Clear valid collisions.
|
||||||
void clear();
|
void clear();
|
||||||
|
|
||||||
|
CollisionInfo* operator[](int index);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _maxSize; // the container cannot get larger than this
|
int _maxSize; // the container cannot get larger than this
|
||||||
int _size; // the current number of valid collisions in the list
|
int _size; // the current number of valid collisions in the list
|
||||||
|
|
|
@ -92,6 +92,29 @@ bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<con
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool collideShapeWithAACube(const Shape* shapeA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) {
|
||||||
|
int typeA = shapeA->getType();
|
||||||
|
if (typeA == Shape::SPHERE_SHAPE) {
|
||||||
|
return sphereAACube(static_cast<const SphereShape*>(shapeA), cubeCenter, cubeSide, collisions);
|
||||||
|
} else if (typeA == Shape::CAPSULE_SHAPE) {
|
||||||
|
return capsuleAACube(static_cast<const CapsuleShape*>(shapeA), cubeCenter, cubeSide, collisions);
|
||||||
|
} else if (typeA == Shape::LIST_SHAPE) {
|
||||||
|
const ListShape* listA = static_cast<const ListShape*>(shapeA);
|
||||||
|
bool touching = false;
|
||||||
|
for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) {
|
||||||
|
const Shape* subShape = listA->getSubShape(i);
|
||||||
|
int subType = subShape->getType();
|
||||||
|
if (subType == Shape::SPHERE_SHAPE) {
|
||||||
|
touching = sphereAACube(static_cast<const SphereShape*>(subShape), cubeCenter, cubeSide, collisions) || touching;
|
||||||
|
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||||
|
touching = capsuleAACube(static_cast<const CapsuleShape*>(subShape), cubeCenter, cubeSide, collisions) || touching;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return touching;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, CollisionList& collisions) {
|
bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, CollisionList& collisions) {
|
||||||
glm::vec3 BA = sphereB->getPosition() - sphereA->getPosition();
|
glm::vec3 BA = sphereB->getPosition() - sphereA->getPosition();
|
||||||
float distanceSquared = glm::dot(BA, BA);
|
float distanceSquared = glm::dot(BA, BA);
|
||||||
|
@ -567,4 +590,103 @@ bool listList(const ListShape* listA, const ListShape* listB, CollisionList& col
|
||||||
return touching;
|
return touching;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// helper function
|
||||||
|
bool sphereAACube(const glm::vec3& sphereCenter, float sphereRadius, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) {
|
||||||
|
glm::vec3 BA = cubeCenter - sphereCenter;
|
||||||
|
float distance = glm::length(BA);
|
||||||
|
if (distance > EPSILON) {
|
||||||
|
BA /= distance; // BA is now normalized
|
||||||
|
// compute the nearest point on sphere
|
||||||
|
glm::vec3 surfaceA = sphereCenter + sphereRadius * BA;
|
||||||
|
// compute the nearest point on cube
|
||||||
|
float maxBA = glm::max(glm::max(fabs(BA.x), fabs(BA.y)), fabs(BA.z));
|
||||||
|
glm::vec3 surfaceB = cubeCenter - (0.5f * cubeSide / maxBA) * BA;
|
||||||
|
// collision happens when "vector to surfaceA from surfaceB" dots with BA to produce a positive value
|
||||||
|
glm::vec3 surfaceAB = surfaceA - surfaceB;
|
||||||
|
if (glm::dot(surfaceAB, BA) > 0.f) {
|
||||||
|
CollisionInfo* collision = collisions.getNewCollision();
|
||||||
|
if (collision) {
|
||||||
|
/* KEEP THIS CODE -- this is how to collide the cube with stark face normals (no rounding).
|
||||||
|
* We might want to use this code later for sealing boundaries between adjacent voxels.
|
||||||
|
// penetration is parallel to box side direction
|
||||||
|
BA /= maxBA;
|
||||||
|
glm::vec3 direction;
|
||||||
|
glm::modf(BA, direction);
|
||||||
|
direction = glm::normalize(direction);
|
||||||
|
*/
|
||||||
|
|
||||||
|
// For rounded normals at edges and corners:
|
||||||
|
// At this point imagine that sphereCenter touches a "normalized" cube with rounded edges.
|
||||||
|
// This cube has a sidelength of 2 and its smoothing radius is sphereRadius/maxBA.
|
||||||
|
// We're going to try to compute the "negative normal" (and hence direction of penetration)
|
||||||
|
// of this surface.
|
||||||
|
|
||||||
|
float radius = sphereRadius / (distance * maxBA); // normalized radius
|
||||||
|
float shortLength = maxBA - radius;
|
||||||
|
glm::vec3 direction = BA;
|
||||||
|
if (shortLength > 0.0f) {
|
||||||
|
direction = glm::abs(BA) - glm::vec3(shortLength);
|
||||||
|
// Set any negative components to zero, and adopt the sign of the original BA component.
|
||||||
|
// Unfortunately there isn't an easy way to make this fast.
|
||||||
|
if (direction.x < 0.0f) {
|
||||||
|
direction.x = 0.f;
|
||||||
|
} else if (BA.x < 0.f) {
|
||||||
|
direction.x = -direction.x;
|
||||||
|
}
|
||||||
|
if (direction.y < 0.0f) {
|
||||||
|
direction.y = 0.f;
|
||||||
|
} else if (BA.y < 0.f) {
|
||||||
|
direction.y = -direction.y;
|
||||||
|
}
|
||||||
|
if (direction.z < 0.0f) {
|
||||||
|
direction.z = 0.f;
|
||||||
|
} else if (BA.z < 0.f) {
|
||||||
|
direction.z = -direction.z;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
direction = glm::normalize(direction);
|
||||||
|
|
||||||
|
// penetration is the projection of surfaceAB on direction
|
||||||
|
collision->_penetration = glm::dot(surfaceAB, direction) * direction;
|
||||||
|
// contactPoint is on surface of A
|
||||||
|
collision->_contactPoint = sphereCenter - sphereRadius * direction;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (sphereRadius + 0.5f * cubeSide > distance) {
|
||||||
|
// NOTE: for cocentric approximation we collide sphere and cube as two spheres which means
|
||||||
|
// this algorithm will probably be wrong when both sphere and cube are very small (both ~EPSILON)
|
||||||
|
CollisionInfo* collision = collisions.getNewCollision();
|
||||||
|
if (collision) {
|
||||||
|
// the penetration and contactPoint are undefined, so we pick a penetration direction (-yAxis)
|
||||||
|
collision->_penetration = (sphereRadius + 0.5f * cubeSide) * glm::vec3(0.0f, -1.0f, 0.0f);
|
||||||
|
// contactPoint is on surface of A
|
||||||
|
collision->_contactPoint = sphereCenter + collision->_penetration;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sphereAACube(const SphereShape* sphereA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) {
|
||||||
|
return sphereAACube(sphereA->getPosition(), sphereA->getRadius(), cubeCenter, cubeSide, collisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool capsuleAACube(const CapsuleShape* capsuleA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions) {
|
||||||
|
// find nerest approach of capsule line segment to cube
|
||||||
|
glm::vec3 capsuleAxis;
|
||||||
|
capsuleA->computeNormalizedAxis(capsuleAxis);
|
||||||
|
float offset = glm::dot(cubeCenter - capsuleA->getPosition(), capsuleAxis);
|
||||||
|
float halfHeight = capsuleA->getHalfHeight();
|
||||||
|
if (offset > halfHeight) {
|
||||||
|
offset = halfHeight;
|
||||||
|
} else if (offset < -halfHeight) {
|
||||||
|
offset = -halfHeight;
|
||||||
|
}
|
||||||
|
glm::vec3 nearestApproach = capsuleA->getPosition() + offset * capsuleAxis;
|
||||||
|
// collide nearest approach like a sphere at that point
|
||||||
|
return sphereAACube(nearestApproach, capsuleA->getRadius(), cubeCenter, cubeSide, collisions);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace ShapeCollider
|
} // namespace ShapeCollider
|
||||||
|
|
|
@ -33,6 +33,13 @@ namespace ShapeCollider {
|
||||||
/// \return true if any shapes collide
|
/// \return true if any shapes collide
|
||||||
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision);
|
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision);
|
||||||
|
|
||||||
|
/// \param shapeA a pointer to a shape
|
||||||
|
/// \param cubeCenter center of cube
|
||||||
|
/// \param cubeSide lenght of side of cube
|
||||||
|
/// \param collisions[out] average collision details
|
||||||
|
/// \return true if shapeA collides with axis aligned cube
|
||||||
|
bool collideShapeWithAACube(const Shape* shapeA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||||
|
|
||||||
/// \param sphereA pointer to first shape
|
/// \param sphereA pointer to first shape
|
||||||
/// \param sphereB pointer to second shape
|
/// \param sphereB pointer to second shape
|
||||||
/// \param[out] collisions where to append collision details
|
/// \param[out] collisions where to append collision details
|
||||||
|
@ -129,6 +136,20 @@ namespace ShapeCollider {
|
||||||
/// \return true if shapes collide
|
/// \return true if shapes collide
|
||||||
bool listList(const ListShape* listA, const ListShape* listB, CollisionList& collisions);
|
bool listList(const ListShape* listA, const ListShape* listB, CollisionList& collisions);
|
||||||
|
|
||||||
|
/// \param sphereA pointer to sphere
|
||||||
|
/// \param cubeCenter center of cube
|
||||||
|
/// \param cubeSide lenght of side of cube
|
||||||
|
/// \param[out] collisions where to append collision details
|
||||||
|
/// \return true if sphereA collides with axis aligned cube
|
||||||
|
bool sphereAACube(const SphereShape* sphereA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||||
|
|
||||||
|
/// \param capsuleA pointer to capsule
|
||||||
|
/// \param cubeCenter center of cube
|
||||||
|
/// \param cubeSide lenght of side of cube
|
||||||
|
/// \param[out] collisions where to append collision details
|
||||||
|
/// \return true if capsuleA collides with axis aligned cube
|
||||||
|
bool capsuleAACube(const CapsuleShape* capsuleA, const glm::vec3& cubeCenter, float cubeSide, CollisionList& collisions);
|
||||||
|
|
||||||
} // namespace ShapeCollider
|
} // namespace ShapeCollider
|
||||||
|
|
||||||
#endif // hifi_ShapeCollider_h
|
#endif // hifi_ShapeCollider_h
|
||||||
|
|
|
@ -18,10 +18,10 @@
|
||||||
|
|
||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
|
|
||||||
|
#include <AABox.h>
|
||||||
#include <OctreeElement.h>
|
#include <OctreeElement.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "AABox.h"
|
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
|
|
||||||
|
|
|
@ -23,18 +23,18 @@
|
||||||
|
|
||||||
#include "ShapeColliderTests.h"
|
#include "ShapeColliderTests.h"
|
||||||
|
|
||||||
const glm::vec3 origin(0.f);
|
const glm::vec3 origin(0.0f);
|
||||||
static const glm::vec3 xAxis(1.f, 0.f, 0.f);
|
static const glm::vec3 xAxis(1.0f, 0.0f, 0.0f);
|
||||||
static const glm::vec3 yAxis(0.f, 1.f, 0.f);
|
static const glm::vec3 yAxis(0.0f, 1.0f, 0.0f);
|
||||||
static const glm::vec3 zAxis(0.f, 0.f, 1.f);
|
static const glm::vec3 zAxis(0.0f, 0.0f, 1.0f);
|
||||||
|
|
||||||
void ShapeColliderTests::sphereMissesSphere() {
|
void ShapeColliderTests::sphereMissesSphere() {
|
||||||
// non-overlapping spheres of unequal size
|
// non-overlapping spheres of unequal size
|
||||||
float radiusA = 7.f;
|
float radiusA = 7.0f;
|
||||||
float radiusB = 3.f;
|
float radiusB = 3.0f;
|
||||||
float alpha = 1.2f;
|
float alpha = 1.2f;
|
||||||
float beta = 1.3f;
|
float beta = 1.3f;
|
||||||
glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.f, 2.f, 3.f));
|
glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
|
||||||
float offsetDistance = alpha * radiusA + beta * radiusB;
|
float offsetDistance = alpha * radiusA + beta * radiusB;
|
||||||
|
|
||||||
SphereShape sphereA(radiusA, origin);
|
SphereShape sphereA(radiusA, origin);
|
||||||
|
@ -77,13 +77,13 @@ void ShapeColliderTests::sphereMissesSphere() {
|
||||||
|
|
||||||
void ShapeColliderTests::sphereTouchesSphere() {
|
void ShapeColliderTests::sphereTouchesSphere() {
|
||||||
// overlapping spheres of unequal size
|
// overlapping spheres of unequal size
|
||||||
float radiusA = 7.f;
|
float radiusA = 7.0f;
|
||||||
float radiusB = 3.f;
|
float radiusB = 3.0f;
|
||||||
float alpha = 0.2f;
|
float alpha = 0.2f;
|
||||||
float beta = 0.3f;
|
float beta = 0.3f;
|
||||||
glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.f, 2.f, 3.f));
|
glm::vec3 offsetDirection = glm::normalize(glm::vec3(1.0f, 2.0f, 3.0f));
|
||||||
float offsetDistance = alpha * radiusA + beta * radiusB;
|
float offsetDistance = alpha * radiusA + beta * radiusB;
|
||||||
float expectedPenetrationDistance = (1.f - alpha) * radiusA + (1.f - beta) * radiusB;
|
float expectedPenetrationDistance = (1.0f - alpha) * radiusA + (1.0f - beta) * radiusB;
|
||||||
glm::vec3 expectedPenetration = expectedPenetrationDistance * offsetDirection;
|
glm::vec3 expectedPenetration = expectedPenetrationDistance * offsetDirection;
|
||||||
|
|
||||||
SphereShape sphereA(radiusA, origin);
|
SphereShape sphereA(radiusA, origin);
|
||||||
|
@ -118,8 +118,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of sphereA
|
// contactPoint is on surface of sphereA
|
||||||
|
@ -129,8 +128,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,8 +148,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of sphereA
|
// contactPoint is on surface of sphereA
|
||||||
|
@ -161,8 +158,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +177,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
||||||
|
|
||||||
// give the capsule some arbirary transform
|
// give the capsule some arbirary transform
|
||||||
float angle = 37.8f;
|
float angle = 37.8f;
|
||||||
glm::vec3 axis = glm::normalize( glm::vec3(-7.f, 2.8f, 9.3f) );
|
glm::vec3 axis = glm::normalize( glm::vec3(-7.0f, 2.8f, 9.3f) );
|
||||||
glm::quat rotation = glm::angleAxis(angle, axis);
|
glm::quat rotation = glm::angleAxis(angle, axis);
|
||||||
glm::vec3 translation(15.1f, -27.1f, -38.6f);
|
glm::vec3 translation(15.1f, -27.1f, -38.6f);
|
||||||
capsuleB.setRotation(rotation);
|
capsuleB.setRotation(rotation);
|
||||||
|
@ -190,7 +186,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
||||||
CollisionList collisions(16);
|
CollisionList collisions(16);
|
||||||
|
|
||||||
// walk sphereA along the local yAxis next to, but not touching, capsuleB
|
// walk sphereA along the local yAxis next to, but not touching, capsuleB
|
||||||
glm::vec3 localStartPosition(radialOffset, axialOffset, 0.f);
|
glm::vec3 localStartPosition(radialOffset, axialOffset, 0.0f);
|
||||||
int numberOfSteps = 10;
|
int numberOfSteps = 10;
|
||||||
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
|
float delta = 1.3f * (totalRadius + halfHeightB) / (numberOfSteps - 1);
|
||||||
for (int i = 0; i < numberOfSteps; ++i) {
|
for (int i = 0; i < numberOfSteps; ++i) {
|
||||||
|
@ -224,10 +220,10 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
||||||
|
|
||||||
void ShapeColliderTests::sphereTouchesCapsule() {
|
void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
// overlapping sphere and capsule
|
// overlapping sphere and capsule
|
||||||
float radiusA = 2.f;
|
float radiusA = 2.0f;
|
||||||
float radiusB = 1.f;
|
float radiusB = 1.0f;
|
||||||
float totalRadius = radiusA + radiusB;
|
float totalRadius = radiusA + radiusB;
|
||||||
float halfHeightB = 2.f;
|
float halfHeightB = 2.0f;
|
||||||
float alpha = 0.5f;
|
float alpha = 0.5f;
|
||||||
float beta = 0.5f;
|
float beta = 0.5f;
|
||||||
float radialOffset = alpha * radiusA + beta * radiusB;
|
float radialOffset = alpha * radiusA + beta * radiusB;
|
||||||
|
@ -257,8 +253,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of sphereA
|
// contactPoint is on surface of sphereA
|
||||||
|
@ -267,8 +262,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// capsuleB collides with sphereA
|
// capsuleB collides with sphereA
|
||||||
|
@ -288,8 +282,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of capsuleB
|
// contactPoint is on surface of capsuleB
|
||||||
|
@ -300,8 +293,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // sphereA hits end cap at axis
|
{ // sphereA hits end cap at axis
|
||||||
|
@ -319,13 +311,12 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
|
|
||||||
// penetration points from sphereA into capsuleB
|
// penetration points from sphereA into capsuleB
|
||||||
CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
|
CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
|
||||||
glm::vec3 expectedPenetration = - ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis;
|
glm::vec3 expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
|
||||||
float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of sphereA
|
// contactPoint is on surface of sphereA
|
||||||
|
@ -334,8 +325,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// capsuleB collides with sphereA
|
// capsuleB collides with sphereA
|
||||||
|
@ -350,13 +340,12 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
|
|
||||||
// penetration points from sphereA into capsuleB
|
// penetration points from sphereA into capsuleB
|
||||||
collision = collisions.getCollision(numCollisions - 1);
|
collision = collisions.getCollision(numCollisions - 1);
|
||||||
expectedPenetration = ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis;
|
expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
|
||||||
inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of capsuleB
|
// contactPoint is on surface of capsuleB
|
||||||
|
@ -367,8 +356,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{ // sphereA hits start cap at axis
|
{ // sphereA hits start cap at axis
|
||||||
|
@ -386,13 +374,12 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
|
|
||||||
// penetration points from sphereA into capsuleB
|
// penetration points from sphereA into capsuleB
|
||||||
CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
|
CollisionInfo* collision = collisions.getCollision(numCollisions - 1);
|
||||||
glm::vec3 expectedPenetration = ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis;
|
glm::vec3 expectedPenetration = ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
|
||||||
float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
float inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of sphereA
|
// contactPoint is on surface of sphereA
|
||||||
|
@ -401,8 +388,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// capsuleB collides with sphereA
|
// capsuleB collides with sphereA
|
||||||
|
@ -417,13 +403,12 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
|
|
||||||
// penetration points from sphereA into capsuleB
|
// penetration points from sphereA into capsuleB
|
||||||
collision = collisions.getCollision(numCollisions - 1);
|
collision = collisions.getCollision(numCollisions - 1);
|
||||||
expectedPenetration = - ((1.f - alpha) * radiusA + (1.f - beta) * radiusB) * yAxis;
|
expectedPenetration = - ((1.0f - alpha) * radiusA + (1.0f - beta) * radiusB) * yAxis;
|
||||||
inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
inaccuracy = glm::length(collision->_penetration - expectedPenetration);
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// contactPoint is on surface of capsuleB
|
// contactPoint is on surface of capsuleB
|
||||||
|
@ -434,8 +419,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (collisions.size() != numCollisions) {
|
if (collisions.size() != numCollisions) {
|
||||||
|
@ -447,10 +431,10 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
||||||
|
|
||||||
void ShapeColliderTests::capsuleMissesCapsule() {
|
void ShapeColliderTests::capsuleMissesCapsule() {
|
||||||
// non-overlapping capsules
|
// non-overlapping capsules
|
||||||
float radiusA = 2.f;
|
float radiusA = 2.0f;
|
||||||
float halfHeightA = 3.f;
|
float halfHeightA = 3.0f;
|
||||||
float radiusB = 3.f;
|
float radiusB = 3.0f;
|
||||||
float halfHeightB = 4.f;
|
float halfHeightB = 4.0f;
|
||||||
|
|
||||||
float totalRadius = radiusA + radiusB;
|
float totalRadius = radiusA + radiusB;
|
||||||
float totalHalfLength = totalRadius + halfHeightA + halfHeightB;
|
float totalHalfLength = totalRadius + halfHeightA + halfHeightB;
|
||||||
|
@ -516,10 +500,10 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
||||||
|
|
||||||
void ShapeColliderTests::capsuleTouchesCapsule() {
|
void ShapeColliderTests::capsuleTouchesCapsule() {
|
||||||
// overlapping capsules
|
// overlapping capsules
|
||||||
float radiusA = 2.f;
|
float radiusA = 2.0f;
|
||||||
float halfHeightA = 3.f;
|
float halfHeightA = 3.0f;
|
||||||
float radiusB = 3.f;
|
float radiusB = 3.0f;
|
||||||
float halfHeightB = 4.f;
|
float halfHeightB = 4.0f;
|
||||||
|
|
||||||
float totalRadius = radiusA + radiusB;
|
float totalRadius = radiusA + radiusB;
|
||||||
float totalHalfLength = totalRadius + halfHeightA + halfHeightB;
|
float totalHalfLength = totalRadius + halfHeightA + halfHeightB;
|
||||||
|
@ -617,8 +601,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
<< " ERROR: bad penetration: expected = " << expectedPenetration
|
||||||
<< " actual = " << collision->_penetration
|
<< " actual = " << collision->_penetration;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 expectedContactPoint = capsuleA.getPosition() + radiusA * xAxis;
|
glm::vec3 expectedContactPoint = capsuleA.getPosition() + radiusA * xAxis;
|
||||||
|
@ -626,8 +609,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
||||||
if (fabs(inaccuracy) > EPSILON) {
|
if (fabs(inaccuracy) > EPSILON) {
|
||||||
std::cout << __FILE__ << ":" << __LINE__
|
std::cout << __FILE__ << ":" << __LINE__
|
||||||
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
<< " ERROR: bad contactPoint: expected = " << expectedContactPoint
|
||||||
<< " actual = " << collision->_contactPoint
|
<< " actual = " << collision->_contactPoint;
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// capsuleB vs capsuleA
|
// capsuleB vs capsuleA
|
||||||
|
@ -699,6 +681,116 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShapeColliderTests::sphereTouchesAACube() {
|
||||||
|
CollisionList collisions(16);
|
||||||
|
|
||||||
|
glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
|
||||||
|
float cubeSide = 2.0f;
|
||||||
|
|
||||||
|
float sphereRadius = 1.0f;
|
||||||
|
glm::vec3 sphereCenter(0.0f);
|
||||||
|
SphereShape sphere(sphereRadius, sphereCenter);
|
||||||
|
|
||||||
|
float sphereOffset = (0.5f * cubeSide + sphereRadius - 0.25f);
|
||||||
|
|
||||||
|
// top
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * yAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * yAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// left
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * xAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * xAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// forward
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * zAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// back
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * zAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (!ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShapeColliderTests::sphereMissesAACube() {
|
||||||
|
CollisionList collisions(16);
|
||||||
|
|
||||||
|
glm::vec3 cubeCenter(1.23f, 4.56f, 7.89f);
|
||||||
|
float cubeSide = 2.0f;
|
||||||
|
|
||||||
|
float sphereRadius = 1.0f;
|
||||||
|
glm::vec3 sphereCenter(0.0f);
|
||||||
|
SphereShape sphere(sphereRadius, sphereCenter);
|
||||||
|
|
||||||
|
float sphereOffset = (0.5f * cubeSide + sphereRadius + 0.25f);
|
||||||
|
|
||||||
|
// top
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * yAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * yAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// left
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * xAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// right
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * xAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// forward
|
||||||
|
sphereCenter = cubeCenter + sphereOffset * zAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// back
|
||||||
|
sphereCenter = cubeCenter - sphereOffset * zAxis;
|
||||||
|
sphere.setPosition(sphereCenter);
|
||||||
|
if (ShapeCollider::sphereAACube(&sphere, cubeCenter, cubeSide, collisions)){
|
||||||
|
std::cout << __FILE__ << ":" << __LINE__ << " ERROR: sphere should NOT collide with cube" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ShapeColliderTests::runAllTests() {
|
void ShapeColliderTests::runAllTests() {
|
||||||
sphereMissesSphere();
|
sphereMissesSphere();
|
||||||
|
@ -709,4 +801,7 @@ void ShapeColliderTests::runAllTests() {
|
||||||
|
|
||||||
capsuleMissesCapsule();
|
capsuleMissesCapsule();
|
||||||
capsuleTouchesCapsule();
|
capsuleTouchesCapsule();
|
||||||
|
|
||||||
|
sphereTouchesAACube();
|
||||||
|
sphereMissesAACube();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,9 @@ namespace ShapeColliderTests {
|
||||||
void capsuleMissesCapsule();
|
void capsuleMissesCapsule();
|
||||||
void capsuleTouchesCapsule();
|
void capsuleTouchesCapsule();
|
||||||
|
|
||||||
|
void sphereTouchesAACube();
|
||||||
|
void sphereMissesAACube();
|
||||||
|
|
||||||
void runAllTests();
|
void runAllTests();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue