mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 13:18:26 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into ossome
This commit is contained in:
commit
778e432cc4
68 changed files with 2203 additions and 1395 deletions
|
@ -16,7 +16,6 @@ add_subdirectory(animation-server)
|
||||||
add_subdirectory(assignment-client)
|
add_subdirectory(assignment-client)
|
||||||
add_subdirectory(domain-server)
|
add_subdirectory(domain-server)
|
||||||
add_subdirectory(interface)
|
add_subdirectory(interface)
|
||||||
add_subdirectory(injector)
|
|
||||||
add_subdirectory(pairing-server)
|
add_subdirectory(pairing-server)
|
||||||
add_subdirectory(space-server)
|
add_subdirectory(space-server)
|
||||||
add_subdirectory(voxel-edit)
|
add_subdirectory(voxel-edit)
|
|
@ -140,8 +140,6 @@ void Agent::run() {
|
||||||
|
|
||||||
int thisFrame = 0;
|
int thisFrame = 0;
|
||||||
|
|
||||||
bool firstDomainCheckIn = false;
|
|
||||||
|
|
||||||
while (!_shouldStop) {
|
while (!_shouldStop) {
|
||||||
|
|
||||||
// if we're not hearing from the domain-server we should stop running
|
// if we're not hearing from the domain-server we should stop running
|
||||||
|
@ -155,24 +153,34 @@ void Agent::run() {
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (firstDomainCheckIn) {
|
// find the audio-mixer in the NodeList so we can inject audio at it
|
||||||
// find the audio-mixer in the NodeList so we can inject audio at it
|
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
|
||||||
|
if (audioMixer && audioMixer->getActiveSocket()) {
|
||||||
emit willSendAudioDataCallback();
|
emit willSendAudioDataCallback();
|
||||||
|
|
||||||
if (audioMixer && scriptedAudioInjector.hasSamplesToInject()) {
|
if (scriptedAudioInjector.hasSamplesToInject()) {
|
||||||
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow();
|
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow();
|
||||||
if (usecToSleep > 0) {
|
if (usecToSleep > 0) {
|
||||||
usleep(usecToSleep);
|
usleep(usecToSleep);
|
||||||
}
|
}
|
||||||
|
|
||||||
scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getPublicSocket());
|
scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket());
|
||||||
|
|
||||||
// clear out the audio injector so that it doesn't re-send what we just sent
|
// clear out the audio injector so that it doesn't re-send what we just sent
|
||||||
scriptedAudioInjector.clear();
|
scriptedAudioInjector.clear();
|
||||||
}
|
}
|
||||||
|
} else if (audioMixer) {
|
||||||
|
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow();
|
||||||
|
if (usecToSleep > 0) {
|
||||||
|
usleep(usecToSleep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// don't have an active socket for the audio-mixer, ping it now
|
||||||
|
NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) {
|
||||||
// allow the scripter's call back to setup visual data
|
// allow the scripter's call back to setup visual data
|
||||||
emit willSendVisualDataCallback();
|
emit willSendVisualDataCallback();
|
||||||
|
|
||||||
|
@ -182,18 +190,15 @@ void Agent::run() {
|
||||||
// since we're in non-threaded mode, call process so that the packets are sent
|
// since we're in non-threaded mode, call process so that the packets are sent
|
||||||
voxelScripter.getVoxelPacketSender()->process();
|
voxelScripter.getVoxelPacketSender()->process();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine.hasUncaughtException()) {
|
if (engine.hasUncaughtException()) {
|
||||||
int line = engine.uncaughtExceptionLineNumber();
|
int line = engine.uncaughtExceptionLineNumber();
|
||||||
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)) {
|
while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)
|
||||||
if (!firstDomainCheckIn && receivedData[0] == PACKET_TYPE_DOMAIN) {
|
&& packetVersionMatch(receivedData)) {
|
||||||
firstDomainCheckIn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
|
NodeList::getInstance()->processNodeData((sockaddr*) &senderAddress, receivedData, receivedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
#include <StdDev.h>
|
#include <StdDev.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ void AudioMixer::run() {
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData());
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
|
|
||||||
if (Logging::shouldSendStats() && numStatCollections > 0) {
|
if (Logging::shouldSendStats() && numStatCollections > 0) {
|
||||||
// if we should be sending stats to Logstash send the appropriate average now
|
// if we should be sending stats to Logstash send the appropriate average now
|
||||||
|
@ -168,167 +169,166 @@ void AudioMixer::run() {
|
||||||
&& (otherNode != node || (otherNode == node && nodeRingBuffer->shouldLoopbackForNode()))) {
|
&& (otherNode != node || (otherNode == node && nodeRingBuffer->shouldLoopbackForNode()))) {
|
||||||
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) otherNode->getLinkedData();
|
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) otherNode->getLinkedData();
|
||||||
// based on our listen mode we will do this mixing...
|
// based on our listen mode we will do this mixing...
|
||||||
if (nodeRingBuffer->isListeningToNode(*otherNode)) {
|
|
||||||
float bearingRelativeAngleToSource = 0.0f;
|
float bearingRelativeAngleToSource = 0.0f;
|
||||||
float attenuationCoefficient = 1.0f;
|
float attenuationCoefficient = 1.0f;
|
||||||
int numSamplesDelay = 0;
|
int numSamplesDelay = 0;
|
||||||
float weakChannelAmplitudeRatio = 1.0f;
|
float weakChannelAmplitudeRatio = 1.0f;
|
||||||
|
|
||||||
|
stk::TwoPole* otherNodeTwoPole = NULL;
|
||||||
|
|
||||||
|
if (otherNode != node) {
|
||||||
|
|
||||||
stk::TwoPole* otherNodeTwoPole = NULL;
|
glm::vec3 listenerPosition = nodeRingBuffer->getPosition();
|
||||||
|
glm::vec3 relativePosition = otherNodeBuffer->getPosition() - nodeRingBuffer->getPosition();
|
||||||
|
glm::quat inverseOrientation = glm::inverse(nodeRingBuffer->getOrientation());
|
||||||
|
|
||||||
// only do axis/distance attenuation when in normal mode
|
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
|
||||||
if (otherNode != node && nodeRingBuffer->getListeningMode() == AudioRingBuffer::NORMAL) {
|
float radius = 0.0f;
|
||||||
|
|
||||||
glm::vec3 listenerPosition = nodeRingBuffer->getPosition();
|
if (otherNode->getType() == NODE_TYPE_AUDIO_INJECTOR) {
|
||||||
glm::vec3 relativePosition = otherNodeBuffer->getPosition() - nodeRingBuffer->getPosition();
|
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherNodeBuffer;
|
||||||
glm::quat inverseOrientation = glm::inverse(nodeRingBuffer->getOrientation());
|
radius = injectedBuffer->getRadius();
|
||||||
|
attenuationCoefficient *= injectedBuffer->getAttenuationRatio();
|
||||||
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
|
|
||||||
float radius = 0.0f;
|
|
||||||
|
|
||||||
if (otherNode->getType() == NODE_TYPE_AUDIO_INJECTOR) {
|
|
||||||
InjectedAudioRingBuffer* injectedBuffer = (InjectedAudioRingBuffer*) otherNodeBuffer;
|
|
||||||
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(otherNodeBuffer->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 / 90.0f));
|
|
||||||
|
|
||||||
// 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(glm::radians(bearingRelativeAngleToSource)));
|
|
||||||
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
|
||||||
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
|
||||||
|
|
||||||
// grab the TwoPole object for this source, add it if it doesn't exist
|
|
||||||
TwoPoleNodeMap& nodeTwoPoles = nodeRingBuffer->getTwoPoles();
|
|
||||||
TwoPoleNodeMap::iterator twoPoleIterator = nodeTwoPoles.find(otherNode->getNodeID());
|
|
||||||
|
|
||||||
if (twoPoleIterator == nodeTwoPoles.end()) {
|
|
||||||
// setup the freeVerb effect for this source for this client
|
|
||||||
otherNodeTwoPole = nodeTwoPoles[otherNode->getNodeID()] = new stk::TwoPole;
|
|
||||||
} else {
|
|
||||||
otherNodeTwoPole = twoPoleIterator->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calculate the reasonance for this TwoPole based on angle to source
|
|
||||||
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
|
|
||||||
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
|
|
||||||
|
|
||||||
otherNodeTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
|
|
||||||
TWO_POLE_MAX_FILTER_STRENGTH
|
|
||||||
* fabsf(bearingRelativeAngleToSource) / 180.0f,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t* sourceBuffer = otherNodeBuffer->getNextOutput();
|
if (radius == 0 || (distanceSquareToSource > radius * radius)) {
|
||||||
|
// this is either not a spherical source, or the listener is outside the sphere
|
||||||
int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f)
|
|
||||||
? clientSamples
|
if (radius > 0) {
|
||||||
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
// this is a spherical source - the distance used for the coefficient
|
||||||
int16_t* delayedChannel = (bearingRelativeAngleToSource > 0.0f)
|
// needs to be the closest point on the boundary to the source
|
||||||
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
|
||||||
: clientSamples;
|
|
||||||
|
|
||||||
int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer()
|
|
||||||
? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
|
|
||||||
: otherNodeBuffer->getNextOutput() - numSamplesDelay;
|
|
||||||
|
|
||||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
|
||||||
// load up the stkFrameBuffer with this source's samples
|
|
||||||
stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s];
|
|
||||||
}
|
|
||||||
|
|
||||||
// perform the TwoPole effect on the stkFrameBuffer
|
|
||||||
if (otherNodeTwoPole) {
|
|
||||||
otherNodeTwoPole->tick(stkFrameBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
|
||||||
if (s < numSamplesDelay) {
|
|
||||||
// pull the earlier sample for the delayed channel
|
|
||||||
int earlierSample = delaySamplePointer[s] * attenuationCoefficient * weakChannelAmplitudeRatio;
|
|
||||||
|
|
||||||
delayedChannel[s] = glm::clamp(delayedChannel[s] + earlierSample,
|
// ovveride the distance to the node with the distance to the point on the
|
||||||
MIN_SAMPLE_VALUE,
|
// boundary of the sphere
|
||||||
MAX_SAMPLE_VALUE);
|
distanceSquareToSource -= (radius * radius);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// calculate the angle delivery for off-axis attenuation
|
||||||
|
glm::vec3 rotatedListenerPosition = glm::inverse(otherNodeBuffer->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 / 90.0f));
|
||||||
|
|
||||||
|
// multiply the current attenuation coefficient by the calculated off axis coefficient
|
||||||
|
attenuationCoefficient *= offAxisCoefficient;
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t currentSample = stkFrameBuffer[s] * attenuationCoefficient;
|
glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition;
|
||||||
|
|
||||||
goodChannel[s] = glm::clamp(goodChannel[s] + currentSample,
|
const float DISTANCE_SCALE = 2.5f;
|
||||||
MIN_SAMPLE_VALUE,
|
const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f;
|
||||||
MAX_SAMPLE_VALUE);
|
const float DISTANCE_LOG_BASE = 2.5f;
|
||||||
|
const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE);
|
||||||
|
|
||||||
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
// calculate the distance coefficient using the distance to this node
|
||||||
int sumSample = delayedChannel[s + numSamplesDelay]
|
float distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR,
|
||||||
+ (currentSample * weakChannelAmplitudeRatio);
|
DISTANCE_SCALE_LOG +
|
||||||
delayedChannel[s + numSamplesDelay] = glm::clamp(sumSample,
|
(0.5f * logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1);
|
||||||
MIN_SAMPLE_VALUE,
|
distanceCoefficient = std::min(1.0f, distanceCoefficient);
|
||||||
MAX_SAMPLE_VALUE);
|
|
||||||
|
// 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(glm::radians(bearingRelativeAngleToSource)));
|
||||||
|
numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio;
|
||||||
|
weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio);
|
||||||
|
|
||||||
|
// grab the TwoPole object for this source, add it if it doesn't exist
|
||||||
|
TwoPoleNodeMap& nodeTwoPoles = nodeRingBuffer->getTwoPoles();
|
||||||
|
TwoPoleNodeMap::iterator twoPoleIterator = nodeTwoPoles.find(otherNode->getUUID());
|
||||||
|
|
||||||
|
if (twoPoleIterator == nodeTwoPoles.end()) {
|
||||||
|
// setup the freeVerb effect for this source for this client
|
||||||
|
otherNodeTwoPole = nodeTwoPoles[otherNode->getUUID()] = new stk::TwoPole;
|
||||||
|
} else {
|
||||||
|
otherNodeTwoPole = twoPoleIterator->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) {
|
// calculate the reasonance for this TwoPole based on angle to source
|
||||||
// this could be a delayed sample on the next pass
|
float TWO_POLE_CUT_OFF_FREQUENCY = 800.0f;
|
||||||
// so store the affected back in the ARB
|
float TWO_POLE_MAX_FILTER_STRENGTH = 0.4f;
|
||||||
otherNodeBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
|
|
||||||
}
|
otherNodeTwoPole->setResonance(TWO_POLE_CUT_OFF_FREQUENCY,
|
||||||
|
TWO_POLE_MAX_FILTER_STRENGTH
|
||||||
|
* fabsf(bearingRelativeAngleToSource) / 180.0f,
|
||||||
|
true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int16_t* sourceBuffer = otherNodeBuffer->getNextOutput();
|
||||||
|
|
||||||
|
int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f)
|
||||||
|
? clientSamples
|
||||||
|
: clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||||
|
int16_t* delayedChannel = (bearingRelativeAngleToSource > 0.0f)
|
||||||
|
? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL
|
||||||
|
: clientSamples;
|
||||||
|
|
||||||
|
int16_t* delaySamplePointer = otherNodeBuffer->getNextOutput() == otherNodeBuffer->getBuffer()
|
||||||
|
? otherNodeBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay
|
||||||
|
: otherNodeBuffer->getNextOutput() - numSamplesDelay;
|
||||||
|
|
||||||
|
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||||
|
// load up the stkFrameBuffer with this source's samples
|
||||||
|
stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s];
|
||||||
|
}
|
||||||
|
|
||||||
|
// perform the TwoPole effect on the stkFrameBuffer
|
||||||
|
if (otherNodeTwoPole) {
|
||||||
|
otherNodeTwoPole->tick(stkFrameBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) {
|
||||||
|
if (s < numSamplesDelay) {
|
||||||
|
// pull the earlier sample for the delayed channel
|
||||||
|
int earlierSample = delaySamplePointer[s] * attenuationCoefficient * weakChannelAmplitudeRatio;
|
||||||
|
|
||||||
|
delayedChannel[s] = glm::clamp(delayedChannel[s] + earlierSample,
|
||||||
|
MIN_SAMPLE_VALUE,
|
||||||
|
MAX_SAMPLE_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t currentSample = stkFrameBuffer[s] * attenuationCoefficient;
|
||||||
|
|
||||||
|
goodChannel[s] = glm::clamp(goodChannel[s] + currentSample,
|
||||||
|
MIN_SAMPLE_VALUE,
|
||||||
|
MAX_SAMPLE_VALUE);
|
||||||
|
|
||||||
|
if (s + numSamplesDelay < BUFFER_LENGTH_SAMPLES_PER_CHANNEL) {
|
||||||
|
int sumSample = delayedChannel[s + numSamplesDelay]
|
||||||
|
+ (currentSample * weakChannelAmplitudeRatio);
|
||||||
|
delayedChannel[s + numSamplesDelay] = glm::clamp(sumSample,
|
||||||
|
MIN_SAMPLE_VALUE,
|
||||||
|
MAX_SAMPLE_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) {
|
||||||
|
// this could be a delayed sample on the next pass
|
||||||
|
// so store the affected back in the ARB
|
||||||
|
otherNodeBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -357,13 +357,17 @@ void AudioMixer::run() {
|
||||||
packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO) {
|
packetData[0] == PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO) {
|
||||||
|
|
||||||
unsigned char* currentBuffer = packetData + numBytesForPacketHeader(packetData);
|
unsigned char* currentBuffer = packetData + numBytesForPacketHeader(packetData);
|
||||||
uint16_t sourceID;
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) currentBuffer, NUM_BYTES_RFC4122_UUID));
|
||||||
memcpy(&sourceID, currentBuffer, sizeof(sourceID));
|
|
||||||
|
|
||||||
Node* avatarNode = nodeList->addOrUpdateNode(nodeAddress,
|
Node* avatarNode = nodeList->addOrUpdateNode(nodeUUID,
|
||||||
nodeAddress,
|
|
||||||
NODE_TYPE_AGENT,
|
NODE_TYPE_AGENT,
|
||||||
sourceID);
|
nodeAddress,
|
||||||
|
nodeAddress);
|
||||||
|
|
||||||
|
// temp activation of public socket before server ping/reply is setup
|
||||||
|
if (!avatarNode->getActiveSocket()) {
|
||||||
|
avatarNode->activatePublicSocket();
|
||||||
|
}
|
||||||
|
|
||||||
nodeList->updateNodeWithData(nodeAddress, packetData, receivedBytes);
|
nodeList->updateNodeWithData(nodeAddress, packetData, receivedBytes);
|
||||||
|
|
||||||
|
@ -372,36 +376,18 @@ void AudioMixer::run() {
|
||||||
avatarNode->setAlive(false);
|
avatarNode->setAlive(false);
|
||||||
}
|
}
|
||||||
} else if (packetData[0] == PACKET_TYPE_INJECT_AUDIO) {
|
} else if (packetData[0] == PACKET_TYPE_INJECT_AUDIO) {
|
||||||
Node* matchingInjector = NULL;
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
|
||||||
|
NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
Node* matchingInjector = nodeList->addOrUpdateNode(nodeUUID,
|
||||||
if (node->getLinkedData()) {
|
NODE_TYPE_AUDIO_INJECTOR,
|
||||||
|
NULL,
|
||||||
InjectedAudioRingBuffer* ringBuffer = (InjectedAudioRingBuffer*) node->getLinkedData();
|
NULL);
|
||||||
if (memcmp(ringBuffer->getStreamIdentifier(),
|
|
||||||
packetData + numBytesForPacketHeader(packetData),
|
|
||||||
STREAM_IDENTIFIER_NUM_BYTES) == 0) {
|
|
||||||
// this is the matching stream, assign to matchingInjector and stop looking
|
|
||||||
matchingInjector = &*node;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!matchingInjector) {
|
|
||||||
matchingInjector = nodeList->addOrUpdateNode(NULL,
|
|
||||||
NULL,
|
|
||||||
NODE_TYPE_AUDIO_INJECTOR,
|
|
||||||
nodeList->getLastNodeID());
|
|
||||||
nodeList->increaseNodeID();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// give the new audio data to the matching injector node
|
// give the new audio data to the matching injector node
|
||||||
nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes);
|
nodeList->updateNodeWithData(matchingInjector, packetData, receivedBytes);
|
||||||
} else if (packetData[0] == PACKET_TYPE_PING || packetData[0] == PACKET_TYPE_DOMAIN) {
|
} else {
|
||||||
|
// let processNodeData handle it.
|
||||||
// If the packet is a ping, let processNodeData handle it.
|
|
||||||
nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
|
nodeList->processNodeData(nodeAddress, packetData, receivedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,11 @@
|
||||||
#include <Stk.h>
|
#include <Stk.h>
|
||||||
#include <TwoPole.h>
|
#include <TwoPole.h>
|
||||||
|
|
||||||
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
#include "PositionalAudioRingBuffer.h"
|
#include "PositionalAudioRingBuffer.h"
|
||||||
|
|
||||||
typedef std::map<uint16_t, stk::TwoPole*> TwoPoleNodeMap;
|
typedef std::map<QUuid, stk::TwoPole*> TwoPoleNodeMap;
|
||||||
|
|
||||||
class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
|
class AvatarAudioRingBuffer : public PositionalAudioRingBuffer {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "AvatarData.h"
|
#include "AvatarData.h"
|
||||||
|
|
||||||
|
@ -22,7 +23,9 @@
|
||||||
const char AVATAR_MIXER_LOGGING_NAME[] = "avatar-mixer";
|
const char AVATAR_MIXER_LOGGING_NAME[] = "avatar-mixer";
|
||||||
|
|
||||||
unsigned char* addNodeToBroadcastPacket(unsigned char *currentPosition, Node *nodeToAdd) {
|
unsigned char* addNodeToBroadcastPacket(unsigned char *currentPosition, Node *nodeToAdd) {
|
||||||
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
|
QByteArray rfcUUID = nodeToAdd->getUUID().toRfc4122();
|
||||||
|
memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size());
|
||||||
|
currentPosition += rfcUUID.size();
|
||||||
|
|
||||||
AvatarData *nodeData = (AvatarData *)nodeToAdd->getLinkedData();
|
AvatarData *nodeData = (AvatarData *)nodeToAdd->getLinkedData();
|
||||||
currentPosition += nodeData->getBroadcastData(currentPosition);
|
currentPosition += nodeData->getBroadcastData(currentPosition);
|
||||||
|
@ -43,7 +46,7 @@ void attachAvatarDataToNode(Node* newNode) {
|
||||||
// 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to
|
// 3) if we need to rate limit the amount of data we send, we can use a distance weighted "semi-random" function to
|
||||||
// determine which avatars are included in the packet stream
|
// determine which avatars are included in the packet stream
|
||||||
// 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful).
|
// 4) we should optimize the avatar data format to be more compact (100 bytes is pretty wasteful).
|
||||||
void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
|
void broadcastAvatarData(NodeList* nodeList, const QUuid& receiverUUID, sockaddr* receiverAddress) {
|
||||||
static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE];
|
static unsigned char broadcastPacketBuffer[MAX_PACKET_SIZE];
|
||||||
static unsigned char avatarDataBuffer[MAX_PACKET_SIZE];
|
static unsigned char avatarDataBuffer[MAX_PACKET_SIZE];
|
||||||
unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0];
|
unsigned char* broadcastPacket = (unsigned char*)&broadcastPacketBuffer[0];
|
||||||
|
@ -54,7 +57,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
|
||||||
|
|
||||||
// send back a packet with other active node data to this node
|
// send back a packet with other active node data to this node
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getLinkedData() && !socketMatch(nodeAddress, node->getActiveSocket())) {
|
if (node->getLinkedData() && node->getUUID() != receiverUUID) {
|
||||||
unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node);
|
unsigned char* avatarDataEndpoint = addNodeToBroadcastPacket((unsigned char*)&avatarDataBuffer[0], &*node);
|
||||||
int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer;
|
int avatarDataLength = avatarDataEndpoint - (unsigned char*)&avatarDataBuffer;
|
||||||
|
|
||||||
|
@ -65,7 +68,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
|
||||||
} else {
|
} else {
|
||||||
packetsSent++;
|
packetsSent++;
|
||||||
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
||||||
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
||||||
|
|
||||||
// reset the packet
|
// reset the packet
|
||||||
currentBufferPosition = broadcastPacket + numHeaderBytes;
|
currentBufferPosition = broadcastPacket + numHeaderBytes;
|
||||||
|
@ -80,7 +83,7 @@ void broadcastAvatarData(NodeList* nodeList, sockaddr* nodeAddress) {
|
||||||
}
|
}
|
||||||
packetsSent++;
|
packetsSent++;
|
||||||
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
//printf("packetsSent=%d packetLength=%d\n", packetsSent, packetLength);
|
||||||
nodeList->getNodeSocket()->send(nodeAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
nodeList->getNodeSocket()->send(receiverAddress, broadcastPacket, currentBufferPosition - broadcastPacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
AvatarMixer::AvatarMixer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes) {
|
||||||
|
@ -103,7 +106,7 @@ void AvatarMixer::run() {
|
||||||
|
|
||||||
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
unsigned char* packetData = new unsigned char[MAX_PACKET_SIZE];
|
||||||
|
|
||||||
uint16_t nodeID = 0;
|
QUuid nodeUUID;
|
||||||
Node* avatarNode = NULL;
|
Node* avatarNode = NULL;
|
||||||
|
|
||||||
timeval lastDomainServerCheckIn = {};
|
timeval lastDomainServerCheckIn = {};
|
||||||
|
@ -117,32 +120,31 @@ void AvatarMixer::run() {
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData());
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) &&
|
if (nodeList->getNodeSocket()->receive(&nodeAddress, packetData, &receivedBytes) &&
|
||||||
packetVersionMatch(packetData)) {
|
packetVersionMatch(packetData)) {
|
||||||
switch (packetData[0]) {
|
switch (packetData[0]) {
|
||||||
case PACKET_TYPE_HEAD_DATA:
|
case PACKET_TYPE_HEAD_DATA:
|
||||||
// grab the node ID from the packet
|
nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
|
||||||
unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
|
NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// add or update the node in our list
|
// add or update the node in our list
|
||||||
avatarNode = nodeList->addOrUpdateNode(&nodeAddress, &nodeAddress, NODE_TYPE_AGENT, nodeID);
|
avatarNode = nodeList->addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, &nodeAddress, &nodeAddress);
|
||||||
|
|
||||||
// parse positional data from an node
|
// parse positional data from an node
|
||||||
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
|
nodeList->updateNodeWithData(avatarNode, packetData, receivedBytes);
|
||||||
case PACKET_TYPE_INJECT_AUDIO:
|
case PACKET_TYPE_INJECT_AUDIO:
|
||||||
broadcastAvatarData(nodeList, &nodeAddress);
|
broadcastAvatarData(nodeList, nodeUUID, &nodeAddress);
|
||||||
break;
|
break;
|
||||||
case PACKET_TYPE_AVATAR_URLS:
|
case PACKET_TYPE_AVATAR_URLS:
|
||||||
case PACKET_TYPE_AVATAR_FACE_VIDEO:
|
case PACKET_TYPE_AVATAR_FACE_VIDEO:
|
||||||
// grab the node ID from the packet
|
nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData + numBytesForPacketHeader(packetData),
|
||||||
unpackNodeId(packetData + numBytesForPacketHeader(packetData), &nodeID);
|
NUM_BYTES_RFC4122_UUID));
|
||||||
|
|
||||||
// let everyone else know about the update
|
// let everyone else know about the update
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getActiveSocket() && node->getNodeID() != nodeID) {
|
if (node->getActiveSocket() && node->getUUID() != nodeUUID) {
|
||||||
nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
|
nodeList->getNodeSocket()->send(node->getActiveSocket(), packetData, receivedBytes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,6 +91,8 @@ void childClient() {
|
||||||
nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket));
|
nodeList->setDomainIP(QHostAddress((sockaddr*) &senderSocket));
|
||||||
nodeList->setDomainPort(ntohs(senderSocket.sin_port));
|
nodeList->setDomainPort(ntohs(senderSocket.sin_port));
|
||||||
|
|
||||||
|
nodeList->setOwnerUUID(deployedAssignment->getUUID());
|
||||||
|
|
||||||
qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str());
|
qDebug("Destination IP for assignment is %s\n", nodeList->getDomainIP().toString().toStdString().c_str());
|
||||||
|
|
||||||
// run the deployed assignment
|
// run the deployed assignment
|
||||||
|
|
|
@ -30,6 +30,18 @@ void DomainServer::setDomainServerInstance(DomainServer* domainServer) {
|
||||||
domainServerInstance = domainServer;
|
domainServerInstance = domainServer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QJsonObject jsonForSocket(sockaddr* socket) {
|
||||||
|
QJsonObject socketJSON;
|
||||||
|
|
||||||
|
if (socket->sa_family == AF_INET) {
|
||||||
|
sockaddr_in* socketIPv4 = (sockaddr_in*) socket;
|
||||||
|
socketJSON["ip"] = QString(inet_ntoa(socketIPv4->sin_addr));
|
||||||
|
socketJSON["port"] = (int) ntohs(socketIPv4->sin_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return socketJSON;
|
||||||
|
}
|
||||||
|
|
||||||
int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
|
int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
|
||||||
const struct mg_request_info* ri = mg_get_request_info(connection);
|
const struct mg_request_info* ri = mg_get_request_info(connection);
|
||||||
|
|
||||||
|
@ -67,14 +79,9 @@ int DomainServer::civetwebRequestHandler(struct mg_connection *connection) {
|
||||||
QString assignmentUUID = uuidStringWithoutCurlyBraces(((Assignment*) node->getLinkedData())->getUUID());
|
QString assignmentUUID = uuidStringWithoutCurlyBraces(((Assignment*) node->getLinkedData())->getUUID());
|
||||||
assignedNodeJSON[ASSIGNMENT_JSON_UUID_KEY] = assignmentUUID;
|
assignedNodeJSON[ASSIGNMENT_JSON_UUID_KEY] = assignmentUUID;
|
||||||
|
|
||||||
QJsonObject nodePublicSocketJSON;
|
// add the node socket information
|
||||||
|
assignedNodeJSON["public"] = jsonForSocket(node->getPublicSocket());
|
||||||
// add the public socket information
|
assignedNodeJSON["local"] = jsonForSocket(node->getLocalSocket());
|
||||||
sockaddr_in* nodePublicSocket = (sockaddr_in*) node->getPublicSocket();
|
|
||||||
nodePublicSocketJSON["ip"] = QString(inet_ntoa(nodePublicSocket->sin_addr));
|
|
||||||
nodePublicSocketJSON["port"] = (int) ntohs(nodePublicSocket->sin_port);
|
|
||||||
|
|
||||||
assignedNodeJSON["public"] = nodePublicSocketJSON;
|
|
||||||
|
|
||||||
// re-format the type name so it matches the target name
|
// re-format the type name so it matches the target name
|
||||||
QString nodeTypeName(node->getTypeName());
|
QString nodeTypeName(node->getTypeName());
|
||||||
|
@ -154,7 +161,7 @@ void DomainServer::civetwebUploadHandler(struct mg_connection *connection, const
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::nodeAdded(Node* node) {
|
void DomainServer::nodeAdded(Node* node) {
|
||||||
NodeList::getInstance()->increaseNodeID();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DomainServer::nodeKilled(Node* node) {
|
void DomainServer::nodeKilled(Node* node) {
|
||||||
|
@ -187,7 +194,11 @@ void DomainServer::nodeKilled(Node* node) {
|
||||||
unsigned char* DomainServer::addNodeToBroadcastPacket(unsigned char* currentPosition, Node* nodeToAdd) {
|
unsigned char* DomainServer::addNodeToBroadcastPacket(unsigned char* currentPosition, Node* nodeToAdd) {
|
||||||
*currentPosition++ = nodeToAdd->getType();
|
*currentPosition++ = nodeToAdd->getType();
|
||||||
|
|
||||||
currentPosition += packNodeId(currentPosition, nodeToAdd->getNodeID());
|
|
||||||
|
QByteArray rfcUUID = nodeToAdd->getUUID().toRfc4122();
|
||||||
|
memcpy(currentPosition, rfcUUID.constData(), rfcUUID.size());
|
||||||
|
currentPosition += rfcUUID.size();
|
||||||
|
|
||||||
currentPosition += packSocket(currentPosition, nodeToAdd->getPublicSocket());
|
currentPosition += packSocket(currentPosition, nodeToAdd->getPublicSocket());
|
||||||
currentPosition += packSocket(currentPosition, nodeToAdd->getLocalSocket());
|
currentPosition += packSocket(currentPosition, nodeToAdd->getLocalSocket());
|
||||||
|
|
||||||
|
@ -291,11 +302,8 @@ void DomainServer::prepopulateStaticAssignmentFile() {
|
||||||
_staticAssignmentFile.close();
|
_staticAssignmentFile.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
Assignment* DomainServer::matchingStaticAssignmentForCheckIn(NODE_TYPE nodeType, const uchar* checkInData) {
|
Assignment* DomainServer::matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NODE_TYPE nodeType) {
|
||||||
// pull the UUID passed with the check in
|
// pull the UUID passed with the check in
|
||||||
QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) checkInData + numBytesForPacketHeader(checkInData) +
|
|
||||||
sizeof(NODE_TYPE),
|
|
||||||
NUM_BYTES_RFC4122_UUID));
|
|
||||||
|
|
||||||
if (_hasCompletedRestartHold) {
|
if (_hasCompletedRestartHold) {
|
||||||
_assignmentQueueMutex.lock();
|
_assignmentQueueMutex.lock();
|
||||||
|
@ -395,19 +403,14 @@ void DomainServer::removeAssignmentFromQueue(Assignment* removableAssignment) {
|
||||||
|
|
||||||
bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket,
|
bool DomainServer::checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket,
|
||||||
sockaddr* nodeLocalSocket,
|
sockaddr* nodeLocalSocket,
|
||||||
const uchar* checkInData) {
|
const QUuid& checkInUUID) {
|
||||||
// pull the UUID passed with the check in
|
|
||||||
QUuid checkInUUID = QUuid::fromRfc4122(QByteArray((const char*) checkInData + numBytesForPacketHeader(checkInData) +
|
|
||||||
sizeof(NODE_TYPE),
|
|
||||||
NUM_BYTES_RFC4122_UUID));
|
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
|
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getLinkedData()
|
if (node->getLinkedData()
|
||||||
&& socketMatch(node->getPublicSocket(), nodePublicSocket)
|
&& socketMatch(node->getPublicSocket(), nodePublicSocket)
|
||||||
&& socketMatch(node->getLocalSocket(), nodeLocalSocket)
|
&& socketMatch(node->getLocalSocket(), nodeLocalSocket)
|
||||||
&& ((Assignment*) node->getLinkedData())->getUUID() == checkInUUID) {
|
&& node->getUUID() == checkInUUID) {
|
||||||
// this is a matching existing node if the public socket, local socket, and UUID match
|
// this is a matching existing node if the public socket, local socket, and UUID match
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -480,11 +483,10 @@ int DomainServer::run() {
|
||||||
unsigned char* currentBufferPos;
|
unsigned char* currentBufferPos;
|
||||||
unsigned char* startPointer;
|
unsigned char* startPointer;
|
||||||
|
|
||||||
sockaddr_in nodePublicAddress, nodeLocalAddress, replyDestinationSocket;
|
sockaddr_in senderAddress, nodePublicAddress, nodeLocalAddress;
|
||||||
|
nodePublicAddress.sin_family = AF_INET;
|
||||||
nodeLocalAddress.sin_family = AF_INET;
|
nodeLocalAddress.sin_family = AF_INET;
|
||||||
|
|
||||||
in_addr_t serverLocalAddress = getLocalAddress();
|
|
||||||
|
|
||||||
nodeList->startSilentNodeRemovalThread();
|
nodeList->startSilentNodeRemovalThread();
|
||||||
|
|
||||||
if (!_staticAssignmentFile.exists() || _voxelServerConfig) {
|
if (!_staticAssignmentFile.exists() || _voxelServerConfig) {
|
||||||
|
@ -507,7 +509,7 @@ int DomainServer::run() {
|
||||||
gettimeofday(&startTime, NULL);
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
while (nodeList->getNodeSocket()->receive((sockaddr *)&nodePublicAddress, packetData, &receivedBytes) &&
|
while (nodeList->getNodeSocket()->receive((sockaddr *)&senderAddress, packetData, &receivedBytes) &&
|
||||||
packetVersionMatch(packetData)) {
|
packetVersionMatch(packetData)) {
|
||||||
if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) {
|
if (packetData[0] == PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY || packetData[0] == PACKET_TYPE_DOMAIN_LIST_REQUEST) {
|
||||||
// this is an RFD or domain list request packet, and there is a version match
|
// this is an RFD or domain list request packet, and there is a version match
|
||||||
|
@ -515,20 +517,30 @@ int DomainServer::run() {
|
||||||
int numBytesSenderHeader = numBytesForPacketHeader(packetData);
|
int numBytesSenderHeader = numBytesForPacketHeader(packetData);
|
||||||
|
|
||||||
nodeType = *(packetData + numBytesSenderHeader);
|
nodeType = *(packetData + numBytesSenderHeader);
|
||||||
int numBytesSocket = unpackSocket(packetData + numBytesSenderHeader + sizeof(NODE_TYPE),
|
|
||||||
(sockaddr*) &nodeLocalAddress);
|
|
||||||
|
|
||||||
replyDestinationSocket = nodePublicAddress;
|
int packetIndex = numBytesSenderHeader + sizeof(NODE_TYPE);
|
||||||
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray(((char*) packetData + packetIndex), NUM_BYTES_RFC4122_UUID));
|
||||||
|
packetIndex += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// check the node public address
|
int numBytesPrivateSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodePublicAddress);
|
||||||
// if it matches our local address
|
packetIndex += numBytesPrivateSocket;
|
||||||
// or if it's the loopback address we're on the same box
|
|
||||||
if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress ||
|
if (nodePublicAddress.sin_addr.s_addr == 0) {
|
||||||
nodePublicAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
|
// this node wants to use us its STUN server
|
||||||
|
// so set the node public address to whatever we perceive the public address to be
|
||||||
|
|
||||||
nodePublicAddress.sin_addr.s_addr = 0;
|
nodePublicAddress = senderAddress;
|
||||||
|
|
||||||
|
// if the sender is on our box then leave its public address to 0 so that
|
||||||
|
// other users attempt to reach it on the same address they have for the domain-server
|
||||||
|
if (senderAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
|
||||||
|
nodePublicAddress.sin_addr.s_addr = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int numBytesPublicSocket = unpackSocket(packetData + packetIndex, (sockaddr*) &nodeLocalAddress);
|
||||||
|
packetIndex += numBytesPublicSocket;
|
||||||
|
|
||||||
const char STATICALLY_ASSIGNED_NODES[3] = {
|
const char STATICALLY_ASSIGNED_NODES[3] = {
|
||||||
NODE_TYPE_AUDIO_MIXER,
|
NODE_TYPE_AUDIO_MIXER,
|
||||||
NODE_TYPE_AVATAR_MIXER,
|
NODE_TYPE_AVATAR_MIXER,
|
||||||
|
@ -537,16 +549,16 @@ int DomainServer::run() {
|
||||||
|
|
||||||
Assignment* matchingStaticAssignment = NULL;
|
Assignment* matchingStaticAssignment = NULL;
|
||||||
|
|
||||||
if (memchr(STATICALLY_ASSIGNED_NODES, nodeType, sizeof(STATICALLY_ASSIGNED_NODES)) == NULL ||
|
if (memchr(STATICALLY_ASSIGNED_NODES, nodeType, sizeof(STATICALLY_ASSIGNED_NODES)) == NULL
|
||||||
((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeType, packetData)) ||
|
|| ((matchingStaticAssignment = matchingStaticAssignmentForCheckIn(nodeUUID, nodeType))
|
||||||
checkInWithUUIDMatchesExistingNode((sockaddr*) &nodePublicAddress,
|
|| checkInWithUUIDMatchesExistingNode((sockaddr*) &nodePublicAddress,
|
||||||
(sockaddr*) &nodeLocalAddress,
|
(sockaddr*) &nodeLocalAddress,
|
||||||
packetData))) {
|
nodeUUID)))
|
||||||
|
{
|
||||||
Node* checkInNode = nodeList->addOrUpdateNode((sockaddr*) &nodePublicAddress,
|
Node* checkInNode = nodeList->addOrUpdateNode(nodeUUID,
|
||||||
(sockaddr*) &nodeLocalAddress,
|
|
||||||
nodeType,
|
nodeType,
|
||||||
nodeList->getLastNodeID());
|
(sockaddr*) &nodePublicAddress,
|
||||||
|
(sockaddr*) &nodeLocalAddress);
|
||||||
|
|
||||||
if (matchingStaticAssignment) {
|
if (matchingStaticAssignment) {
|
||||||
// this was a newly added node with a matching static assignment
|
// this was a newly added node with a matching static assignment
|
||||||
|
@ -568,12 +580,7 @@ int DomainServer::run() {
|
||||||
currentBufferPos = broadcastPacket + numHeaderBytes;
|
currentBufferPos = broadcastPacket + numHeaderBytes;
|
||||||
startPointer = currentBufferPos;
|
startPointer = currentBufferPos;
|
||||||
|
|
||||||
int numBytesUUID = (nodeType == NODE_TYPE_AUDIO_MIXER || nodeType == NODE_TYPE_AVATAR_MIXER)
|
unsigned char* nodeTypesOfInterest = packetData + packetIndex + sizeof(unsigned char);
|
||||||
? NUM_BYTES_RFC4122_UUID
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
unsigned char* nodeTypesOfInterest = packetData + numBytesSenderHeader + numBytesUUID +
|
|
||||||
sizeof(NODE_TYPE) + numBytesSocket + sizeof(unsigned char);
|
|
||||||
int numInterestTypes = *(nodeTypesOfInterest - 1);
|
int numInterestTypes = *(nodeTypesOfInterest - 1);
|
||||||
|
|
||||||
if (numInterestTypes > 0) {
|
if (numInterestTypes > 0) {
|
||||||
|
@ -595,11 +602,8 @@ int DomainServer::run() {
|
||||||
uint64_t timeNow = usecTimestampNow();
|
uint64_t timeNow = usecTimestampNow();
|
||||||
checkInNode->setLastHeardMicrostamp(timeNow);
|
checkInNode->setLastHeardMicrostamp(timeNow);
|
||||||
|
|
||||||
// add the node ID to the end of the pointer
|
|
||||||
currentBufferPos += packNodeId(currentBufferPos, checkInNode->getNodeID());
|
|
||||||
|
|
||||||
// send the constructed list back to this node
|
// send the constructed list back to this node
|
||||||
nodeList->getNodeSocket()->send((sockaddr*)&replyDestinationSocket,
|
nodeList->getNodeSocket()->send((sockaddr*)&senderAddress,
|
||||||
broadcastPacket,
|
broadcastPacket,
|
||||||
(currentBufferPos - startPointer) + numHeaderBytes);
|
(currentBufferPos - startPointer) + numHeaderBytes);
|
||||||
}
|
}
|
||||||
|
@ -623,7 +627,7 @@ int DomainServer::run() {
|
||||||
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT);
|
int numHeaderBytes = populateTypeAndVersion(broadcastPacket, PACKET_TYPE_CREATE_ASSIGNMENT);
|
||||||
int numAssignmentBytes = assignmentToDeploy->packToBuffer(broadcastPacket + numHeaderBytes);
|
int numAssignmentBytes = assignmentToDeploy->packToBuffer(broadcastPacket + numHeaderBytes);
|
||||||
|
|
||||||
nodeList->getNodeSocket()->send((sockaddr*) &nodePublicAddress,
|
nodeList->getNodeSocket()->send((sockaddr*) &senderAddress,
|
||||||
broadcastPacket,
|
broadcastPacket,
|
||||||
numHeaderBytes + numAssignmentBytes);
|
numHeaderBytes + numAssignmentBytes);
|
||||||
}
|
}
|
||||||
|
@ -637,20 +641,11 @@ int DomainServer::run() {
|
||||||
|
|
||||||
qDebug() << "Received a create assignment -" << *createAssignment << "\n";
|
qDebug() << "Received a create assignment -" << *createAssignment << "\n";
|
||||||
|
|
||||||
// check the node public address
|
|
||||||
// if it matches our local address
|
|
||||||
// or if it's the loopback address we're on the same box
|
|
||||||
if (nodePublicAddress.sin_addr.s_addr == serverLocalAddress ||
|
|
||||||
nodePublicAddress.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
|
|
||||||
|
|
||||||
nodePublicAddress.sin_addr.s_addr = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we have a matching node with the UUID packed with the assignment
|
// make sure we have a matching node with the UUID packed with the assignment
|
||||||
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
// if the node has sent no types of interest, assume they want nothing but their own ID back
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getLinkedData()
|
if (node->getLinkedData()
|
||||||
&& socketMatch((sockaddr*) &nodePublicAddress, node->getPublicSocket())
|
&& socketMatch((sockaddr*) &senderAddress, node->getPublicSocket())
|
||||||
&& ((Assignment*) node->getLinkedData())->getUUID() == createAssignment->getUUID()) {
|
&& ((Assignment*) node->getLinkedData())->getUUID() == createAssignment->getUUID()) {
|
||||||
|
|
||||||
// give the create assignment a new UUID
|
// give the create assignment a new UUID
|
||||||
|
|
|
@ -42,10 +42,10 @@ private:
|
||||||
static DomainServer* domainServerInstance;
|
static DomainServer* domainServerInstance;
|
||||||
|
|
||||||
void prepopulateStaticAssignmentFile();
|
void prepopulateStaticAssignmentFile();
|
||||||
Assignment* matchingStaticAssignmentForCheckIn(NODE_TYPE nodeType, const uchar* checkInUUID);
|
Assignment* matchingStaticAssignmentForCheckIn(const QUuid& checkInUUID, NODE_TYPE nodeType);
|
||||||
Assignment* deployableAssignmentForRequest(Assignment& requestAssignment);
|
Assignment* deployableAssignmentForRequest(Assignment& requestAssignment);
|
||||||
void removeAssignmentFromQueue(Assignment* removableAssignment);
|
void removeAssignmentFromQueue(Assignment* removableAssignment);
|
||||||
bool checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, sockaddr* nodeLocalSocket, const uchar* checkInData);
|
bool checkInWithUUIDMatchesExistingNode(sockaddr* nodePublicSocket, sockaddr* nodeLocalSocket, const QUuid& checkInUUI);
|
||||||
void possiblyAddStaticAssignmentsBackToQueueAfterRestart(timeval* startTime);
|
void possiblyAddStaticAssignmentsBackToQueueAfterRestart(timeval* startTime);
|
||||||
|
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
cmake_minimum_required(VERSION 2.8)
|
|
||||||
|
|
||||||
set(ROOT_DIR ..)
|
|
||||||
set(MACRO_DIR ${ROOT_DIR}/cmake/macros)
|
|
||||||
|
|
||||||
# setup for find modules
|
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/")
|
|
||||||
|
|
||||||
set(TARGET_NAME injector)
|
|
||||||
|
|
||||||
include(${MACRO_DIR}/SetupHifiProject.cmake)
|
|
||||||
setup_hifi_project(${TARGET_NAME} TRUE)
|
|
||||||
|
|
||||||
# set up the external glm library
|
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
|
||||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
|
||||||
|
|
||||||
# link the shared hifi library
|
|
||||||
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
|
||||||
link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR})
|
|
||||||
link_hifi_library(avatars ${TARGET_NAME} ${ROOT_DIR})
|
|
|
@ -1,244 +0,0 @@
|
||||||
//
|
|
||||||
// main.cpp
|
|
||||||
// Audio Injector
|
|
||||||
//
|
|
||||||
// Created by Leonardo Murillo on 3/5/13.
|
|
||||||
// Copyright (c) 2013 Leonardo Murillo. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sstream>
|
|
||||||
|
|
||||||
#include <NodeList.h>
|
|
||||||
#include <NodeTypes.h>
|
|
||||||
#include <AvatarData.h>
|
|
||||||
#include <SharedUtil.h>
|
|
||||||
#include <PacketHeaders.h>
|
|
||||||
#include <UDPSocket.h>
|
|
||||||
#include <AudioInjector.h>
|
|
||||||
#include <AudioInjectionManager.h>
|
|
||||||
|
|
||||||
const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15;
|
|
||||||
|
|
||||||
const int DEFAULT_INJECTOR_VOLUME = 0xFF;
|
|
||||||
|
|
||||||
enum {
|
|
||||||
INJECTOR_POSITION_X,
|
|
||||||
INJECTOR_POSITION_Y,
|
|
||||||
INJECTOR_POSITION_Z,
|
|
||||||
INJECTOR_YAW
|
|
||||||
};
|
|
||||||
|
|
||||||
// Command line parameter defaults
|
|
||||||
bool shouldLoopAudio = true;
|
|
||||||
bool hasInjectedAudioOnce = false;
|
|
||||||
float sleepIntervalMin = 1.00;
|
|
||||||
float sleepIntervalMax = 2.00;
|
|
||||||
char *sourceAudioFile = NULL;
|
|
||||||
const char *allowedParameters = ":sc::a::f::t::r:l";
|
|
||||||
float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f};
|
|
||||||
unsigned char volume = DEFAULT_INJECTOR_VOLUME;
|
|
||||||
float triggerDistance = 0.0f;
|
|
||||||
float radius = 0.0f;
|
|
||||||
bool wantsLocalDomain = false;
|
|
||||||
|
|
||||||
|
|
||||||
void usage(void) {
|
|
||||||
std::cout << "High Fidelity - Interface audio injector" << std::endl;
|
|
||||||
std::cout << " -s Single play mode. If not specified will default to constant loop." << std::endl;
|
|
||||||
std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl;
|
|
||||||
std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl;
|
|
||||||
std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl;
|
|
||||||
std::cout << " -t FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl;
|
|
||||||
std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl;
|
|
||||||
std::cout << " -l Local domain mode." << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool processParameters(int parameterCount, char* parameterData[]) {
|
|
||||||
int p;
|
|
||||||
while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) {
|
|
||||||
switch (p) {
|
|
||||||
case 's':
|
|
||||||
::shouldLoopAudio = false;
|
|
||||||
std::cout << "[DEBUG] Single play mode enabled" << std::endl;
|
|
||||||
break;
|
|
||||||
case 'f':
|
|
||||||
::sourceAudioFile = optarg;
|
|
||||||
std::cout << "[DEBUG] Opening file: " << sourceAudioFile << std::endl;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
{
|
|
||||||
std::istringstream ss(optarg);
|
|
||||||
std::string token;
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
while (std::getline(ss, token, ',')) {
|
|
||||||
::floatArguments[i] = atof(token.c_str());
|
|
||||||
++i;
|
|
||||||
if (i == 4) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'a':
|
|
||||||
::volume = atoi(optarg);
|
|
||||||
std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl;
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
::triggerDistance = atof(optarg);
|
|
||||||
std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl;
|
|
||||||
break;
|
|
||||||
case 'r':
|
|
||||||
::radius = atof(optarg);
|
|
||||||
std::cout << "[DEBUG] Injector radius: " << optarg << std::endl;
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
::wantsLocalDomain = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
usage();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
void createAvatarDataForNode(Node* node) {
|
|
||||||
if (!node->getLinkedData()) {
|
|
||||||
node->setLinkedData(new AvatarData(node));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
|
|
||||||
// new seed for random audio sleep times
|
|
||||||
srand(time(0));
|
|
||||||
|
|
||||||
int AUDIO_UDP_SEND_PORT = 1500 + (rand() % (int)(1500 - 2000 + 1));
|
|
||||||
|
|
||||||
if (processParameters(argc, argv)) {
|
|
||||||
if (::sourceAudioFile == NULL) {
|
|
||||||
std::cout << "[FATAL] Source audio file not specified" << std::endl;
|
|
||||||
exit(-1);
|
|
||||||
} else {
|
|
||||||
AudioInjector injector(sourceAudioFile);
|
|
||||||
|
|
||||||
// create an NodeList instance to handle communication with other nodes
|
|
||||||
NodeList* nodeList = NodeList::createInstance(NODE_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT);
|
|
||||||
|
|
||||||
if (::wantsLocalDomain) {
|
|
||||||
printf("Local Domain MODE!\n");
|
|
||||||
nodeList->setDomainIPToLocalhost();
|
|
||||||
}
|
|
||||||
|
|
||||||
// start the node list thread that will kill off nodes when they stop talking
|
|
||||||
nodeList->startSilentNodeRemovalThread();
|
|
||||||
|
|
||||||
injector.setPosition(glm::vec3(::floatArguments[INJECTOR_POSITION_X],
|
|
||||||
::floatArguments[INJECTOR_POSITION_Y],
|
|
||||||
::floatArguments[INJECTOR_POSITION_Z]));
|
|
||||||
injector.setOrientation(glm::quat(glm::vec3(0.0f, ::floatArguments[INJECTOR_YAW], 0.0f)));
|
|
||||||
injector.setVolume(::volume);
|
|
||||||
|
|
||||||
if (::radius > 0) {
|
|
||||||
// if we were passed a cube side length, give that to the injector
|
|
||||||
injector.setRadius(::radius);
|
|
||||||
}
|
|
||||||
|
|
||||||
// register the callback for node data creation
|
|
||||||
nodeList->linkedDataCreateCallback = createAvatarDataForNode;
|
|
||||||
|
|
||||||
timeval lastSend = {};
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO);
|
|
||||||
unsigned char* broadcastPacket = new unsigned char[numBytesPacketHeader];
|
|
||||||
|
|
||||||
timeval lastDomainServerCheckIn = {};
|
|
||||||
|
|
||||||
sockaddr senderAddress;
|
|
||||||
ssize_t bytesReceived;
|
|
||||||
unsigned char incomingPacket[MAX_PACKET_SIZE];
|
|
||||||
|
|
||||||
// the audio injector needs to know about the avatar mixer and the audio mixer
|
|
||||||
const char INJECTOR_NODES_OF_INTEREST[] = {NODE_TYPE_AUDIO_MIXER, NODE_TYPE_AVATAR_MIXER};
|
|
||||||
|
|
||||||
int bytesNodesOfInterest = (::triggerDistance > 0)
|
|
||||||
? sizeof(INJECTOR_NODES_OF_INTEREST)
|
|
||||||
: sizeof(INJECTOR_NODES_OF_INTEREST) - 1;
|
|
||||||
|
|
||||||
NodeList::getInstance()->setNodeTypesOfInterest(INJECTOR_NODES_OF_INTEREST, bytesNodesOfInterest);
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn();
|
|
||||||
}
|
|
||||||
|
|
||||||
while (nodeList->getNodeSocket()->receive(&senderAddress, incomingPacket, &bytesReceived) &&
|
|
||||||
packetVersionMatch(incomingPacket)) {
|
|
||||||
switch (incomingPacket[0]) {
|
|
||||||
case PACKET_TYPE_BULK_AVATAR_DATA: // this is the positional data for other nodes
|
|
||||||
// pass that off to the nodeList processBulkNodeData method
|
|
||||||
nodeList->processBulkNodeData(&senderAddress, incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
// have the nodeList handle list of nodes from DS, replies from other nodes, etc.
|
|
||||||
nodeList->processNodeData(&senderAddress, incomingPacket, bytesReceived);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (::triggerDistance) {
|
|
||||||
if (!injector.isInjectingAudio()) {
|
|
||||||
// enumerate the other nodes to decide if one is close enough that we should inject
|
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
|
||||||
AvatarData* avatarData = (AvatarData*) node->getLinkedData();
|
|
||||||
|
|
||||||
if (avatarData) {
|
|
||||||
glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition();
|
|
||||||
|
|
||||||
if (glm::dot(tempVector, tempVector) <= ::triggerDistance) {
|
|
||||||
// use the AudioInjectionManager to thread this injector
|
|
||||||
AudioInjectionManager::threadInjector(&injector);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the current avatar mixer
|
|
||||||
Node* avatarMixer = nodeList->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
|
|
||||||
|
|
||||||
// make sure we actually have an avatar mixer with an active socket
|
|
||||||
if (avatarMixer && avatarMixer->getActiveSocket() != NULL
|
|
||||||
&& (usecTimestampNow() - usecTimestamp(&lastSend) > AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS)) {
|
|
||||||
|
|
||||||
// update the lastSend timeval to the current time
|
|
||||||
gettimeofday(&lastSend, NULL);
|
|
||||||
|
|
||||||
// use the UDPSocket instance attached to our node list to ask avatar mixer for a list of avatars
|
|
||||||
nodeList->getNodeSocket()->send(avatarMixer->getActiveSocket(),
|
|
||||||
broadcastPacket,
|
|
||||||
numBytesPacketHeader);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (!injector.isInjectingAudio() && (::shouldLoopAudio || !::hasInjectedAudioOnce)) {
|
|
||||||
// use the AudioInjectionManager to thread this injector
|
|
||||||
AudioInjectionManager::threadInjector(&injector);
|
|
||||||
::hasInjectedAudioOnce = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// stop the node list's threads
|
|
||||||
nodeList->stopSilentNodeRemovalThread();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <PairingHandler.h>
|
#include <PairingHandler.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
|
#include <UUID.h>
|
||||||
#include <VoxelSceneStats.h>
|
#include <VoxelSceneStats.h>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
@ -500,7 +500,7 @@ void Application::controlledBroadcastToNodes(unsigned char* broadcastData, size_
|
||||||
if (nodeTypes[i] == NODE_TYPE_VOXEL_SERVER && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
if (nodeTypes[i] == NODE_TYPE_VOXEL_SERVER && !Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the broadcast for one type
|
// Perform the broadcast for one type
|
||||||
int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(broadcastData, dataBytes, & nodeTypes[i], 1);
|
int nReceivingNodes = NodeList::getInstance()->broadcastToNodes(broadcastData, dataBytes, & nodeTypes[i], 1);
|
||||||
|
|
||||||
|
@ -1160,8 +1160,9 @@ void Application::sendAvatarFaceVideoMessage(int frameCount, const QByteArray& d
|
||||||
|
|
||||||
packetPosition += populateTypeAndVersion(packetPosition, PACKET_TYPE_AVATAR_FACE_VIDEO);
|
packetPosition += populateTypeAndVersion(packetPosition, PACKET_TYPE_AVATAR_FACE_VIDEO);
|
||||||
|
|
||||||
*(uint16_t*)packetPosition = NodeList::getInstance()->getOwnerID();
|
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
|
||||||
packetPosition += sizeof(uint16_t);
|
memcpy(packetPosition, rfcUUID.constData(), rfcUUID.size());
|
||||||
|
packetPosition += rfcUUID.size();
|
||||||
|
|
||||||
*(uint32_t*)packetPosition = frameCount;
|
*(uint32_t*)packetPosition = frameCount;
|
||||||
packetPosition += sizeof(uint32_t);
|
packetPosition += sizeof(uint32_t);
|
||||||
|
@ -1295,12 +1296,13 @@ static Avatar* processAvatarMessageHeader(unsigned char*& packetData, size_t& da
|
||||||
dataBytes -= numBytesPacketHeader;
|
dataBytes -= numBytesPacketHeader;
|
||||||
|
|
||||||
// read the node id
|
// read the node id
|
||||||
uint16_t nodeID = *(uint16_t*)packetData;
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) packetData, NUM_BYTES_RFC4122_UUID));
|
||||||
packetData += sizeof(nodeID);
|
|
||||||
dataBytes -= sizeof(nodeID);
|
packetData += NUM_BYTES_RFC4122_UUID;
|
||||||
|
dataBytes -= NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// make sure the node exists
|
// make sure the node exists
|
||||||
Node* node = NodeList::getInstance()->nodeWithID(nodeID);
|
Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||||
if (!node || !node->getLinkedData()) {
|
if (!node || !node->getLinkedData()) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -1393,13 +1395,13 @@ void Application::increaseVoxelSize() {
|
||||||
|
|
||||||
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500;
|
||||||
struct SendVoxelsOperationArgs {
|
struct SendVoxelsOperationArgs {
|
||||||
unsigned char* newBaseOctCode;
|
const unsigned char* newBaseOctCode;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||||
SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData;
|
SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData;
|
||||||
if (node->isColored()) {
|
if (node->isColored()) {
|
||||||
unsigned char* nodeOctalCode = node->getOctalCode();
|
const unsigned char* nodeOctalCode = node->getOctalCode();
|
||||||
|
|
||||||
unsigned char* codeColorBuffer = NULL;
|
unsigned char* codeColorBuffer = NULL;
|
||||||
int codeLength = 0;
|
int codeLength = 0;
|
||||||
|
@ -1561,29 +1563,6 @@ void Application::deleteVoxels() {
|
||||||
deleteVoxelUnderCursor();
|
deleteVoxelUnderCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Application::setListenModeNormal() {
|
|
||||||
_audio.setListenMode(AudioRingBuffer::NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setListenModePoint() {
|
|
||||||
_audio.setListenMode(AudioRingBuffer::OMNI_DIRECTIONAL_POINT);
|
|
||||||
_audio.setListenRadius(1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::setListenModeSingleSource() {
|
|
||||||
_audio.setListenMode(AudioRingBuffer::SELECTED_SOURCES);
|
|
||||||
_audio.clearListenSources();
|
|
||||||
|
|
||||||
glm::vec3 mouseRayOrigin = _myAvatar.getMouseRayOrigin();
|
|
||||||
glm::vec3 mouseRayDirection = _myAvatar.getMouseRayDirection();
|
|
||||||
glm::vec3 eyePositionIgnored;
|
|
||||||
uint16_t nodeID;
|
|
||||||
|
|
||||||
if (findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeID)) {
|
|
||||||
_audio.addListenSource(nodeID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Application::initDisplay() {
|
void Application::initDisplay() {
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||||
|
@ -1690,7 +1669,7 @@ const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
|
||||||
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
|
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
|
||||||
const float HEAD_SPHERE_RADIUS = 0.07;
|
const float HEAD_SPHERE_RADIUS = 0.07;
|
||||||
|
|
||||||
static uint16_t DEFAULT_NODE_ID_REF = 1;
|
static QUuid DEFAULT_NODE_ID_REF;
|
||||||
|
|
||||||
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
glm::vec3& eyePosition) {
|
glm::vec3& eyePosition) {
|
||||||
|
@ -1699,7 +1678,7 @@ void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, cons
|
||||||
}
|
}
|
||||||
|
|
||||||
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
glm::vec3& eyePosition, uint16_t& nodeID = DEFAULT_NODE_ID_REF) {
|
glm::vec3& eyePosition, QUuid& nodeUUID = DEFAULT_NODE_ID_REF) {
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
|
@ -1712,7 +1691,7 @@ Avatar* Application::findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, con
|
||||||
eyePosition = avatar->getHead().getEyePosition();
|
eyePosition = avatar->getHead().getEyePosition();
|
||||||
_lookatIndicatorScale = avatar->getHead().getScale();
|
_lookatIndicatorScale = avatar->getHead().getScale();
|
||||||
_lookatOtherPosition = headPosition;
|
_lookatOtherPosition = headPosition;
|
||||||
nodeID = avatar->getOwningNode()->getNodeID();
|
nodeUUID = avatar->getOwningNode()->getUUID();
|
||||||
return avatar;
|
return avatar;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1761,12 +1740,12 @@ void Application::renderFollowIndicator() {
|
||||||
Avatar* avatar = (Avatar *) node->getLinkedData();
|
Avatar* avatar = (Avatar *) node->getLinkedData();
|
||||||
Avatar* leader = NULL;
|
Avatar* leader = NULL;
|
||||||
|
|
||||||
if (avatar->getLeaderID() != UNKNOWN_NODE_ID) {
|
if (!avatar->getLeaderUUID().isNull()) {
|
||||||
if (avatar->getLeaderID() == NodeList::getInstance()->getOwnerID()) {
|
if (avatar->getLeaderUUID() == NodeList::getInstance()->getOwnerUUID()) {
|
||||||
leader = &_myAvatar;
|
leader = &_myAvatar;
|
||||||
} else {
|
} else {
|
||||||
for (NodeList::iterator it = nodeList->begin(); it != nodeList->end(); ++it) {
|
for (NodeList::iterator it = nodeList->begin(); it != nodeList->end(); ++it) {
|
||||||
if(it->getNodeID() == avatar->getLeaderID()
|
if(it->getUUID() == avatar->getLeaderUUID()
|
||||||
&& it->getType() == NODE_TYPE_AGENT) {
|
&& it->getType() == NODE_TYPE_AGENT) {
|
||||||
leader = (Avatar*) it->getLinkedData();
|
leader = (Avatar*) it->getLinkedData();
|
||||||
}
|
}
|
||||||
|
@ -2246,26 +2225,27 @@ void Application::updateAvatar(float deltaTime) {
|
||||||
_myAvatar.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
|
_myAvatar.setCameraEyeOffsetPosition(_viewFrustum.getEyeOffsetPosition());
|
||||||
|
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
if (nodeList->getOwnerID() != UNKNOWN_NODE_ID) {
|
|
||||||
// if I know my ID, send head/hand data to the avatar mixer and voxel server
|
// send head/hand data to the avatar mixer and voxel server
|
||||||
unsigned char broadcastString[MAX_PACKET_SIZE];
|
unsigned char broadcastString[MAX_PACKET_SIZE];
|
||||||
unsigned char* endOfBroadcastStringWrite = broadcastString;
|
unsigned char* endOfBroadcastStringWrite = broadcastString;
|
||||||
|
|
||||||
endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA);
|
endOfBroadcastStringWrite += populateTypeAndVersion(endOfBroadcastStringWrite, PACKET_TYPE_HEAD_DATA);
|
||||||
|
|
||||||
endOfBroadcastStringWrite += packNodeId(endOfBroadcastStringWrite, nodeList->getOwnerID());
|
QByteArray ownerUUID = nodeList->getOwnerUUID().toRfc4122();
|
||||||
|
memcpy(endOfBroadcastStringWrite, ownerUUID.constData(), ownerUUID.size());
|
||||||
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
endOfBroadcastStringWrite += ownerUUID.size();
|
||||||
|
|
||||||
const char nodeTypesOfInterest[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AVATAR_MIXER };
|
endOfBroadcastStringWrite += _myAvatar.getBroadcastData(endOfBroadcastStringWrite);
|
||||||
controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString,
|
|
||||||
nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
|
const char nodeTypesOfInterest[] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AVATAR_MIXER };
|
||||||
|
controlledBroadcastToNodes(broadcastString, endOfBroadcastStringWrite - broadcastString,
|
||||||
// once in a while, send my urls
|
nodeTypesOfInterest, sizeof(nodeTypesOfInterest));
|
||||||
const float AVATAR_URLS_SEND_INTERVAL = 1.0f; // seconds
|
|
||||||
if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) {
|
// once in a while, send my urls
|
||||||
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
|
const float AVATAR_URLS_SEND_INTERVAL = 1.0f; // seconds
|
||||||
}
|
if (shouldDo(AVATAR_URLS_SEND_INTERVAL, deltaTime)) {
|
||||||
|
Avatar::sendAvatarURLsMessage(_myAvatar.getVoxels()->getVoxelURL());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2806,24 +2786,40 @@ void Application::displayOverlay() {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)
|
if (Menu::getInstance()->isOptionChecked(MenuOption::HeadMouse)
|
||||||
&& !Menu::getInstance()->isOptionChecked(MenuOption::Mirror)
|
&& !Menu::getInstance()->isOptionChecked(MenuOption::Mirror)
|
||||||
&& USING_INVENSENSE_MPU9150) {
|
&& USING_INVENSENSE_MPU9150) {
|
||||||
// Display small target box at center or head mouse target that can also be used to measure LOD
|
// Display small target box at center or head mouse target that can also be used to measure LOD
|
||||||
glColor3f(1.0, 1.0, 1.0);
|
glColor3f(1.0, 1.0, 1.0);
|
||||||
|
glDisable(GL_LINE_SMOOTH);
|
||||||
|
const int PIXEL_BOX = 16;
|
||||||
|
glBegin(GL_LINES);
|
||||||
|
glVertex2f(_headMouseX - PIXEL_BOX/2, _headMouseY);
|
||||||
|
glVertex2f(_headMouseX + PIXEL_BOX/2, _headMouseY);
|
||||||
|
glVertex2f(_headMouseX, _headMouseY - PIXEL_BOX/2);
|
||||||
|
glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2);
|
||||||
|
glEnd();
|
||||||
|
glEnable(GL_LINE_SMOOTH);
|
||||||
|
glColor3f(1.f, 0.f, 0.f);
|
||||||
|
glPointSize(3.0f);
|
||||||
|
glDisable(GL_POINT_SMOOTH);
|
||||||
|
glBegin(GL_POINTS);
|
||||||
|
glVertex2f(_headMouseX - 1, _headMouseY + 1);
|
||||||
|
glEnd();
|
||||||
|
// If Faceshift is active, show eye pitch and yaw as separate pointer
|
||||||
|
if (_faceshift.isActive()) {
|
||||||
|
const float EYE_TARGET_PIXELS_PER_DEGREE = 40.0;
|
||||||
|
int eyeTargetX = (_glWidget->width() / 2) - _faceshift.getEstimatedEyeYaw() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||||
|
int eyeTargetY = (_glWidget->height() / 2) - _faceshift.getEstimatedEyePitch() * EYE_TARGET_PIXELS_PER_DEGREE;
|
||||||
|
|
||||||
|
glColor3f(0.0, 1.0, 1.0);
|
||||||
glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
const int PIXEL_BOX = 16;
|
|
||||||
glBegin(GL_LINES);
|
glBegin(GL_LINES);
|
||||||
glVertex2f(_headMouseX - PIXEL_BOX/2, _headMouseY);
|
glVertex2f(eyeTargetX - PIXEL_BOX/2, eyeTargetY);
|
||||||
glVertex2f(_headMouseX + PIXEL_BOX/2, _headMouseY);
|
glVertex2f(eyeTargetX + PIXEL_BOX/2, eyeTargetY);
|
||||||
glVertex2f(_headMouseX, _headMouseY - PIXEL_BOX/2);
|
glVertex2f(eyeTargetX, eyeTargetY - PIXEL_BOX/2);
|
||||||
glVertex2f(_headMouseX, _headMouseY + PIXEL_BOX/2);
|
glVertex2f(eyeTargetX, eyeTargetY + PIXEL_BOX/2);
|
||||||
glEnd();
|
|
||||||
glEnable(GL_LINE_SMOOTH);
|
|
||||||
glColor3f(1.f, 0.f, 0.f);
|
|
||||||
glPointSize(3.0f);
|
|
||||||
glDisable(GL_POINT_SMOOTH);
|
|
||||||
glBegin(GL_POINTS);
|
|
||||||
glVertex2f(_headMouseX - 1, _headMouseY + 1);
|
|
||||||
glEnd();
|
glEnd();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Show detected levels from the serial I/O ADC channel sensors
|
// Show detected levels from the serial I/O ADC channel sensors
|
||||||
if (_displayLevels) _serialHeadSensor.renderLevels(_glWidget->width(), _glWidget->height());
|
if (_displayLevels) _serialHeadSensor.renderLevels(_glWidget->width(), _glWidget->height());
|
||||||
|
@ -3559,8 +3555,8 @@ void Application::toggleFollowMode() {
|
||||||
_pieMenu.getY() / (float)_glWidget->height(),
|
_pieMenu.getY() / (float)_glWidget->height(),
|
||||||
mouseRayOrigin, mouseRayDirection);
|
mouseRayOrigin, mouseRayDirection);
|
||||||
glm::vec3 eyePositionIgnored;
|
glm::vec3 eyePositionIgnored;
|
||||||
uint16_t nodeIDIgnored;
|
QUuid nodeUUIDIgnored;
|
||||||
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeIDIgnored);
|
Avatar* leadingAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePositionIgnored, nodeUUIDIgnored);
|
||||||
|
|
||||||
_myAvatar.follow(leadingAvatar);
|
_myAvatar.follow(leadingAvatar);
|
||||||
}
|
}
|
||||||
|
@ -3628,10 +3624,10 @@ void Application::nodeAdded(Node* node) {
|
||||||
|
|
||||||
void Application::nodeKilled(Node* node) {
|
void Application::nodeKilled(Node* node) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
QUuid nodeUUID = node->getUUID();
|
||||||
// see if this is the first we've heard of this node...
|
// see if this is the first we've heard of this node...
|
||||||
if (_voxelServerJurisdictions.find(nodeID) != _voxelServerJurisdictions.end()) {
|
if (_voxelServerJurisdictions.find(nodeUUID) != _voxelServerJurisdictions.end()) {
|
||||||
unsigned char* rootCode = _voxelServerJurisdictions[nodeID].getRootOctalCode();
|
unsigned char* rootCode = _voxelServerJurisdictions[nodeUUID].getRootOctalCode();
|
||||||
VoxelPositionSize rootDetails;
|
VoxelPositionSize rootDetails;
|
||||||
voxelDetailsForCode(rootCode, rootDetails);
|
voxelDetailsForCode(rootCode, rootDetails);
|
||||||
|
|
||||||
|
@ -3661,13 +3657,13 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
||||||
|
|
||||||
// quick fix for crash... why would voxelServer be NULL?
|
// quick fix for crash... why would voxelServer be NULL?
|
||||||
if (voxelServer) {
|
if (voxelServer) {
|
||||||
uint16_t nodeID = voxelServer->getNodeID();
|
QUuid nodeUUID = voxelServer->getUUID();
|
||||||
|
|
||||||
VoxelPositionSize rootDetails;
|
VoxelPositionSize rootDetails;
|
||||||
voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), rootDetails);
|
voxelDetailsForCode(_voxelSceneStats.getJurisdictionRoot(), rootDetails);
|
||||||
|
|
||||||
// see if this is the first we've heard of this node...
|
// see if this is the first we've heard of this node...
|
||||||
if (_voxelServerJurisdictions.find(nodeID) == _voxelServerJurisdictions.end()) {
|
if (_voxelServerJurisdictions.find(nodeUUID) == _voxelServerJurisdictions.end()) {
|
||||||
printf("stats from new voxel server... v[%f, %f, %f, %f]\n",
|
printf("stats from new voxel server... v[%f, %f, %f, %f]\n",
|
||||||
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||||
|
|
||||||
|
@ -3684,7 +3680,7 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
||||||
// details from the VoxelSceneStats to construct the JurisdictionMap
|
// details from the VoxelSceneStats to construct the JurisdictionMap
|
||||||
JurisdictionMap jurisdictionMap;
|
JurisdictionMap jurisdictionMap;
|
||||||
jurisdictionMap.copyContents(_voxelSceneStats.getJurisdictionRoot(), _voxelSceneStats.getJurisdictionEndNodes());
|
jurisdictionMap.copyContents(_voxelSceneStats.getJurisdictionRoot(), _voxelSceneStats.getJurisdictionEndNodes());
|
||||||
_voxelServerJurisdictions[nodeID] = jurisdictionMap;
|
_voxelServerJurisdictions[nodeUUID] = jurisdictionMap;
|
||||||
}
|
}
|
||||||
return statsMessageLength;
|
return statsMessageLength;
|
||||||
}
|
}
|
||||||
|
|
|
@ -171,9 +171,6 @@ public slots:
|
||||||
void doKillLocalVoxels();
|
void doKillLocalVoxels();
|
||||||
void decreaseVoxelSize();
|
void decreaseVoxelSize();
|
||||||
void increaseVoxelSize();
|
void increaseVoxelSize();
|
||||||
void setListenModeNormal();
|
|
||||||
void setListenModePoint();
|
|
||||||
void setListenModeSingleSource();
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
|
@ -213,7 +210,7 @@ private:
|
||||||
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
glm::vec3& eyePosition);
|
glm::vec3& eyePosition);
|
||||||
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection,
|
||||||
glm::vec3& eyePosition, uint16_t& nodeID);
|
glm::vec3& eyePosition, QUuid &nodeUUID);
|
||||||
bool isLookingAtMyAvatar(Avatar* avatar);
|
bool isLookingAtMyAvatar(Avatar* avatar);
|
||||||
|
|
||||||
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
|
||||||
|
|
|
@ -84,93 +84,74 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
||||||
memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
|
memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
|
||||||
memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
|
memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
|
||||||
|
|
||||||
|
// If Mute button is pressed, clear the input buffer
|
||||||
|
if (_muted) {
|
||||||
|
memset(inputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL);
|
||||||
|
}
|
||||||
|
|
||||||
// Add Procedural effects to input samples
|
// Add Procedural effects to input samples
|
||||||
addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||||
|
|
||||||
if (nodeList && inputLeft) {
|
if (nodeList && inputLeft) {
|
||||||
|
|
||||||
if (!_muted) {
|
// Measure the loudness of the signal from the microphone and store in audio object
|
||||||
// Measure the loudness of the signal from the microphone and store in audio object
|
float loudness = 0;
|
||||||
float loudness = 0;
|
for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
||||||
for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
|
loudness += abs(inputLeft[i]);
|
||||||
loudness += abs(inputLeft[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
loudness /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
|
||||||
_lastInputLoudness = loudness;
|
|
||||||
|
|
||||||
// add input (@microphone) data to the scope
|
|
||||||
_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loudness /= BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
|
||||||
|
_lastInputLoudness = loudness;
|
||||||
|
|
||||||
|
// add input (@microphone) data to the scope
|
||||||
|
_scope->addSamples(0, inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||||
|
|
||||||
Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
Node* audioMixer = nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||||
|
|
||||||
if (audioMixer) {
|
if (audioMixer) {
|
||||||
audioMixer->lock();
|
if (audioMixer->getActiveSocket()) {
|
||||||
sockaddr_in audioSocket = *(sockaddr_in*) audioMixer->getActiveSocket();
|
glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition();
|
||||||
audioMixer->unlock();
|
glm::quat headOrientation = interfaceAvatar->getHead().getOrientation();
|
||||||
|
|
||||||
glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition();
|
int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO);
|
||||||
glm::quat headOrientation = interfaceAvatar->getHead().getOrientation();
|
int leadingBytes = numBytesPacketHeader + sizeof(headPosition) + sizeof(headOrientation);
|
||||||
|
|
||||||
int numBytesPacketHeader = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO);
|
// we need the amount of bytes in the buffer + 1 for type
|
||||||
int leadingBytes = numBytesPacketHeader + sizeof(headPosition) + sizeof(headOrientation);
|
// + 12 for 3 floats for position + float for bearing + 1 attenuation byte
|
||||||
|
unsigned char dataPacket[MAX_PACKET_SIZE];
|
||||||
// we need the amount of bytes in the buffer + 1 for type
|
|
||||||
// + 12 for 3 floats for position + float for bearing + 1 attenuation byte
|
PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio)
|
||||||
unsigned char dataPacket[MAX_PACKET_SIZE];
|
? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO
|
||||||
|
: PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO;
|
||||||
PACKET_TYPE packetType = Menu::getInstance()->isOptionChecked(MenuOption::EchoAudio)
|
|
||||||
? PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO
|
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, packetType);
|
||||||
: PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO;
|
|
||||||
|
// pack Source Data
|
||||||
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, packetType);
|
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
|
||||||
|
memcpy(currentPacketPtr, rfcUUID.constData(), rfcUUID.size());
|
||||||
// pack Source Data
|
currentPacketPtr += rfcUUID.size();
|
||||||
uint16_t ownerID = NodeList::getInstance()->getOwnerID();
|
leadingBytes += rfcUUID.size();
|
||||||
memcpy(currentPacketPtr, &ownerID, sizeof(ownerID));
|
|
||||||
currentPacketPtr += (sizeof(ownerID));
|
// memcpy the three float positions
|
||||||
leadingBytes += (sizeof(ownerID));
|
memcpy(currentPacketPtr, &headPosition, sizeof(headPosition));
|
||||||
|
currentPacketPtr += (sizeof(headPosition));
|
||||||
// pack Listen Mode Data
|
|
||||||
memcpy(currentPacketPtr, &_listenMode, sizeof(_listenMode));
|
// memcpy our orientation
|
||||||
currentPacketPtr += (sizeof(_listenMode));
|
memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation));
|
||||||
leadingBytes += (sizeof(_listenMode));
|
currentPacketPtr += sizeof(headOrientation);
|
||||||
|
|
||||||
if (_listenMode == AudioRingBuffer::OMNI_DIRECTIONAL_POINT) {
|
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
||||||
memcpy(currentPacketPtr, &_listenRadius, sizeof(_listenRadius));
|
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
||||||
currentPacketPtr += (sizeof(_listenRadius));
|
|
||||||
leadingBytes += (sizeof(_listenRadius));
|
nodeList->getNodeSocket()->send(audioMixer->getActiveSocket(),
|
||||||
} else if (_listenMode == AudioRingBuffer::SELECTED_SOURCES) {
|
dataPacket,
|
||||||
int listenSourceCount = _listenSources.size();
|
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
||||||
memcpy(currentPacketPtr, &listenSourceCount, sizeof(listenSourceCount));
|
|
||||||
currentPacketPtr += (sizeof(listenSourceCount));
|
interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL
|
||||||
leadingBytes += (sizeof(listenSourceCount));
|
+ leadingBytes);
|
||||||
for (int i = 0; i < listenSourceCount; i++) {
|
} else {
|
||||||
memcpy(currentPacketPtr, &_listenSources[i], sizeof(_listenSources[i]));
|
nodeList->pingPublicAndLocalSocketsForInactiveNode(audioMixer);
|
||||||
currentPacketPtr += sizeof(_listenSources[i]);
|
|
||||||
leadingBytes += sizeof(_listenSources[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// memcpy the three float positions
|
|
||||||
memcpy(currentPacketPtr, &headPosition, sizeof(headPosition));
|
|
||||||
currentPacketPtr += (sizeof(headPosition));
|
|
||||||
|
|
||||||
// memcpy our orientation
|
|
||||||
memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation));
|
|
||||||
currentPacketPtr += sizeof(headOrientation);
|
|
||||||
|
|
||||||
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
|
|
||||||
memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES_PER_CHANNEL);
|
|
||||||
|
|
||||||
nodeList->getNodeSocket()->send((sockaddr*) &audioSocket,
|
|
||||||
dataPacket,
|
|
||||||
BUFFER_LENGTH_BYTES_PER_CHANNEL + leadingBytes);
|
|
||||||
|
|
||||||
interface->getBandwidthMeter()->outputStream(BandwidthMeter::AUDIO).updateValue(BUFFER_LENGTH_BYTES_PER_CHANNEL
|
|
||||||
+ leadingBytes);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -264,8 +245,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
|
||||||
if (flangeIndex < 0) {
|
if (flangeIndex < 0) {
|
||||||
// we need to grab the flange sample from earlier in the buffer
|
// we need to grab the flange sample from earlier in the buffer
|
||||||
flangeFrame = ringBuffer->getNextOutput() != ringBuffer->getBuffer()
|
flangeFrame = ringBuffer->getNextOutput() != ringBuffer->getBuffer()
|
||||||
? ringBuffer->getNextOutput() - PACKET_LENGTH_SAMPLES
|
? ringBuffer->getNextOutput() - PACKET_LENGTH_SAMPLES
|
||||||
: ringBuffer->getNextOutput() + RING_BUFFER_LENGTH_SAMPLES - PACKET_LENGTH_SAMPLES;
|
: ringBuffer->getNextOutput() + RING_BUFFER_LENGTH_SAMPLES - PACKET_LENGTH_SAMPLES;
|
||||||
|
|
||||||
flangeIndex = PACKET_LENGTH_SAMPLES_PER_CHANNEL + (s - sampleFlangeDelay);
|
flangeIndex = PACKET_LENGTH_SAMPLES_PER_CHANNEL + (s - sampleFlangeDelay);
|
||||||
}
|
}
|
||||||
|
@ -348,24 +329,6 @@ void Audio::reset() {
|
||||||
_ringBuffer.reset();
|
_ringBuffer.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Audio::addListenSource(int sourceID) {
|
|
||||||
_listenSources.push_back(sourceID);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::clearListenSources() {
|
|
||||||
_listenSources.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Audio::removeListenSource(int sourceID) {
|
|
||||||
for (int i = 0; i < _listenSources.size(); i++) {
|
|
||||||
if (_listenSources[i] == sourceID) {
|
|
||||||
_listenSources.erase(_listenSources.begin() + i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
||||||
_stream(NULL),
|
_stream(NULL),
|
||||||
_ringBuffer(true),
|
_ringBuffer(true),
|
||||||
|
@ -396,9 +359,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) :
|
||||||
_collisionSoundDuration(0.0f),
|
_collisionSoundDuration(0.0f),
|
||||||
_proceduralEffectSample(0),
|
_proceduralEffectSample(0),
|
||||||
_heartbeatMagnitude(0.0f),
|
_heartbeatMagnitude(0.0f),
|
||||||
_muted(false),
|
_muted(false)
|
||||||
_listenMode(AudioRingBuffer::NORMAL),
|
|
||||||
_listenRadius(0.0f)
|
|
||||||
{
|
{
|
||||||
outputPortAudioError(Pa_Initialize());
|
outputPortAudioError(Pa_Initialize());
|
||||||
|
|
||||||
|
|
|
@ -68,13 +68,6 @@ public:
|
||||||
// in which case 'true' is returned - otherwise the return value is 'false'.
|
// in which case 'true' is returned - otherwise the return value is 'false'.
|
||||||
// The results of the analysis are written to the log.
|
// The results of the analysis are written to the log.
|
||||||
bool eventuallyAnalyzePing();
|
bool eventuallyAnalyzePing();
|
||||||
|
|
||||||
void setListenMode(AudioRingBuffer::ListenMode mode) { _listenMode = mode; }
|
|
||||||
void setListenRadius(float radius) { _listenRadius = radius; }
|
|
||||||
void addListenSource(int sourceID);
|
|
||||||
void removeListenSource(int sourceID);
|
|
||||||
void clearListenSources();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
PaStream* _stream;
|
PaStream* _stream;
|
||||||
|
@ -117,10 +110,6 @@ private:
|
||||||
GLuint _muteTextureId;
|
GLuint _muteTextureId;
|
||||||
QRect _iconBounds;
|
QRect _iconBounds;
|
||||||
|
|
||||||
AudioRingBuffer::ListenMode _listenMode;
|
|
||||||
float _listenRadius;
|
|
||||||
std::vector<int> _listenSources;
|
|
||||||
|
|
||||||
// Audio callback in class context.
|
// Audio callback in class context.
|
||||||
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);
|
inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight);
|
||||||
|
|
||||||
|
|
|
@ -442,21 +442,6 @@ Menu::Menu() :
|
||||||
|
|
||||||
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
|
QMenu* audioDebugMenu = developerMenu->addMenu("Audio Debugging Tools");
|
||||||
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
|
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoAudio);
|
||||||
addActionToQMenuAndActionHash(audioDebugMenu,
|
|
||||||
MenuOption::ListenModeNormal,
|
|
||||||
Qt::CTRL | Qt::Key_1,
|
|
||||||
appInstance,
|
|
||||||
SLOT(setListenModeNormal()));
|
|
||||||
addActionToQMenuAndActionHash(audioDebugMenu,
|
|
||||||
MenuOption::ListenModePoint,
|
|
||||||
Qt::CTRL | Qt::Key_2,
|
|
||||||
appInstance,
|
|
||||||
SLOT(setListenModePoint()));
|
|
||||||
addActionToQMenuAndActionHash(audioDebugMenu,
|
|
||||||
MenuOption::ListenModeSingleSource,
|
|
||||||
Qt::CTRL | Qt::Key_3,
|
|
||||||
appInstance,
|
|
||||||
SLOT(setListenModeSingleSource()));
|
|
||||||
|
|
||||||
QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options");
|
QMenu* voxelProtoOptionsMenu = developerMenu->addMenu("Voxel Server Protocol Options");
|
||||||
|
|
||||||
|
|
|
@ -176,9 +176,6 @@ namespace MenuOption {
|
||||||
const QString Gravity = "Use Gravity";
|
const QString Gravity = "Use Gravity";
|
||||||
const QString GroundPlane = "Ground Plane";
|
const QString GroundPlane = "Ground Plane";
|
||||||
const QString ParticleCloud = "Particle Cloud";
|
const QString ParticleCloud = "Particle Cloud";
|
||||||
const QString ListenModeNormal = "Listen Mode Normal";
|
|
||||||
const QString ListenModePoint = "Listen Mode Point";
|
|
||||||
const QString ListenModeSingleSource = "Listen Mode Single Source";
|
|
||||||
const QString Log = "Log";
|
const QString Log = "Log";
|
||||||
const QString Login = "Login";
|
const QString Login = "Login";
|
||||||
const QString LookAtIndicator = "Look-at Indicator";
|
const QString LookAtIndicator = "Look-at Indicator";
|
||||||
|
|
|
@ -47,13 +47,12 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char*
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Voxels)) {
|
||||||
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
Node* voxelServer = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) {
|
||||||
int nodeID = voxelServer->getNodeID();
|
|
||||||
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
if (packetData[0] == PACKET_TYPE_ENVIRONMENT_DATA) {
|
||||||
app->_environment.parseData(&senderAddress, packetData, messageLength);
|
app->_environment.parseData(&senderAddress, packetData, messageLength);
|
||||||
} else {
|
} else {
|
||||||
app->_voxels.setDataSourceID(nodeID);
|
app->_voxels.setDataSourceUUID(voxelServer->getUUID());
|
||||||
app->_voxels.parseData(packetData, messageLength);
|
app->_voxels.parseData(packetData, messageLength);
|
||||||
app->_voxels.setDataSourceID(UNKNOWN_NODE_ID);
|
app->_voxels.setDataSourceUUID(QUuid());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
|
||||||
VoxelNode::addUpdateHook(this);
|
VoxelNode::addUpdateHook(this);
|
||||||
_abandonedVBOSlots = 0;
|
_abandonedVBOSlots = 0;
|
||||||
_falseColorizeBySource = false;
|
_falseColorizeBySource = false;
|
||||||
_dataSourceID = UNKNOWN_NODE_ID;
|
_dataSourceUUID = QUuid();
|
||||||
_voxelServerCount = 0;
|
_voxelServerCount = 0;
|
||||||
|
|
||||||
_viewFrustum = Application::getInstance()->getViewFrustum();
|
_viewFrustum = Application::getInstance()->getViewFrustum();
|
||||||
|
@ -576,7 +576,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"readBitstreamToTree()");
|
"readBitstreamToTree()");
|
||||||
// ask the VoxelTree to read the bitstream into the tree
|
// ask the VoxelTree to read the bitstream into the tree
|
||||||
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
|
||||||
pthread_mutex_lock(&_treeLock);
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||||
pthread_mutex_unlock(&_treeLock);
|
pthread_mutex_unlock(&_treeLock);
|
||||||
|
@ -586,7 +586,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"readBitstreamToTree()");
|
"readBitstreamToTree()");
|
||||||
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
|
// ask the VoxelTree to read the MONOCHROME bitstream into the tree
|
||||||
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceID());
|
ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID());
|
||||||
pthread_mutex_lock(&_treeLock);
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
_tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args);
|
||||||
pthread_mutex_unlock(&_treeLock);
|
pthread_mutex_unlock(&_treeLock);
|
||||||
|
@ -1417,8 +1417,8 @@ bool VoxelSystem::falseColorizeBySourceOperation(VoxelNode* node, void* extraDat
|
||||||
_nodeCount++;
|
_nodeCount++;
|
||||||
if (node->isColored()) {
|
if (node->isColored()) {
|
||||||
// pick a color based on the source - we want each source to be obviously different
|
// pick a color based on the source - we want each source to be obviously different
|
||||||
uint16_t nodeID = node->getSourceID();
|
uint16_t nodeIDKey = node->getSourceUUIDKey();
|
||||||
node->setFalseColor(args->colors[nodeID].red, args->colors[nodeID].green, args->colors[nodeID].blue);
|
node->setFalseColor(args->colors[nodeIDKey].red, args->colors[nodeIDKey].green, args->colors[nodeIDKey].blue);
|
||||||
}
|
}
|
||||||
return true; // keep going!
|
return true; // keep going!
|
||||||
}
|
}
|
||||||
|
@ -1442,7 +1442,7 @@ void VoxelSystem::falseColorizeBySource() {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
uint16_t nodeID = VoxelNode::getSourceNodeUUIDKey(node->getUUID());
|
||||||
int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;
|
int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS;
|
||||||
args.colors[nodeID] = groupColors[groupColor];
|
args.colors[nodeID] = groupColors[groupColor];
|
||||||
|
|
||||||
|
@ -2299,19 +2299,17 @@ void VoxelSystem::falseColorizeOccludedV2() {
|
||||||
|
|
||||||
void VoxelSystem::nodeAdded(Node* node) {
|
void VoxelSystem::nodeAdded(Node* node) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
qDebug("VoxelSystem... voxel server %s added...\n", node->getUUID().toString().toLocal8Bit().constData());
|
||||||
qDebug("VoxelSystem... voxel server %u added...\n", nodeID);
|
|
||||||
_voxelServerCount++;
|
_voxelServerCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) {
|
bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||||
uint16_t killedNodeID = *(uint16_t*)extraData;
|
QUuid killedNodeID = *(QUuid*)extraData;
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
VoxelNode* childNode = node->getChildAtIndex(i);
|
VoxelNode* childNode = node->getChildAtIndex(i);
|
||||||
if (childNode) {
|
if (childNode) {
|
||||||
uint16_t childNodeID = childNode->getSourceID();
|
if (childNode->matchesSourceUUID(killedNodeID)) {
|
||||||
if (childNodeID == killedNodeID) {
|
|
||||||
node->safeDeepDeleteChildAtIndex(i);
|
node->safeDeepDeleteChildAtIndex(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2322,13 +2320,16 @@ bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) {
|
||||||
void VoxelSystem::nodeKilled(Node* node) {
|
void VoxelSystem::nodeKilled(Node* node) {
|
||||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
_voxelServerCount--;
|
_voxelServerCount--;
|
||||||
uint16_t nodeID = node->getNodeID();
|
|
||||||
qDebug("VoxelSystem... voxel server %u removed...\n", nodeID);
|
QUuid nodeUUID = node->getUUID();
|
||||||
|
|
||||||
|
qDebug("VoxelSystem... voxel server %s removed...\n", nodeUUID.toString().toLocal8Bit().constData());
|
||||||
|
|
||||||
if (_voxelServerCount > 0) {
|
if (_voxelServerCount > 0) {
|
||||||
// Kill any voxels from the local tree that match this nodeID
|
// Kill any voxels from the local tree that match this nodeID
|
||||||
|
// commenting out for removal of 16 bit node IDs
|
||||||
pthread_mutex_lock(&_treeLock);
|
pthread_mutex_lock(&_treeLock);
|
||||||
_tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeID);
|
_tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID);
|
||||||
pthread_mutex_unlock(&_treeLock);
|
pthread_mutex_unlock(&_treeLock);
|
||||||
_tree->setDirtyBit();
|
_tree->setDirtyBit();
|
||||||
setupNewVoxelsForDrawing();
|
setupNewVoxelsForDrawing();
|
||||||
|
|
|
@ -44,8 +44,8 @@ public:
|
||||||
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = DEFAULT_MAX_VOXELS_PER_SYSTEM);
|
||||||
~VoxelSystem();
|
~VoxelSystem();
|
||||||
|
|
||||||
void setDataSourceID(int dataSourceID) { _dataSourceID = dataSourceID; }
|
void setDataSourceUUID(const QUuid& dataSourceUUID) { _dataSourceUUID = dataSourceUUID; }
|
||||||
int getDataSourceID() const { return _dataSourceID; }
|
const QUuid& getDataSourceUUID() const { return _dataSourceUUID; }
|
||||||
|
|
||||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||||
|
|
||||||
|
@ -279,7 +279,7 @@ private:
|
||||||
glBufferIndex getNextBufferIndex();
|
glBufferIndex getNextBufferIndex();
|
||||||
|
|
||||||
bool _falseColorizeBySource;
|
bool _falseColorizeBySource;
|
||||||
int _dataSourceID;
|
QUuid _dataSourceUUID;
|
||||||
|
|
||||||
int _voxelServerCount;
|
int _voxelServerCount;
|
||||||
unsigned long _memoryUsageRAM;
|
unsigned long _memoryUsageRAM;
|
||||||
|
|
|
@ -61,19 +61,13 @@ const float chatMessageScale = 0.0015;
|
||||||
const float chatMessageHeight = 0.20;
|
const float chatMessageHeight = 0.20;
|
||||||
|
|
||||||
void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) {
|
void Avatar::sendAvatarURLsMessage(const QUrl& voxelURL) {
|
||||||
uint16_t ownerID = NodeList::getInstance()->getOwnerID();
|
|
||||||
|
|
||||||
if (ownerID == UNKNOWN_NODE_ID) {
|
|
||||||
return; // we don't yet know who we are
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray message;
|
QByteArray message;
|
||||||
|
|
||||||
char packetHeader[MAX_PACKET_HEADER_BYTES];
|
char packetHeader[MAX_PACKET_HEADER_BYTES];
|
||||||
int numBytesPacketHeader = populateTypeAndVersion((unsigned char*) packetHeader, PACKET_TYPE_AVATAR_URLS);
|
int numBytesPacketHeader = populateTypeAndVersion((unsigned char*) packetHeader, PACKET_TYPE_AVATAR_URLS);
|
||||||
|
|
||||||
message.append(packetHeader, numBytesPacketHeader);
|
message.append(packetHeader, numBytesPacketHeader);
|
||||||
message.append((const char*)&ownerID, sizeof(ownerID));
|
message.append(NodeList::getInstance()->getOwnerUUID().toRfc4122());
|
||||||
|
|
||||||
QDataStream out(&message, QIODevice::WriteOnly | QIODevice::Append);
|
QDataStream out(&message, QIODevice::WriteOnly | QIODevice::Append);
|
||||||
out << voxelURL;
|
out << voxelURL;
|
||||||
|
@ -284,13 +278,13 @@ void Avatar::follow(Avatar* leadingAvatar) {
|
||||||
|
|
||||||
_leadingAvatar = leadingAvatar;
|
_leadingAvatar = leadingAvatar;
|
||||||
if (_leadingAvatar != NULL) {
|
if (_leadingAvatar != NULL) {
|
||||||
_leaderID = leadingAvatar->getOwningNode()->getNodeID();
|
_leaderUUID = leadingAvatar->getOwningNode()->getUUID();
|
||||||
_stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale;
|
_stringLength = glm::length(_position - _leadingAvatar->getPosition()) / _scale;
|
||||||
if (_stringLength > MAX_STRING_LENGTH) {
|
if (_stringLength > MAX_STRING_LENGTH) {
|
||||||
_stringLength = MAX_STRING_LENGTH;
|
_stringLength = MAX_STRING_LENGTH;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
_leaderID = UNKNOWN_NODE_ID;
|
_leaderUUID = QUuid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -329,16 +329,7 @@ void Head::setScale (float scale) {
|
||||||
|
|
||||||
|
|
||||||
void Head::createMohawk() {
|
void Head::createMohawk() {
|
||||||
uint16_t nodeId = UNKNOWN_NODE_ID;
|
srand(time(NULL));
|
||||||
if (_owningAvatar->getOwningNode()) {
|
|
||||||
nodeId = _owningAvatar->getOwningNode()->getNodeID();
|
|
||||||
} else {
|
|
||||||
nodeId = NodeList::getInstance()->getOwnerID();
|
|
||||||
if (nodeId == UNKNOWN_NODE_ID) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
srand(nodeId);
|
|
||||||
float height = _scale * (0.08f + randFloat() * 0.05f);
|
float height = _scale * (0.08f + randFloat() * 0.05f);
|
||||||
float variance = 0.03 + randFloat() * 0.03f;
|
float variance = 0.03 + randFloat() * 0.03f;
|
||||||
const float RAD_PER_TRIANGLE = (2.3f + randFloat() * 0.2f) / (float)MOHAWK_TRIANGLES;
|
const float RAD_PER_TRIANGLE = (2.3f + randFloat() * 0.2f) / (float)MOHAWK_TRIANGLES;
|
||||||
|
|
|
@ -59,7 +59,7 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) {
|
||||||
// if we don't have an explicit destination socket then pull active socket for current audio mixer from node list
|
// if we don't have an explicit destination socket then pull active socket for current audio mixer from node list
|
||||||
if (!_isDestinationSocketExplicit) {
|
if (!_isDestinationSocketExplicit) {
|
||||||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||||
if (audioMixer) {
|
if (audioMixer && audioMixer->getActiveSocket()) {
|
||||||
_destinationSocket = *audioMixer->getActiveSocket();
|
_destinationSocket = *audioMixer->getActiveSocket();
|
||||||
} else {
|
} else {
|
||||||
pthread_exit(0);
|
pthread_exit(0);
|
||||||
|
|
|
@ -10,8 +10,10 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "AudioInjector.h"
|
#include "AudioInjector.h"
|
||||||
|
|
||||||
|
@ -23,8 +25,6 @@ AudioInjector::AudioInjector(const char* filename) :
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
_isInjectingAudio(false)
|
_isInjectingAudio(false)
|
||||||
{
|
{
|
||||||
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
|
|
||||||
|
|
||||||
std::fstream sourceFile;
|
std::fstream sourceFile;
|
||||||
|
|
||||||
sourceFile.open(filename, std::ios::in | std::ios::binary);
|
sourceFile.open(filename, std::ios::in | std::ios::binary);
|
||||||
|
@ -53,8 +53,6 @@ AudioInjector::AudioInjector(int maxNumSamples) :
|
||||||
_indexOfNextSlot(0),
|
_indexOfNextSlot(0),
|
||||||
_isInjectingAudio(false)
|
_isInjectingAudio(false)
|
||||||
{
|
{
|
||||||
loadRandomIdentifier(_streamIdentifier, STREAM_IDENTIFIER_NUM_BYTES);
|
|
||||||
|
|
||||||
_audioSampleArray = new int16_t[maxNumSamples];
|
_audioSampleArray = new int16_t[maxNumSamples];
|
||||||
memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t));
|
memset(_audioSampleArray, 0, _numTotalSamples * sizeof(int16_t));
|
||||||
}
|
}
|
||||||
|
@ -71,7 +69,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
||||||
|
|
||||||
// calculate the number of bytes required for additional data
|
// calculate the number of bytes required for additional data
|
||||||
int leadingBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO)
|
int leadingBytes = numBytesForPacketHeader((unsigned char*) &PACKET_TYPE_INJECT_AUDIO)
|
||||||
+ sizeof(_streamIdentifier)
|
+ NUM_BYTES_RFC4122_UUID
|
||||||
+ sizeof(_position)
|
+ sizeof(_position)
|
||||||
+ sizeof(_orientation)
|
+ sizeof(_orientation)
|
||||||
+ sizeof(_radius)
|
+ sizeof(_radius)
|
||||||
|
@ -82,8 +80,9 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination
|
||||||
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, PACKET_TYPE_INJECT_AUDIO);
|
unsigned char* currentPacketPtr = dataPacket + populateTypeAndVersion(dataPacket, PACKET_TYPE_INJECT_AUDIO);
|
||||||
|
|
||||||
// copy the identifier for this injector
|
// copy the identifier for this injector
|
||||||
memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier));
|
QByteArray rfcUUID = NodeList::getInstance()->getOwnerUUID().toRfc4122();
|
||||||
currentPacketPtr += sizeof(_streamIdentifier);
|
memcpy(currentPacketPtr, rfcUUID.constData(), rfcUUID.size());
|
||||||
|
currentPacketPtr += rfcUUID.size();
|
||||||
|
|
||||||
memcpy(currentPacketPtr, &_position, sizeof(_position));
|
memcpy(currentPacketPtr, &_position, sizeof(_position));
|
||||||
currentPacketPtr += sizeof(_position);
|
currentPacketPtr += sizeof(_position);
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
|
|
||||||
#include "AudioRingBuffer.h"
|
#include "AudioRingBuffer.h"
|
||||||
|
|
||||||
const int STREAM_IDENTIFIER_NUM_BYTES = 8;
|
|
||||||
|
|
||||||
const int MAX_INJECTOR_VOLUME = 0xFF;
|
const int MAX_INJECTOR_VOLUME = 0xFF;
|
||||||
|
|
||||||
const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000);
|
const int INJECT_INTERVAL_USECS = floorf((BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SAMPLE_RATE) * 1000000);
|
||||||
|
@ -61,7 +59,6 @@ public slots:
|
||||||
int16_t& sampleAt(const int index);
|
int16_t& sampleAt(const int index);
|
||||||
void insertSample(const int index, int sample);
|
void insertSample(const int index, int sample);
|
||||||
private:
|
private:
|
||||||
unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES];
|
|
||||||
int16_t* _audioSampleArray;
|
int16_t* _audioSampleArray;
|
||||||
int _numTotalSamples;
|
int _numTotalSamples;
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
|
|
|
@ -9,13 +9,13 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "InjectedAudioRingBuffer.h"
|
#include "InjectedAudioRingBuffer.h"
|
||||||
|
|
||||||
InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
|
InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
|
||||||
_radius(0.0f),
|
_radius(0.0f),
|
||||||
_attenuationRatio(0),
|
_attenuationRatio(0)
|
||||||
_streamIdentifier()
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,8 @@ InjectedAudioRingBuffer::InjectedAudioRingBuffer() :
|
||||||
int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
int InjectedAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
|
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
|
||||||
|
|
||||||
// pull stream identifier from the packet
|
// push past the UUID for this injector
|
||||||
memcpy(&_streamIdentifier, currentBuffer, sizeof(_streamIdentifier));
|
currentBuffer += NUM_BYTES_RFC4122_UUID;
|
||||||
currentBuffer += sizeof(_streamIdentifier);
|
|
||||||
|
|
||||||
// use parsePositionalData in parent PostionalAudioRingBuffer class to pull common positional data
|
// use parsePositionalData in parent PostionalAudioRingBuffer class to pull common positional data
|
||||||
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
||||||
|
|
|
@ -21,7 +21,6 @@ public:
|
||||||
|
|
||||||
float getRadius() const { return _radius; }
|
float getRadius() const { return _radius; }
|
||||||
float getAttenuationRatio() const { return _attenuationRatio; }
|
float getAttenuationRatio() const { return _attenuationRatio; }
|
||||||
const unsigned char* getStreamIdentifier() const { return _streamIdentifier; }
|
|
||||||
private:
|
private:
|
||||||
// disallow copying of InjectedAudioRingBuffer objects
|
// disallow copying of InjectedAudioRingBuffer objects
|
||||||
InjectedAudioRingBuffer(const InjectedAudioRingBuffer&);
|
InjectedAudioRingBuffer(const InjectedAudioRingBuffer&);
|
||||||
|
@ -29,7 +28,6 @@ private:
|
||||||
|
|
||||||
float _radius;
|
float _radius;
|
||||||
float _attenuationRatio;
|
float _attenuationRatio;
|
||||||
unsigned char _streamIdentifier[STREAM_IDENTIFIER_NUM_BYTES];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__InjectedAudioRingBuffer__) */
|
#endif /* defined(__hifi__InjectedAudioRingBuffer__) */
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
|
|
||||||
#include <Node.h>
|
#include <Node.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#include "PositionalAudioRingBuffer.h"
|
#include "PositionalAudioRingBuffer.h"
|
||||||
|
|
||||||
|
@ -17,9 +18,7 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer() :
|
||||||
AudioRingBuffer(false),
|
AudioRingBuffer(false),
|
||||||
_position(0.0f, 0.0f, 0.0f),
|
_position(0.0f, 0.0f, 0.0f),
|
||||||
_orientation(0.0f, 0.0f, 0.0f, 0.0f),
|
_orientation(0.0f, 0.0f, 0.0f, 0.0f),
|
||||||
_willBeAddedToMix(false),
|
_willBeAddedToMix(false)
|
||||||
_listenMode(AudioRingBuffer::NORMAL),
|
|
||||||
_listenRadius(0.0f)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -27,65 +26,15 @@ PositionalAudioRingBuffer::PositionalAudioRingBuffer() :
|
||||||
PositionalAudioRingBuffer::~PositionalAudioRingBuffer() {
|
PositionalAudioRingBuffer::~PositionalAudioRingBuffer() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PositionalAudioRingBuffer::isListeningToNode(Node& other) const {
|
|
||||||
switch (_listenMode) {
|
|
||||||
default:
|
|
||||||
case AudioRingBuffer::NORMAL:
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case AudioRingBuffer::OMNI_DIRECTIONAL_POINT: {
|
|
||||||
PositionalAudioRingBuffer* otherNodeBuffer = (PositionalAudioRingBuffer*) other.getLinkedData();
|
|
||||||
float distance = glm::distance(_position, otherNodeBuffer->_position);
|
|
||||||
return distance <= _listenRadius;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case AudioRingBuffer::SELECTED_SOURCES:
|
|
||||||
for (int i = 0; i < _listenSources.size(); i++) {
|
|
||||||
if (other.getNodeID() == _listenSources[i]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
int PositionalAudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
|
unsigned char* currentBuffer = sourceBuffer + numBytesForPacketHeader(sourceBuffer);
|
||||||
currentBuffer += sizeof(uint16_t); // the source ID
|
currentBuffer += NUM_BYTES_RFC4122_UUID; // the source UUID
|
||||||
currentBuffer += parseListenModeData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
|
||||||
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
currentBuffer += parsePositionalData(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
||||||
currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
currentBuffer += parseAudioSamples(currentBuffer, numBytes - (currentBuffer - sourceBuffer));
|
||||||
|
|
||||||
return currentBuffer - sourceBuffer;
|
return currentBuffer - sourceBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PositionalAudioRingBuffer::parseListenModeData(unsigned char* sourceBuffer, int numBytes) {
|
|
||||||
unsigned char* currentBuffer = sourceBuffer;
|
|
||||||
|
|
||||||
memcpy(&_listenMode, currentBuffer, sizeof(_listenMode));
|
|
||||||
currentBuffer += sizeof(_listenMode);
|
|
||||||
|
|
||||||
if (_listenMode == AudioRingBuffer::OMNI_DIRECTIONAL_POINT) {
|
|
||||||
memcpy(&_listenRadius, currentBuffer, sizeof(_listenRadius));
|
|
||||||
currentBuffer += sizeof(_listenRadius);
|
|
||||||
} else if (_listenMode == AudioRingBuffer::SELECTED_SOURCES) {
|
|
||||||
int listenSourcesCount;
|
|
||||||
memcpy(&listenSourcesCount, currentBuffer, sizeof(listenSourcesCount));
|
|
||||||
currentBuffer += sizeof(listenSourcesCount);
|
|
||||||
for (int i = 0; i < listenSourcesCount; i++) {
|
|
||||||
int sourceID;
|
|
||||||
memcpy(&sourceID, currentBuffer, sizeof(sourceID));
|
|
||||||
currentBuffer += sizeof(sourceID);
|
|
||||||
_listenSources.push_back(sourceID);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentBuffer - sourceBuffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
int PositionalAudioRingBuffer::parsePositionalData(unsigned char* sourceBuffer, int numBytes) {
|
int PositionalAudioRingBuffer::parsePositionalData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
unsigned char* currentBuffer = sourceBuffer;
|
unsigned char* currentBuffer = sourceBuffer;
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,6 @@ 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; }
|
||||||
|
|
||||||
bool isListeningToNode(Node& other) const;
|
|
||||||
ListenMode getListeningMode() const { return _listenMode; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// disallow copying of PositionalAudioRingBuffer objects
|
// disallow copying of PositionalAudioRingBuffer objects
|
||||||
|
@ -42,10 +39,6 @@ protected:
|
||||||
glm::vec3 _position;
|
glm::vec3 _position;
|
||||||
glm::quat _orientation;
|
glm::quat _orientation;
|
||||||
bool _willBeAddedToMix;
|
bool _willBeAddedToMix;
|
||||||
|
|
||||||
ListenMode _listenMode;
|
|
||||||
float _listenRadius;
|
|
||||||
std::vector<int> _listenSources;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__PositionalAudioRingBuffer__) */
|
#endif /* defined(__hifi__PositionalAudioRingBuffer__) */
|
||||||
|
|
|
@ -13,9 +13,10 @@
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
#include <VoxelConstants.h>
|
||||||
|
|
||||||
#include "AvatarData.h"
|
#include "AvatarData.h"
|
||||||
#include <VoxelConstants.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -29,7 +30,7 @@ AvatarData::AvatarData(Node* owningNode) :
|
||||||
_bodyPitch(0.0),
|
_bodyPitch(0.0),
|
||||||
_bodyRoll(0.0),
|
_bodyRoll(0.0),
|
||||||
_newScale(1.0f),
|
_newScale(1.0f),
|
||||||
_leaderID(UNKNOWN_NODE_ID),
|
_leaderUUID(),
|
||||||
_handState(0),
|
_handState(0),
|
||||||
_cameraPosition(0,0,0),
|
_cameraPosition(0,0,0),
|
||||||
_cameraOrientation(),
|
_cameraOrientation(),
|
||||||
|
@ -53,22 +54,6 @@ AvatarData::~AvatarData() {
|
||||||
delete _handData;
|
delete _handData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AvatarData::sendData() {
|
|
||||||
|
|
||||||
// called from Agent visual loop to send data
|
|
||||||
if (Node* avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER)) {
|
|
||||||
unsigned char packet[MAX_PACKET_SIZE];
|
|
||||||
|
|
||||||
unsigned char* endOfPacket = packet;
|
|
||||||
endOfPacket += populateTypeAndVersion(endOfPacket, PACKET_TYPE_HEAD_DATA);
|
|
||||||
endOfPacket += packNodeId(endOfPacket, NodeList::getInstance()->getOwnerID());
|
|
||||||
|
|
||||||
int numPacketBytes = (endOfPacket - packet) + getBroadcastData(endOfPacket);
|
|
||||||
|
|
||||||
NodeList::getInstance()->getNodeSocket()->send(avatarMixer->getActiveSocket(), packet, numPacketBytes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
||||||
unsigned char* bufferStart = destinationBuffer;
|
unsigned char* bufferStart = destinationBuffer;
|
||||||
|
|
||||||
|
@ -103,8 +88,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
|
||||||
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _newScale);
|
destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _newScale);
|
||||||
|
|
||||||
// Follow mode info
|
// Follow mode info
|
||||||
memcpy(destinationBuffer, &_leaderID, sizeof(uint16_t));
|
memcpy(destinationBuffer, _leaderUUID.toRfc4122().constData(), NUM_BYTES_RFC4122_UUID);
|
||||||
destinationBuffer += sizeof(uint16_t);
|
destinationBuffer += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
|
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||||
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw);
|
destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _headData->_yaw);
|
||||||
|
@ -220,11 +205,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
|
|
||||||
unsigned char* startPosition = sourceBuffer;
|
unsigned char* startPosition = sourceBuffer;
|
||||||
|
|
||||||
// push past the node ID
|
// push past the node session UUID
|
||||||
sourceBuffer += sizeof(uint16_t);
|
sourceBuffer += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// UUID
|
// user UUID
|
||||||
const int NUM_BYTES_RFC4122_UUID = 16;
|
|
||||||
_uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
|
_uuid = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
|
||||||
sourceBuffer += NUM_BYTES_RFC4122_UUID;
|
sourceBuffer += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
|
@ -241,8 +225,8 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _newScale);
|
sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer, _newScale);
|
||||||
|
|
||||||
// Follow mode info
|
// Follow mode info
|
||||||
memcpy(&_leaderID, sourceBuffer, sizeof(uint16_t));
|
_leaderUUID = QUuid::fromRfc4122(QByteArray((char*) sourceBuffer, NUM_BYTES_RFC4122_UUID));
|
||||||
sourceBuffer += sizeof(uint16_t);
|
sourceBuffer += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
|
// Head rotation (NOTE: This needs to become a quaternion to save two bytes)
|
||||||
float headYaw, headPitch, headRoll;
|
float headYaw, headPitch, headRoll;
|
||||||
|
|
|
@ -120,13 +120,12 @@ public:
|
||||||
bool getWantDelta() const { return _wantDelta; }
|
bool getWantDelta() const { return _wantDelta; }
|
||||||
bool getWantLowResMoving() const { return _wantLowResMoving; }
|
bool getWantLowResMoving() const { return _wantLowResMoving; }
|
||||||
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
|
bool getWantOcclusionCulling() const { return _wantOcclusionCulling; }
|
||||||
uint16_t getLeaderID() const { return _leaderID; }
|
const QUuid& getLeaderUUID() const { return _leaderUUID; }
|
||||||
|
|
||||||
void setHeadData(HeadData* headData) { _headData = headData; }
|
void setHeadData(HeadData* headData) { _headData = headData; }
|
||||||
void setHandData(HandData* handData) { _handData = handData; }
|
void setHandData(HandData* handData) { _handData = handData; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void sendData();
|
|
||||||
void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; }
|
void setWantLowResMoving(bool wantLowResMoving) { _wantLowResMoving = wantLowResMoving; }
|
||||||
void setWantColor(bool wantColor) { _wantColor = wantColor; }
|
void setWantColor(bool wantColor) { _wantColor = wantColor; }
|
||||||
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
|
void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; }
|
||||||
|
@ -147,7 +146,7 @@ protected:
|
||||||
float _newScale;
|
float _newScale;
|
||||||
|
|
||||||
// Following mode infos
|
// Following mode infos
|
||||||
uint16_t _leaderID;
|
QUuid _leaderUUID;
|
||||||
|
|
||||||
// Hand state (are we grabbing something or not)
|
// Hand state (are we grabbing something or not)
|
||||||
char _handState;
|
char _handState;
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
#include "UUID.h"
|
||||||
|
|
||||||
#include <QtCore/QDataStream>
|
#include <QtCore/QDataStream>
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
#include "NodeList.h"
|
#include "NodeList.h"
|
||||||
|
|
||||||
const int NUM_BYTES_RFC4122_UUID = 16;
|
|
||||||
const int MAX_PAYLOAD_BYTES = 1024;
|
const int MAX_PAYLOAD_BYTES = 1024;
|
||||||
|
|
||||||
/// Holds information used for request, creation, and deployment of assignments
|
/// Holds information used for request, creation, and deployment of assignments
|
||||||
|
|
|
@ -23,19 +23,9 @@
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
|
||||||
int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) {
|
Node::Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket) :
|
||||||
memcpy(nodeId, packedData, sizeof(uint16_t));
|
|
||||||
return sizeof(uint16_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
int packNodeId(unsigned char* packStore, uint16_t nodeId) {
|
|
||||||
memcpy(packStore, &nodeId, sizeof(uint16_t));
|
|
||||||
return sizeof(uint16_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node::Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID) :
|
|
||||||
_type(type),
|
_type(type),
|
||||||
_nodeID(nodeID),
|
_uuid(uuid),
|
||||||
_wakeMicrostamp(usecTimestampNow()),
|
_wakeMicrostamp(usecTimestampNow()),
|
||||||
_lastHeardMicrostamp(usecTimestampNow()),
|
_lastHeardMicrostamp(usecTimestampNow()),
|
||||||
_activeSocket(NULL),
|
_activeSocket(NULL),
|
||||||
|
@ -106,10 +96,12 @@ const char* Node::getTypeName() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::activateLocalSocket() {
|
void Node::activateLocalSocket() {
|
||||||
|
qDebug() << "Activating local socket for node" << *this << "\n";
|
||||||
_activeSocket = _localSocket;
|
_activeSocket = _localSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::activatePublicSocket() {
|
void Node::activatePublicSocket() {
|
||||||
|
qDebug() << "Activating public socket for node" << *this << "\n";
|
||||||
_activeSocket = _publicSocket;
|
_activeSocket = _publicSocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,10 +144,12 @@ QDebug operator<<(QDebug debug, const Node &node) {
|
||||||
char publicAddressBuffer[16] = {'\0'};
|
char publicAddressBuffer[16] = {'\0'};
|
||||||
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket());
|
unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket());
|
||||||
|
|
||||||
//char localAddressBuffer[16] = {'\0'};
|
char localAddressBuffer[16] = {'\0'};
|
||||||
//unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.localSocket);
|
unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.getLocalSocket());
|
||||||
|
|
||||||
debug << "#" << node.getNodeID() << node.getTypeName() << node.getType();
|
debug.nospace() << node.getTypeName() << " (" << node.getType() << ")";
|
||||||
|
debug << " " << node.getUUID().toString().toLocal8Bit().constData() << " ";
|
||||||
debug.nospace() << publicAddressBuffer << ":" << publicAddressPort;
|
debug.nospace() << publicAddressBuffer << ":" << publicAddressPort;
|
||||||
|
debug.nospace() << " / " << localAddressBuffer << ":" << localAddressPort;
|
||||||
return debug.nospace();
|
return debug.nospace();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,13 +19,14 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
#include "NodeData.h"
|
#include "NodeData.h"
|
||||||
#include "SimpleMovingAverage.h"
|
#include "SimpleMovingAverage.h"
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
public:
|
public:
|
||||||
Node(sockaddr* publicSocket, sockaddr* localSocket, char type, uint16_t nodeID);
|
Node(const QUuid& uuid, char type, sockaddr* publicSocket, sockaddr* localSocket);
|
||||||
~Node();
|
~Node();
|
||||||
|
|
||||||
bool operator==(const Node& otherNode);
|
bool operator==(const Node& otherNode);
|
||||||
|
@ -36,8 +37,8 @@ public:
|
||||||
void setType(char type) { _type = type; }
|
void setType(char type) { _type = type; }
|
||||||
const char* getTypeName() const;
|
const char* getTypeName() const;
|
||||||
|
|
||||||
uint16_t getNodeID() const { return _nodeID; }
|
const QUuid& getUUID() const { return _uuid; }
|
||||||
void setNodeID(uint16_t nodeID) { _nodeID = nodeID;}
|
void setUUID(const QUuid& uuid) { _uuid = uuid; }
|
||||||
|
|
||||||
uint64_t getWakeMicrostamp() const { return _wakeMicrostamp; }
|
uint64_t getWakeMicrostamp() const { return _wakeMicrostamp; }
|
||||||
void setWakeMicrostamp(uint64_t wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
|
void setWakeMicrostamp(uint64_t wakeMicrostamp) { _wakeMicrostamp = wakeMicrostamp; }
|
||||||
|
@ -78,7 +79,7 @@ private:
|
||||||
Node& operator=(Node otherNode);
|
Node& operator=(Node otherNode);
|
||||||
|
|
||||||
char _type;
|
char _type;
|
||||||
uint16_t _nodeID;
|
QUuid _uuid;
|
||||||
uint64_t _wakeMicrostamp;
|
uint64_t _wakeMicrostamp;
|
||||||
uint64_t _lastHeardMicrostamp;
|
uint64_t _lastHeardMicrostamp;
|
||||||
sockaddr* _publicSocket;
|
sockaddr* _publicSocket;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "NodeTypes.h"
|
#include "NodeTypes.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
#include "UUID.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Syssocket.h"
|
#include "Syssocket.h"
|
||||||
|
@ -67,12 +68,14 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) :
|
||||||
_nodeSocket(newSocketListenPort),
|
_nodeSocket(newSocketListenPort),
|
||||||
_ownerType(newOwnerType),
|
_ownerType(newOwnerType),
|
||||||
_nodeTypesOfInterest(NULL),
|
_nodeTypesOfInterest(NULL),
|
||||||
_ownerID(UNKNOWN_NODE_ID),
|
_ownerUUID(QUuid::createUuid()),
|
||||||
_lastNodeID(UNKNOWN_NODE_ID + 1),
|
|
||||||
_numNoReplyDomainCheckIns(0),
|
_numNoReplyDomainCheckIns(0),
|
||||||
_assignmentServerSocket(NULL),
|
_assignmentServerSocket(NULL),
|
||||||
_checkInPacket(NULL),
|
_checkInPacket(NULL),
|
||||||
_numBytesCheckInPacket(0)
|
_numBytesCheckInPacket(0),
|
||||||
|
_publicAddress(),
|
||||||
|
_publicPort(0),
|
||||||
|
_shouldUseDomainServerAsSTUN(0)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -115,8 +118,6 @@ void NodeList::setDomainHostname(const QString& domainHostname) {
|
||||||
_domainIP.clear();
|
_domainIP.clear();
|
||||||
notifyDomainChanged();
|
notifyDomainChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
void NodeList::timePingReply(sockaddr *nodeAddress, unsigned char *packetData) {
|
||||||
|
@ -143,16 +144,25 @@ void NodeList::processNodeData(sockaddr* senderAddress, unsigned char* packetDat
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_TYPE_PING: {
|
case PACKET_TYPE_PING: {
|
||||||
char pingPacket[dataBytes];
|
// send it right back
|
||||||
memcpy(pingPacket, packetData, dataBytes);
|
populateTypeAndVersion(packetData, PACKET_TYPE_PING_REPLY);
|
||||||
populateTypeAndVersion((unsigned char*) pingPacket, PACKET_TYPE_PING_REPLY);
|
_nodeSocket.send(senderAddress, packetData, dataBytes);
|
||||||
_nodeSocket.send(senderAddress, pingPacket, dataBytes);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PACKET_TYPE_PING_REPLY: {
|
case PACKET_TYPE_PING_REPLY: {
|
||||||
|
// activate the appropriate socket for this node, if not yet updated
|
||||||
|
activateSocketFromPingReply(senderAddress);
|
||||||
|
|
||||||
|
// set the ping time for this node for stat collection
|
||||||
timePingReply(senderAddress, packetData);
|
timePingReply(senderAddress, packetData);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case PACKET_TYPE_STUN_RESPONSE: {
|
||||||
|
// a STUN packet begins with 00, we've checked the second zero with packetVersionMatch
|
||||||
|
// pass it along so it can be processed into our public address and port
|
||||||
|
processSTUNResponse(packetData, dataBytes);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,19 +184,18 @@ void NodeList::processBulkNodeData(sockaddr *senderAddress, unsigned char *packe
|
||||||
// we've already verified packet version for the bulk packet, so all head data in the packet is also up to date
|
// we've already verified packet version for the bulk packet, so all head data in the packet is also up to date
|
||||||
populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA);
|
populateTypeAndVersion(packetHolder, PACKET_TYPE_HEAD_DATA);
|
||||||
|
|
||||||
uint16_t nodeID = -1;
|
|
||||||
|
|
||||||
while ((currentPosition - startPosition) < numTotalBytes) {
|
while ((currentPosition - startPosition) < numTotalBytes) {
|
||||||
unpackNodeId(currentPosition, &nodeID);
|
|
||||||
memcpy(packetHolder + numBytesPacketHeader,
|
memcpy(packetHolder + numBytesPacketHeader,
|
||||||
currentPosition,
|
currentPosition,
|
||||||
numTotalBytes - (currentPosition - startPosition));
|
numTotalBytes - (currentPosition - startPosition));
|
||||||
|
|
||||||
Node* matchingNode = nodeWithID(nodeID);
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)currentPosition, NUM_BYTES_RFC4122_UUID));
|
||||||
|
Node* matchingNode = nodeWithUUID(nodeUUID);
|
||||||
|
|
||||||
if (!matchingNode) {
|
if (!matchingNode) {
|
||||||
// we're missing this node, we need to add it to the list
|
// we're missing this node, we need to add it to the list
|
||||||
matchingNode = addOrUpdateNode(NULL, NULL, NODE_TYPE_AGENT, nodeID);
|
matchingNode = addOrUpdateNode(nodeUUID, NODE_TYPE_AGENT, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPosition += updateNodeWithData(matchingNode,
|
currentPosition += updateNodeWithData(matchingNode,
|
||||||
|
@ -238,9 +247,9 @@ Node* NodeList::nodeWithAddress(sockaddr *senderAddress) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* NodeList::nodeWithID(uint16_t nodeID) {
|
Node* NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||||
if (node->getNodeID() == nodeID) {
|
if (node->getUUID() == nodeUUID) {
|
||||||
return &(*node);
|
return &(*node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -288,6 +297,9 @@ void NodeList::reset() {
|
||||||
|
|
||||||
delete _nodeTypesOfInterest;
|
delete _nodeTypesOfInterest;
|
||||||
_nodeTypesOfInterest = NULL;
|
_nodeTypesOfInterest = NULL;
|
||||||
|
|
||||||
|
// refresh the owner UUID
|
||||||
|
_ownerUUID = QUuid::createUuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
||||||
|
@ -298,7 +310,137 @@ void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNo
|
||||||
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
_nodeTypesOfInterest[numNodeTypesOfInterest] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
|
const uint32_t RFC_5389_MAGIC_COOKIE = 0x2112A442;
|
||||||
|
const int NUM_BYTES_STUN_HEADER = 20;
|
||||||
|
const int NUM_STUN_REQUESTS_BEFORE_FALLBACK = 5;
|
||||||
|
|
||||||
|
void NodeList::sendSTUNRequest() {
|
||||||
|
const char STUN_SERVER_HOSTNAME[] = "stun.highfidelity.io";
|
||||||
|
const unsigned short STUN_SERVER_PORT = 3478;
|
||||||
|
|
||||||
|
static int failedStunRequests = 0;
|
||||||
|
|
||||||
|
if (failedStunRequests < NUM_STUN_REQUESTS_BEFORE_FALLBACK) {
|
||||||
|
unsigned char stunRequestPacket[NUM_BYTES_STUN_HEADER];
|
||||||
|
|
||||||
|
int packetIndex = 0;
|
||||||
|
|
||||||
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
|
// leading zeros + message type
|
||||||
|
const uint16_t REQUEST_MESSAGE_TYPE = htons(0x0001);
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &REQUEST_MESSAGE_TYPE, sizeof(REQUEST_MESSAGE_TYPE));
|
||||||
|
packetIndex += sizeof(REQUEST_MESSAGE_TYPE);
|
||||||
|
|
||||||
|
// message length (no additional attributes are included)
|
||||||
|
uint16_t messageLength = 0;
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &messageLength, sizeof(messageLength));
|
||||||
|
packetIndex += sizeof(messageLength);
|
||||||
|
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &RFC_5389_MAGIC_COOKIE_NETWORK_ORDER, sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER));
|
||||||
|
packetIndex += sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
|
||||||
|
// transaction ID (random 12-byte unsigned integer)
|
||||||
|
const uint NUM_TRANSACTION_ID_BYTES = 12;
|
||||||
|
unsigned char transactionID[NUM_TRANSACTION_ID_BYTES];
|
||||||
|
loadRandomIdentifier(transactionID, NUM_TRANSACTION_ID_BYTES);
|
||||||
|
memcpy(stunRequestPacket + packetIndex, &transactionID, sizeof(transactionID));
|
||||||
|
|
||||||
|
// lookup the IP for the STUN server
|
||||||
|
static QHostInfo stunInfo = QHostInfo::fromName(STUN_SERVER_HOSTNAME);
|
||||||
|
|
||||||
|
for (int i = 0; i < stunInfo.addresses().size(); i++) {
|
||||||
|
if (stunInfo.addresses()[i].protocol() == QAbstractSocket::IPv4Protocol) {
|
||||||
|
QString stunIPAddress = stunInfo.addresses()[i].toString();
|
||||||
|
|
||||||
|
qDebug("Sending a stun request to %s\n", stunIPAddress.toLocal8Bit().constData());
|
||||||
|
|
||||||
|
_nodeSocket.send(stunIPAddress.toLocal8Bit().constData(),
|
||||||
|
STUN_SERVER_PORT,
|
||||||
|
stunRequestPacket,
|
||||||
|
sizeof(stunRequestPacket));
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
failedStunRequests++;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we're here this was the last failed STUN request
|
||||||
|
// use our DS as our stun server
|
||||||
|
qDebug("Failed to lookup public address via STUN server at %s:%hu. Using DS for STUN.\n",
|
||||||
|
STUN_SERVER_HOSTNAME, STUN_SERVER_PORT);
|
||||||
|
_shouldUseDomainServerAsSTUN = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeList::processSTUNResponse(unsigned char* packetData, size_t dataBytes) {
|
||||||
|
// check the cookie to make sure this is actually a STUN response
|
||||||
|
// and read the first attribute and make sure it is a XOR_MAPPED_ADDRESS
|
||||||
|
const int NUM_BYTES_MESSAGE_TYPE_AND_LENGTH = 4;
|
||||||
|
const uint16_t XOR_MAPPED_ADDRESS_TYPE = htons(0x0020);
|
||||||
|
|
||||||
|
const uint32_t RFC_5389_MAGIC_COOKIE_NETWORK_ORDER = htonl(RFC_5389_MAGIC_COOKIE);
|
||||||
|
|
||||||
|
int attributeStartIndex = NUM_BYTES_STUN_HEADER;
|
||||||
|
|
||||||
|
if (memcmp(packetData + NUM_BYTES_MESSAGE_TYPE_AND_LENGTH,
|
||||||
|
&RFC_5389_MAGIC_COOKIE_NETWORK_ORDER,
|
||||||
|
sizeof(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER)) == 0) {
|
||||||
|
|
||||||
|
// enumerate the attributes to find XOR_MAPPED_ADDRESS_TYPE
|
||||||
|
while (attributeStartIndex < dataBytes) {
|
||||||
|
if (memcmp(packetData + attributeStartIndex, &XOR_MAPPED_ADDRESS_TYPE, sizeof(XOR_MAPPED_ADDRESS_TYPE)) == 0) {
|
||||||
|
const int NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH = 4;
|
||||||
|
const int NUM_BYTES_FAMILY_ALIGN = 1;
|
||||||
|
const uint8_t IPV4_FAMILY_NETWORK_ORDER = htons(0x01) >> 8;
|
||||||
|
|
||||||
|
int byteIndex = attributeStartIndex + NUM_BYTES_STUN_ATTR_TYPE_AND_LENGTH + NUM_BYTES_FAMILY_ALIGN;
|
||||||
|
|
||||||
|
uint8_t addressFamily = 0;
|
||||||
|
memcpy(&addressFamily, packetData + byteIndex, sizeof(addressFamily));
|
||||||
|
|
||||||
|
byteIndex += sizeof(addressFamily);
|
||||||
|
|
||||||
|
if (addressFamily == IPV4_FAMILY_NETWORK_ORDER) {
|
||||||
|
// grab the X-Port
|
||||||
|
uint16_t xorMappedPort = 0;
|
||||||
|
memcpy(&xorMappedPort, packetData + byteIndex, sizeof(xorMappedPort));
|
||||||
|
|
||||||
|
_publicPort = ntohs(xorMappedPort) ^ (ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER) >> 16);
|
||||||
|
|
||||||
|
byteIndex += sizeof(xorMappedPort);
|
||||||
|
|
||||||
|
// grab the X-Address
|
||||||
|
uint32_t xorMappedAddress = 0;
|
||||||
|
memcpy(&xorMappedAddress, packetData + byteIndex, sizeof(xorMappedAddress));
|
||||||
|
|
||||||
|
uint32_t stunAddress = ntohl(xorMappedAddress) ^ ntohl(RFC_5389_MAGIC_COOKIE_NETWORK_ORDER);
|
||||||
|
_publicAddress = QHostAddress(stunAddress);
|
||||||
|
|
||||||
|
qDebug("Public socket received from STUN server is %s:%hu\n",
|
||||||
|
_publicAddress.toString().toLocal8Bit().constData(),
|
||||||
|
_publicPort);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// push forward attributeStartIndex by the length of this attribute
|
||||||
|
const int NUM_BYTES_ATTRIBUTE_TYPE = 2;
|
||||||
|
|
||||||
|
uint16_t attributeLength = 0;
|
||||||
|
memcpy(&attributeLength, packetData + attributeStartIndex + NUM_BYTES_ATTRIBUTE_TYPE, sizeof(attributeLength));
|
||||||
|
attributeLength = ntohs(attributeLength);
|
||||||
|
|
||||||
|
attributeStartIndex += NUM_BYTES_MESSAGE_TYPE_AND_LENGTH + attributeLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeList::sendDomainServerCheckIn() {
|
||||||
static bool printedDomainServerIP = false;
|
static bool printedDomainServerIP = false;
|
||||||
|
|
||||||
// Lookup the IP address of the domain server if we need to
|
// Lookup the IP address of the domain server if we need to
|
||||||
|
@ -329,56 +471,66 @@ void NodeList::sendDomainServerCheckIn(const char* assignmentUUID) {
|
||||||
printedDomainServerIP = true;
|
printedDomainServerIP = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct the DS check in packet if we need to
|
if (_publicAddress.isNull() && !_shouldUseDomainServerAsSTUN) {
|
||||||
if (!_checkInPacket) {
|
// we don't know our public socket and we need to send it to the domain server
|
||||||
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
|
// send a STUN request to figure it out
|
||||||
|
sendSTUNRequest();
|
||||||
const int IP_ADDRESS_BYTES = 4;
|
} else {
|
||||||
|
// construct the DS check in packet if we need to
|
||||||
// check in packet has header, optional UUID, node type, port, IP, node types of interest, null termination
|
if (!_checkInPacket) {
|
||||||
int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) +
|
int numBytesNodesOfInterest = _nodeTypesOfInterest ? strlen((char*) _nodeTypesOfInterest) : 0;
|
||||||
NUM_BYTES_RFC4122_UUID + sizeof(uint16_t) + IP_ADDRESS_BYTES + numBytesNodesOfInterest + sizeof(unsigned char);
|
|
||||||
|
const int IP_ADDRESS_BYTES = 4;
|
||||||
_checkInPacket = new unsigned char[numPacketBytes];
|
|
||||||
unsigned char* packetPosition = _checkInPacket;
|
// check in packet has header, optional UUID, node type, port, IP, node types of interest, null termination
|
||||||
|
int numPacketBytes = sizeof(PACKET_TYPE) + sizeof(PACKET_VERSION) + sizeof(NODE_TYPE) +
|
||||||
PACKET_TYPE nodePacketType = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES)))
|
NUM_BYTES_RFC4122_UUID + (2 * (sizeof(uint16_t) + IP_ADDRESS_BYTES)) +
|
||||||
? PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
|
numBytesNodesOfInterest + sizeof(unsigned char);
|
||||||
: PACKET_TYPE_DOMAIN_LIST_REQUEST;
|
|
||||||
|
_checkInPacket = new unsigned char[numPacketBytes];
|
||||||
int numHeaderBytes = populateTypeAndVersion(packetPosition, nodePacketType);
|
unsigned char* packetPosition = _checkInPacket;
|
||||||
packetPosition += numHeaderBytes;
|
|
||||||
|
PACKET_TYPE nodePacketType = (memchr(SOLO_NODE_TYPES, _ownerType, sizeof(SOLO_NODE_TYPES)))
|
||||||
*(packetPosition++) = _ownerType;
|
? PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY
|
||||||
|
: PACKET_TYPE_DOMAIN_LIST_REQUEST;
|
||||||
if (assignmentUUID) {
|
|
||||||
// if we've got an assignment UUID to send add that here
|
packetPosition += populateTypeAndVersion(packetPosition, nodePacketType);
|
||||||
memcpy(packetPosition, assignmentUUID, NUM_BYTES_RFC4122_UUID);
|
|
||||||
packetPosition += NUM_BYTES_RFC4122_UUID;
|
*(packetPosition++) = _ownerType;
|
||||||
|
|
||||||
|
// send our owner UUID or the null one
|
||||||
|
QByteArray rfcOwnerUUID = _ownerUUID.toRfc4122();
|
||||||
|
memcpy(packetPosition, rfcOwnerUUID.constData(), rfcOwnerUUID.size());
|
||||||
|
packetPosition += rfcOwnerUUID.size();
|
||||||
|
|
||||||
|
// pack our public address to send to domain-server
|
||||||
|
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
|
||||||
|
htonl(_publicAddress.toIPv4Address()), htons(_publicPort));
|
||||||
|
|
||||||
|
// pack our local address to send to domain-server
|
||||||
|
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
|
||||||
|
getLocalAddress(),
|
||||||
|
htons(_nodeSocket.getListeningPort()));
|
||||||
|
|
||||||
|
// add the number of bytes for node types of interest
|
||||||
|
*(packetPosition++) = numBytesNodesOfInterest;
|
||||||
|
|
||||||
|
// copy over the bytes for node types of interest, if required
|
||||||
|
if (numBytesNodesOfInterest > 0) {
|
||||||
|
memcpy(packetPosition,
|
||||||
|
_nodeTypesOfInterest,
|
||||||
|
numBytesNodesOfInterest);
|
||||||
|
packetPosition += numBytesNodesOfInterest;
|
||||||
|
}
|
||||||
|
|
||||||
|
_numBytesCheckInPacket = packetPosition - _checkInPacket;
|
||||||
}
|
}
|
||||||
|
|
||||||
packetPosition += packSocket(_checkInPacket + (packetPosition - _checkInPacket),
|
_nodeSocket.send(_domainIP.toString().toLocal8Bit().constData(), _domainPort, _checkInPacket, _numBytesCheckInPacket);
|
||||||
getLocalAddress(),
|
|
||||||
htons(_nodeSocket.getListeningPort()));
|
|
||||||
|
|
||||||
// add the number of bytes for node types of interest
|
// increment the count of un-replied check-ins
|
||||||
*(packetPosition++) = numBytesNodesOfInterest;
|
_numNoReplyDomainCheckIns++;
|
||||||
|
|
||||||
// copy over the bytes for node types of interest, if required
|
|
||||||
if (numBytesNodesOfInterest > 0) {
|
|
||||||
memcpy(packetPosition,
|
|
||||||
_nodeTypesOfInterest,
|
|
||||||
numBytesNodesOfInterest);
|
|
||||||
packetPosition += numBytesNodesOfInterest;
|
|
||||||
}
|
|
||||||
|
|
||||||
_numBytesCheckInPacket = packetPosition - _checkInPacket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_nodeSocket.send(_domainIP.toString().toLocal8Bit().constData(), _domainPort, _checkInPacket, _numBytesCheckInPacket);
|
|
||||||
|
|
||||||
// increment the count of un-replied check-ins
|
|
||||||
_numNoReplyDomainCheckIns++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) {
|
int NodeList::processDomainServerList(unsigned char* packetData, size_t dataBytes) {
|
||||||
|
@ -388,7 +540,6 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
||||||
int readNodes = 0;
|
int readNodes = 0;
|
||||||
|
|
||||||
char nodeType;
|
char nodeType;
|
||||||
uint16_t nodeId;
|
|
||||||
|
|
||||||
// assumes only IPv4 addresses
|
// assumes only IPv4 addresses
|
||||||
sockaddr_in nodePublicSocket;
|
sockaddr_in nodePublicSocket;
|
||||||
|
@ -401,7 +552,9 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
||||||
|
|
||||||
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
|
while((readPtr - startPtr) < dataBytes - sizeof(uint16_t)) {
|
||||||
nodeType = *readPtr++;
|
nodeType = *readPtr++;
|
||||||
readPtr += unpackNodeId(readPtr, (uint16_t*) &nodeId);
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*) readPtr, NUM_BYTES_RFC4122_UUID));
|
||||||
|
readPtr += NUM_BYTES_RFC4122_UUID;
|
||||||
|
|
||||||
readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket);
|
readPtr += unpackSocket(readPtr, (sockaddr*) &nodePublicSocket);
|
||||||
readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket);
|
readPtr += unpackSocket(readPtr, (sockaddr*) &nodeLocalSocket);
|
||||||
|
|
||||||
|
@ -411,11 +564,9 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte
|
||||||
nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address());
|
nodePublicSocket.sin_addr.s_addr = htonl(_domainIP.toIPv4Address());
|
||||||
}
|
}
|
||||||
|
|
||||||
addOrUpdateNode((sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket, nodeType, nodeId);
|
addOrUpdateNode(nodeUUID, nodeType, (sockaddr*) &nodePublicSocket, (sockaddr*) &nodeLocalSocket);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read out our ID from the packet
|
|
||||||
unpackNodeId(readPtr, &_ownerID);
|
|
||||||
|
|
||||||
return readNodes;
|
return readNodes;
|
||||||
}
|
}
|
||||||
|
@ -439,41 +590,41 @@ void NodeList::sendAssignment(Assignment& assignment) {
|
||||||
_nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes);
|
_nodeSocket.send(assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) {
|
void NodeList::pingPublicAndLocalSocketsForInactiveNode(Node* node) const {
|
||||||
|
|
||||||
|
uint64_t currentTime = 0;
|
||||||
|
|
||||||
|
// setup a ping packet to send to this node
|
||||||
|
unsigned char pingPacket[numBytesForPacketHeader((uchar*) &PACKET_TYPE_PING) + sizeof(currentTime)];
|
||||||
|
int numHeaderBytes = populateTypeAndVersion(pingPacket, PACKET_TYPE_PING);
|
||||||
|
|
||||||
|
currentTime = usecTimestampNow();
|
||||||
|
memcpy(pingPacket + numHeaderBytes, ¤tTime, sizeof(currentTime));
|
||||||
|
|
||||||
|
qDebug() << "Attemping to ping" << *node << "\n";
|
||||||
|
// send the ping packet to the local and public sockets for this node
|
||||||
|
_nodeSocket.send(node->getLocalSocket(), pingPacket, sizeof(pingPacket));
|
||||||
|
_nodeSocket.send(node->getPublicSocket(), pingPacket, sizeof(pingPacket));
|
||||||
|
}
|
||||||
|
|
||||||
|
Node* NodeList::addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket) {
|
||||||
NodeList::iterator node = end();
|
NodeList::iterator node = end();
|
||||||
|
|
||||||
if (publicSocket) {
|
for (node = begin(); node != end(); node++) {
|
||||||
for (node = begin(); node != end(); node++) {
|
if (node->getUUID() == uuid) {
|
||||||
if (node->matches(publicSocket, localSocket, nodeType)) {
|
// we already have this node, stop checking
|
||||||
// we already have this node, stop checking
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node == end()) {
|
if (node == end()) {
|
||||||
// we didn't have this node, so add them
|
// we didn't have this node, so add them
|
||||||
Node* newNode = new Node(publicSocket, localSocket, nodeType, nodeId);
|
Node* newNode = new Node(uuid, nodeType, publicSocket, localSocket);
|
||||||
|
|
||||||
if (socketMatch(publicSocket, localSocket)) {
|
|
||||||
// likely debugging scenario with two nodes on local network
|
|
||||||
// set the node active right away
|
|
||||||
newNode->activatePublicSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newNode->getType() == NODE_TYPE_VOXEL_SERVER ||
|
|
||||||
newNode->getType() == NODE_TYPE_AVATAR_MIXER ||
|
|
||||||
newNode->getType() == NODE_TYPE_AUDIO_MIXER) {
|
|
||||||
// this is currently the cheat we use to talk directly to our test servers on EC2
|
|
||||||
// to be removed when we have a proper identification strategy
|
|
||||||
newNode->activatePublicSocket();
|
|
||||||
}
|
|
||||||
|
|
||||||
addNodeToList(newNode);
|
addNodeToList(newNode);
|
||||||
|
|
||||||
return newNode;
|
return newNode;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
|
if (node->getType() == NODE_TYPE_AUDIO_MIXER ||
|
||||||
node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
// until the Audio class also uses our nodeList, we need to update
|
// until the Audio class also uses our nodeList, we need to update
|
||||||
|
@ -507,25 +658,32 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt
|
||||||
unsigned n = 0;
|
unsigned n = 0;
|
||||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||||
// only send to the NodeTypes we are asked to send to.
|
// only send to the NodeTypes we are asked to send to.
|
||||||
if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
||||||
// we know which socket is good for this node, send there
|
if (node->getActiveSocket()) {
|
||||||
_nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
|
// we know which socket is good for this node, send there
|
||||||
++n;
|
_nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
|
||||||
|
++n;
|
||||||
|
} else {
|
||||||
|
// we don't have an active link to this node, ping it to set that up
|
||||||
|
pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::handlePingReply(sockaddr *nodeAddress) {
|
void NodeList::activateSocketFromPingReply(sockaddr *nodeAddress) {
|
||||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||||
// check both the public and local addresses for each node to see if we find a match
|
if (!node->getActiveSocket()) {
|
||||||
// prioritize the private address so that we prune erroneous local matches
|
// check both the public and local addresses for each node to see if we find a match
|
||||||
if (socketMatch(node->getPublicSocket(), nodeAddress)) {
|
// prioritize the private address so that we prune erroneous local matches
|
||||||
node->activatePublicSocket();
|
if (socketMatch(node->getPublicSocket(), nodeAddress)) {
|
||||||
break;
|
node->activatePublicSocket();
|
||||||
} else if (socketMatch(node->getLocalSocket(), nodeAddress)) {
|
break;
|
||||||
node->activateLocalSocket();
|
} else if (socketMatch(node->getLocalSocket(), nodeAddress)) {
|
||||||
break;
|
node->activateLocalSocket();
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,6 @@ extern const unsigned short DEFAULT_DOMAIN_SERVER_PORT;
|
||||||
|
|
||||||
const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
const char LOCAL_ASSIGNMENT_SERVER_HOSTNAME[] = "localhost";
|
||||||
|
|
||||||
const int UNKNOWN_NODE_ID = 0;
|
|
||||||
|
|
||||||
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
const int MAX_SILENT_DOMAIN_SERVER_CHECK_INS = 5;
|
||||||
|
|
||||||
class Assignment;
|
class Assignment;
|
||||||
|
@ -83,12 +81,9 @@ public:
|
||||||
|
|
||||||
unsigned short getDomainPort() const { return _domainPort; }
|
unsigned short getDomainPort() const { return _domainPort; }
|
||||||
void setDomainPort(unsigned short domainPort) { _domainPort = domainPort; }
|
void setDomainPort(unsigned short domainPort) { _domainPort = domainPort; }
|
||||||
|
|
||||||
uint16_t getLastNodeID() const { return _lastNodeID; }
|
|
||||||
void increaseNodeID() { (++_lastNodeID == UNKNOWN_NODE_ID) ? ++_lastNodeID : _lastNodeID; }
|
|
||||||
|
|
||||||
uint16_t getOwnerID() const { return _ownerID; }
|
const QUuid& getOwnerUUID() const { return _ownerUUID; }
|
||||||
void setOwnerID(uint16_t ownerID) { _ownerID = ownerID; }
|
void setOwnerUUID(const QUuid& ownerUUID) { _ownerUUID = ownerUUID; }
|
||||||
|
|
||||||
UDPSocket* getNodeSocket() { return &_nodeSocket; }
|
UDPSocket* getNodeSocket() { return &_nodeSocket; }
|
||||||
|
|
||||||
|
@ -106,16 +101,18 @@ public:
|
||||||
|
|
||||||
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
void setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest);
|
||||||
|
|
||||||
void sendDomainServerCheckIn(const char* assignmentUUID = NULL);
|
void sendDomainServerCheckIn();
|
||||||
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
int processDomainServerList(unsigned char *packetData, size_t dataBytes);
|
||||||
|
|
||||||
void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; }
|
void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; }
|
||||||
void sendAssignment(Assignment& assignment);
|
void sendAssignment(Assignment& assignment);
|
||||||
|
|
||||||
Node* nodeWithAddress(sockaddr *senderAddress);
|
void pingPublicAndLocalSocketsForInactiveNode(Node* node) const;
|
||||||
Node* nodeWithID(uint16_t nodeID);
|
|
||||||
|
|
||||||
Node* addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId);
|
Node* nodeWithAddress(sockaddr *senderAddress);
|
||||||
|
Node* nodeWithUUID(const QUuid& nodeUUID);
|
||||||
|
|
||||||
|
Node* addOrUpdateNode(const QUuid& uuid, char nodeType, sockaddr* publicSocket, sockaddr* localSocket);
|
||||||
|
|
||||||
void processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
void processNodeData(sockaddr *senderAddress, unsigned char *packetData, size_t dataBytes);
|
||||||
void processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes);
|
void processBulkNodeData(sockaddr *senderAddress, unsigned char *packetData, int numTotalBytes);
|
||||||
|
@ -153,6 +150,9 @@ private:
|
||||||
|
|
||||||
void addNodeToList(Node* newNode);
|
void addNodeToList(Node* newNode);
|
||||||
|
|
||||||
|
void sendSTUNRequest();
|
||||||
|
void processSTUNResponse(unsigned char* packetData, size_t dataBytes);
|
||||||
|
|
||||||
QString _domainHostname;
|
QString _domainHostname;
|
||||||
QHostAddress _domainIP;
|
QHostAddress _domainIP;
|
||||||
unsigned short _domainPort;
|
unsigned short _domainPort;
|
||||||
|
@ -161,16 +161,18 @@ private:
|
||||||
UDPSocket _nodeSocket;
|
UDPSocket _nodeSocket;
|
||||||
char _ownerType;
|
char _ownerType;
|
||||||
char* _nodeTypesOfInterest;
|
char* _nodeTypesOfInterest;
|
||||||
uint16_t _ownerID;
|
QUuid _ownerUUID;
|
||||||
uint16_t _lastNodeID;
|
|
||||||
pthread_t removeSilentNodesThread;
|
pthread_t removeSilentNodesThread;
|
||||||
pthread_t checkInWithDomainServerThread;
|
pthread_t checkInWithDomainServerThread;
|
||||||
int _numNoReplyDomainCheckIns;
|
int _numNoReplyDomainCheckIns;
|
||||||
sockaddr* _assignmentServerSocket;
|
sockaddr* _assignmentServerSocket;
|
||||||
uchar* _checkInPacket;
|
uchar* _checkInPacket;
|
||||||
int _numBytesCheckInPacket;
|
int _numBytesCheckInPacket;
|
||||||
|
QHostAddress _publicAddress;
|
||||||
|
uint16_t _publicPort;
|
||||||
|
bool _shouldUseDomainServerAsSTUN;
|
||||||
|
|
||||||
void handlePingReply(sockaddr *nodeAddress);
|
void activateSocketFromPingReply(sockaddr *nodeAddress);
|
||||||
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
void timePingReply(sockaddr *nodeAddress, unsigned char *packetData);
|
||||||
|
|
||||||
std::vector<NodeListHook*> _hooks;
|
std::vector<NodeListHook*> _hooks;
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
|
|
||||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode) {
|
||||||
assert(octalCode);
|
assert(octalCode);
|
||||||
if (*octalCode == 255) {
|
if (*octalCode == 255) {
|
||||||
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1);
|
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1);
|
||||||
|
@ -25,18 +25,18 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void printOctalCode(unsigned char * octalCode) {
|
void printOctalCode(const unsigned char* octalCode) {
|
||||||
if (!octalCode) {
|
if (!octalCode) {
|
||||||
qDebug("NULL\n");
|
qDebug("NULL\n");
|
||||||
} else {
|
} else {
|
||||||
for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) {
|
for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {
|
||||||
outputBits(octalCode[i],false);
|
outputBits(octalCode[i],false);
|
||||||
}
|
}
|
||||||
qDebug("\n");
|
qDebug("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
char sectionValue(unsigned char * startByte, char startIndexInByte) {
|
char sectionValue(const unsigned char* startByte, char startIndexInByte) {
|
||||||
char rightShift = 8 - startIndexInByte - 3;
|
char rightShift = 8 - startIndexInByte - 3;
|
||||||
|
|
||||||
if (rightShift < 0) {
|
if (rightShift < 0) {
|
||||||
|
@ -54,14 +54,14 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode) {
|
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode) {
|
||||||
int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
|
int parentSections = numberOfThreeBitSectionsInCode(ancestorOctalCode);
|
||||||
|
|
||||||
int branchStartBit = parentSections * 3;
|
int branchStartBit = parentSections * 3;
|
||||||
return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8);
|
return sectionValue(descendantOctalCode + 1 + (branchStartBit / 8), branchStartBit % 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber) {
|
unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber) {
|
||||||
|
|
||||||
// find the length (in number of three bit code sequences)
|
// find the length (in number of three bit code sequences)
|
||||||
// in the parent
|
// in the parent
|
||||||
|
@ -76,7 +76,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber
|
||||||
int childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);
|
int childCodeBytes = bytesRequiredForCodeLength(parentCodeSections + 1);
|
||||||
|
|
||||||
// create a new buffer to hold the new octal code
|
// create a new buffer to hold the new octal code
|
||||||
unsigned char *newCode = new unsigned char[childCodeBytes];
|
unsigned char* newCode = new unsigned char[childCodeBytes];
|
||||||
|
|
||||||
// copy the parent code to the child
|
// copy the parent code to the child
|
||||||
if (parentOctalCode != NULL) {
|
if (parentOctalCode != NULL) {
|
||||||
|
@ -115,7 +115,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber
|
||||||
return newCode;
|
return newCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPositionSize) {
|
void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize) {
|
||||||
float output[3];
|
float output[3];
|
||||||
memset(&output[0], 0, 3 * sizeof(float));
|
memset(&output[0], 0, 3 * sizeof(float));
|
||||||
float currentScale = 1.0;
|
float currentScale = 1.0;
|
||||||
|
@ -138,7 +138,7 @@ void voxelDetailsForCode(unsigned char * octalCode, VoxelPositionSize& voxelPosi
|
||||||
voxelPositionSize.s = currentScale;
|
voxelPositionSize.s = currentScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
void copyFirstVertexForCode(unsigned char * octalCode, float* output) {
|
void copyFirstVertexForCode(const unsigned char* octalCode, float* output) {
|
||||||
memset(output, 0, 3 * sizeof(float));
|
memset(output, 0, 3 * sizeof(float));
|
||||||
|
|
||||||
float currentScale = 0.5;
|
float currentScale = 0.5;
|
||||||
|
@ -154,13 +154,13 @@ void copyFirstVertexForCode(unsigned char * octalCode, float* output) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
float * firstVertexForCode(unsigned char * octalCode) {
|
float * firstVertexForCode(const unsigned char* octalCode) {
|
||||||
float * firstVertex = new float[3];
|
float * firstVertex = new float[3];
|
||||||
copyFirstVertexForCode(octalCode, firstVertex);
|
copyFirstVertexForCode(octalCode, firstVertex);
|
||||||
return firstVertex;
|
return firstVertex;
|
||||||
}
|
}
|
||||||
|
|
||||||
OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB) {
|
OctalCodeComparison compareOctalCodes(const unsigned char* codeA, const unsigned char* codeB) {
|
||||||
if (!codeA || !codeB) {
|
if (!codeA || !codeB) {
|
||||||
return ILLEGAL_CODE;
|
return ILLEGAL_CODE;
|
||||||
}
|
}
|
||||||
|
@ -196,10 +196,10 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char getOctalCodeSectionValue(unsigned char* octalCode, int section) {
|
char getOctalCodeSectionValue(const unsigned char* octalCode, int section) {
|
||||||
int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);
|
int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE);
|
||||||
char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;
|
char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE;
|
||||||
unsigned char* startByte = octalCode + startAtByte;
|
const unsigned char* startByte = octalCode + startAtByte;
|
||||||
|
|
||||||
return sectionValue(startByte, startIndexInByte);
|
return sectionValue(startByte, startIndexInByte);
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,7 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) {
|
unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels) {
|
||||||
int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
||||||
unsigned char* newCode = NULL;
|
unsigned char* newCode = NULL;
|
||||||
if (codeLength > chopLevels) {
|
if (codeLength > chopLevels) {
|
||||||
|
@ -259,7 +259,9 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) {
|
||||||
return newCode;
|
return newCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace) {
|
unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
|
||||||
|
bool includeColorSpace) {
|
||||||
|
|
||||||
int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode);
|
||||||
int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);
|
int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode);
|
||||||
int newCodeLength = newParentCodeLength + oldCodeLength;
|
int newCodeLength = newParentCodeLength + oldCodeLength;
|
||||||
|
@ -280,7 +282,7 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char*
|
||||||
return newCode;
|
return newCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild) {
|
bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent, int descendentsChild) {
|
||||||
if (!possibleAncestor || !possibleDescendent) {
|
if (!possibleAncestor || !possibleDescendent) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -350,7 +352,7 @@ unsigned char* hexStringToOctalCode(const QString& input) {
|
||||||
return bytes;
|
return bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString octalCodeToHexString(unsigned char* octalCode) {
|
QString octalCodeToHexString(const unsigned char* octalCode) {
|
||||||
const int HEX_NUMBER_BASE = 16;
|
const int HEX_NUMBER_BASE = 16;
|
||||||
const int HEX_BYTE_SIZE = 2;
|
const int HEX_BYTE_SIZE = 2;
|
||||||
QString output;
|
QString output;
|
||||||
|
|
|
@ -20,27 +20,28 @@ const int RED_INDEX = 0;
|
||||||
const int GREEN_INDEX = 1;
|
const int GREEN_INDEX = 1;
|
||||||
const int BLUE_INDEX = 2;
|
const int BLUE_INDEX = 2;
|
||||||
|
|
||||||
void printOctalCode(unsigned char * octalCode);
|
void printOctalCode(const unsigned char* octalCode);
|
||||||
int bytesRequiredForCodeLength(unsigned char threeBitCodes);
|
int bytesRequiredForCodeLength(unsigned char threeBitCodes);
|
||||||
int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode);
|
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode);
|
||||||
unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber);
|
unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber);
|
||||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode);
|
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode);
|
||||||
unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels);
|
unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels);
|
||||||
unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode,
|
unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
|
||||||
bool includeColorSpace = false);
|
bool includeColorSpace = false);
|
||||||
|
|
||||||
const int CHECK_NODE_ONLY = -1;
|
const int CHECK_NODE_ONLY = -1;
|
||||||
bool isAncestorOf(unsigned char* possibleAncestor, unsigned char* possibleDescendent, int descendentsChild = CHECK_NODE_ONLY);
|
bool isAncestorOf(const unsigned char* possibleAncestor, const unsigned char* possibleDescendent,
|
||||||
|
int descendentsChild = CHECK_NODE_ONLY);
|
||||||
|
|
||||||
// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return
|
// Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return
|
||||||
// but other than that these do the same thing.
|
// but other than that these do the same thing.
|
||||||
float * firstVertexForCode(unsigned char * octalCode);
|
float * firstVertexForCode(const unsigned char* octalCode);
|
||||||
void copyFirstVertexForCode(unsigned char * octalCode, float* output);
|
void copyFirstVertexForCode(const unsigned char* octalCode, float* output);
|
||||||
|
|
||||||
struct VoxelPositionSize {
|
struct VoxelPositionSize {
|
||||||
float x, y, z, s;
|
float x, y, z, s;
|
||||||
};
|
};
|
||||||
void voxelDetailsForCode(unsigned char* octalCode, VoxelPositionSize& voxelPositionSize);
|
void voxelDetailsForCode(const unsigned char* octalCode, VoxelPositionSize& voxelPositionSize);
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ILLEGAL_CODE = -2,
|
ILLEGAL_CODE = -2,
|
||||||
|
@ -49,9 +50,9 @@ typedef enum {
|
||||||
GREATER_THAN = 1
|
GREATER_THAN = 1
|
||||||
} OctalCodeComparison;
|
} OctalCodeComparison;
|
||||||
|
|
||||||
OctalCodeComparison compareOctalCodes(unsigned char* code1, unsigned char* code2);
|
OctalCodeComparison compareOctalCodes(const unsigned char* code1, const unsigned char* code2);
|
||||||
|
|
||||||
QString octalCodeToHexString(unsigned char* octalCode);
|
QString octalCodeToHexString(const unsigned char* octalCode);
|
||||||
unsigned char* hexStringToOctalCode(const QString& input);
|
unsigned char* hexStringToOctalCode(const QString& input);
|
||||||
|
|
||||||
#endif /* defined(__hifi__OctalCode__) */
|
#endif /* defined(__hifi__OctalCode__) */
|
||||||
|
|
|
@ -17,19 +17,25 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
|
|
||||||
case PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO:
|
case PACKET_TYPE_MICROPHONE_AUDIO_NO_ECHO:
|
||||||
case PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO:
|
case PACKET_TYPE_MICROPHONE_AUDIO_WITH_ECHO:
|
||||||
return 1;
|
return 2;
|
||||||
|
|
||||||
case PACKET_TYPE_HEAD_DATA:
|
case PACKET_TYPE_HEAD_DATA:
|
||||||
return 9;
|
return 10;
|
||||||
|
|
||||||
case PACKET_TYPE_AVATAR_URLS:
|
case PACKET_TYPE_AVATAR_URLS:
|
||||||
return 1;
|
return 2;
|
||||||
|
|
||||||
case PACKET_TYPE_AVATAR_FACE_VIDEO:
|
case PACKET_TYPE_AVATAR_FACE_VIDEO:
|
||||||
return 1;
|
return 2;
|
||||||
|
|
||||||
case PACKET_TYPE_VOXEL_STATS:
|
case PACKET_TYPE_VOXEL_STATS:
|
||||||
return 2;
|
return 2;
|
||||||
|
|
||||||
|
case PACKET_TYPE_DOMAIN:
|
||||||
|
case PACKET_TYPE_DOMAIN_LIST_REQUEST:
|
||||||
|
case PACKET_TYPE_DOMAIN_REPORT_FOR_DUTY:
|
||||||
|
return 1;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -38,7 +44,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
|
||||||
bool packetVersionMatch(unsigned char* packetHeader) {
|
bool packetVersionMatch(unsigned char* packetHeader) {
|
||||||
// currently this just checks if the version in the packet matches our return from versionForPacketType
|
// currently this just checks if the version in the packet matches our return from versionForPacketType
|
||||||
// may need to be expanded in the future for types and versions that take > than 1 byte
|
// may need to be expanded in the future for types and versions that take > than 1 byte
|
||||||
if (packetHeader[1] == versionForPacketType(packetHeader[0])) {
|
if (packetHeader[1] == versionForPacketType(packetHeader[0]) || packetHeader[0] == PACKET_TYPE_STUN_RESPONSE) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
|
qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]);
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
typedef char PACKET_TYPE;
|
typedef char PACKET_TYPE;
|
||||||
const PACKET_TYPE PACKET_TYPE_UNKNOWN = 0;
|
const PACKET_TYPE PACKET_TYPE_UNKNOWN = 0;
|
||||||
|
const PACKET_TYPE PACKET_TYPE_STUN_RESPONSE = 1;
|
||||||
const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D';
|
const PACKET_TYPE PACKET_TYPE_DOMAIN = 'D';
|
||||||
const PACKET_TYPE PACKET_TYPE_PING = 'P';
|
const PACKET_TYPE PACKET_TYPE_PING = 'P';
|
||||||
const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
|
const PACKET_TYPE PACKET_TYPE_PING_REPLY = 'R';
|
||||||
|
|
|
@ -108,7 +108,8 @@ bool PerformanceWarning::_suppressShortTimings = false;
|
||||||
// Destructor handles recording all of our stats
|
// Destructor handles recording all of our stats
|
||||||
PerformanceWarning::~PerformanceWarning() {
|
PerformanceWarning::~PerformanceWarning() {
|
||||||
uint64_t end = usecTimestampNow();
|
uint64_t end = usecTimestampNow();
|
||||||
double elapsedmsec = (end - _start) / 1000.0;
|
uint64_t elapsedusec = (end - _start);
|
||||||
|
double elapsedmsec = elapsedusec / 1000.0;
|
||||||
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) {
|
||||||
if (elapsedmsec > 1000) {
|
if (elapsedmsec > 1000) {
|
||||||
double elapsedsec = (end - _start) / 1000000.0;
|
double elapsedsec = (end - _start) / 1000000.0;
|
||||||
|
@ -127,6 +128,13 @@ PerformanceWarning::~PerformanceWarning() {
|
||||||
} else if (_alwaysDisplay) {
|
} else if (_alwaysDisplay) {
|
||||||
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
|
qDebug("%s took %lf milliseconds\n", _message, elapsedmsec);
|
||||||
}
|
}
|
||||||
|
// if the caller gave us a pointer to store the running total, track it now.
|
||||||
|
if (_runningTotal) {
|
||||||
|
*_runningTotal += elapsedusec;
|
||||||
|
}
|
||||||
|
if (_totalCalls) {
|
||||||
|
*_totalCalls += 1;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -89,14 +89,19 @@ private:
|
||||||
const char* _message;
|
const char* _message;
|
||||||
bool _renderWarningsOn;
|
bool _renderWarningsOn;
|
||||||
bool _alwaysDisplay;
|
bool _alwaysDisplay;
|
||||||
|
uint64_t* _runningTotal;
|
||||||
|
uint64_t* _totalCalls;
|
||||||
static bool _suppressShortTimings;
|
static bool _suppressShortTimings;
|
||||||
public:
|
public:
|
||||||
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false) :
|
|
||||||
|
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
|
||||||
_start(usecTimestampNow()),
|
_start(usecTimestampNow()),
|
||||||
_message(message),
|
_message(message),
|
||||||
_renderWarningsOn(renderWarnings),
|
_renderWarningsOn(renderWarnings),
|
||||||
_alwaysDisplay(alwaysDisplay) { }
|
_alwaysDisplay(alwaysDisplay),
|
||||||
|
_runningTotal(runningTotal),
|
||||||
|
_totalCalls(totalCalls) { }
|
||||||
|
|
||||||
~PerformanceWarning();
|
~PerformanceWarning();
|
||||||
|
|
||||||
static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; }
|
static void setSuppressShortTimings(bool suppressShortTimings) { _suppressShortTimings = suppressShortTimings; }
|
||||||
|
|
|
@ -105,10 +105,41 @@ void setAtBit(unsigned char& byte, int bitIndex) {
|
||||||
byte += (1 << (7 - bitIndex));
|
byte += (1 << (7 - bitIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clearAtBit(unsigned char& byte, int bitIndex) {
|
||||||
|
if (oneAtBit(byte, bitIndex)) {
|
||||||
|
byte -= (1 << (7 - bitIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int getSemiNibbleAt(unsigned char& byte, int bitIndex) {
|
int getSemiNibbleAt(unsigned char& byte, int bitIndex) {
|
||||||
return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11
|
return (byte >> (6 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int getNthBit(unsigned char byte, int ordinal) {
|
||||||
|
const int ERROR = -1;
|
||||||
|
const int MIN_ORDINAL = 1;
|
||||||
|
const int MAX_ORDINAL = 8;
|
||||||
|
if (ordinal < MIN_ORDINAL || ordinal > MAX_ORDINAL) {
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
int bitsSet = 0;
|
||||||
|
for (int bitIndex = 0; bitIndex < MAX_ORDINAL; bitIndex++) {
|
||||||
|
if (oneAtBit(byte, bitIndex)) {
|
||||||
|
bitsSet++;
|
||||||
|
}
|
||||||
|
if (bitsSet == ordinal) {
|
||||||
|
return bitIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isBetween(int64_t value, int64_t max, int64_t min) {
|
||||||
|
return ((value <= max) && (value >= min));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) {
|
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) {
|
||||||
//assert(value <= 3 && value >= 0);
|
//assert(value <= 3 && value >= 0);
|
||||||
byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11
|
byte += ((value & 3) << (6 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11
|
||||||
|
|
|
@ -55,10 +55,12 @@ void printVoxelCode(unsigned char* voxelCode);
|
||||||
int numberOfOnes(unsigned char byte);
|
int numberOfOnes(unsigned char byte);
|
||||||
bool oneAtBit(unsigned char byte, int bitIndex);
|
bool oneAtBit(unsigned char byte, int bitIndex);
|
||||||
void setAtBit(unsigned char& byte, int bitIndex);
|
void setAtBit(unsigned char& byte, int bitIndex);
|
||||||
|
void clearAtBit(unsigned char& byte, int bitIndex);
|
||||||
int getSemiNibbleAt(unsigned char& byte, int bitIndex);
|
int getSemiNibbleAt(unsigned char& byte, int bitIndex);
|
||||||
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value);
|
void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value);
|
||||||
|
|
||||||
|
int getNthBit(unsigned char byte, int ordinal); /// determines the bit placement 0-7 of the ordinal set bit
|
||||||
|
|
||||||
bool isInEnvironment(const char* environment);
|
bool isInEnvironment(const char* environment);
|
||||||
|
|
||||||
void switchToResourcesParentIfRequired();
|
void switchToResourcesParentIfRequired();
|
||||||
|
@ -109,4 +111,6 @@ public:
|
||||||
static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; }
|
static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool isBetween(int64_t value, int64_t max, int64_t min);
|
||||||
|
|
||||||
#endif /* defined(__hifi__SharedUtil__) */
|
#endif /* defined(__hifi__SharedUtil__) */
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <QtCore/QDebug>
|
#include <QtCore/QDebug>
|
||||||
|
#include <QtNetwork/QNetworkInterface>
|
||||||
|
#include <QtNetwork/QHostAddress>
|
||||||
|
|
||||||
#include "Logging.h"
|
#include "Logging.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
|
@ -88,35 +90,35 @@ void copySocketToEmptySocketPointer(sockaddr** destination, const sockaddr* sour
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLocalAddress() {
|
int getLocalAddress() {
|
||||||
// get this node's local address so we can pass that to DS
|
|
||||||
struct ifaddrs* ifAddrStruct = NULL;
|
|
||||||
struct ifaddrs* ifa = NULL;
|
|
||||||
|
|
||||||
int family;
|
static int localAddress = 0;
|
||||||
int localAddress = 0;
|
|
||||||
|
if (localAddress == 0) {
|
||||||
#ifndef _WIN32
|
foreach(const QNetworkInterface &interface, QNetworkInterface::allInterfaces()) {
|
||||||
getifaddrs(&ifAddrStruct);
|
if (interface.flags() & QNetworkInterface::IsUp
|
||||||
|
&& interface.flags() & QNetworkInterface::IsRunning
|
||||||
for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) {
|
&& interface.flags() & ~QNetworkInterface::IsLoopBack) {
|
||||||
family = ifa->ifa_addr->sa_family;
|
// we've decided that this is the active NIC
|
||||||
if (family == AF_INET) {
|
// enumerate it's addresses to grab the IPv4 address
|
||||||
localAddress = ((sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr;
|
foreach(const QNetworkAddressEntry &entry, interface.addressEntries()) {
|
||||||
|
// make sure it's an IPv4 address that isn't the loopback
|
||||||
|
if (entry.ip().protocol() == QAbstractSocket::IPv4Protocol && !entry.ip().isLoopback()) {
|
||||||
|
qDebug("Node's local address is %s\n", entry.ip().toString().toLocal8Bit().constData());
|
||||||
|
|
||||||
|
// set our localAddress and break out
|
||||||
|
localAddress = htonl(entry.ip().toIPv4Address());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localAddress != 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
freeifaddrs(ifAddrStruct);
|
// return the looked up local address
|
||||||
#else
|
|
||||||
// Get the local hostname
|
|
||||||
char szHostName[255];
|
|
||||||
gethostname(szHostName, 255);
|
|
||||||
struct hostent *host_entry;
|
|
||||||
host_entry = gethostbyname(szHostName);
|
|
||||||
char * szLocalIP;
|
|
||||||
szLocalIP = inet_ntoa (*(struct in_addr *)*host_entry->h_addr_list);
|
|
||||||
localAddress = inet_addr(szLocalIP);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return localAddress;
|
return localAddress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
#include <QtCore/QUuid>
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
|
const int NUM_BYTES_RFC4122_UUID = 16;
|
||||||
|
|
||||||
QString uuidStringWithoutCurlyBraces(const QUuid& uuid);
|
QString uuidStringWithoutCurlyBraces(const QUuid& uuid);
|
||||||
|
|
||||||
#endif /* defined(__hifi__UUID__) */
|
#endif /* defined(__hifi__UUID__) */
|
||||||
|
|
|
@ -32,8 +32,8 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
|
||||||
|
|
||||||
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
||||||
// Create voxel sending thread...
|
// Create voxel sending thread...
|
||||||
uint16_t nodeID = getOwningNode()->getNodeID();
|
QUuid nodeUUID = getOwningNode()->getUUID();
|
||||||
_voxelSendThread = new VoxelSendThread(nodeID, voxelServer);
|
_voxelSendThread = new VoxelSendThread(nodeUUID, voxelServer);
|
||||||
_voxelSendThread->initialize(true);
|
_voxelSendThread->initialize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,21 +29,38 @@ bool VoxelPersistThread::process() {
|
||||||
_initialLoad = true;
|
_initialLoad = true;
|
||||||
qDebug("loading voxels from file: %s...\n", _filename);
|
qDebug("loading voxels from file: %s...\n", _filename);
|
||||||
|
|
||||||
bool persistantFileRead = _tree->readFromSVOFile(_filename);
|
bool persistantFileRead;
|
||||||
|
|
||||||
|
{
|
||||||
|
PerformanceWarning warn(true, "Loading Voxel File", true);
|
||||||
|
persistantFileRead = _tree->readFromSVOFile(_filename);
|
||||||
|
}
|
||||||
|
|
||||||
if (persistantFileRead) {
|
if (persistantFileRead) {
|
||||||
PerformanceWarning warn(true, "reaverageVoxelColors()", true);
|
PerformanceWarning warn(true, "Voxels Re-Averaging", true);
|
||||||
|
|
||||||
// after done inserting all these voxels, then reaverage colors
|
// after done inserting all these voxels, then reaverage colors
|
||||||
|
qDebug("BEGIN Voxels Re-Averaging\n");
|
||||||
_tree->reaverageVoxelColors(_tree->rootNode);
|
_tree->reaverageVoxelColors(_tree->rootNode);
|
||||||
qDebug("Voxels reAveraged\n");
|
qDebug("DONE WITH Voxels Re-Averaging\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
||||||
qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
||||||
unsigned long nodeCount = _tree->rootNode->getSubTreeNodeCount();
|
|
||||||
unsigned long internalNodeCount = _tree->rootNode->getSubTreeInternalNodeCount();
|
unsigned long nodeCount = VoxelNode::getNodeCount();
|
||||||
unsigned long leafNodeCount = _tree->rootNode->getSubTreeLeafNodeCount();
|
unsigned long internalNodeCount = VoxelNode::getInternalNodeCount();
|
||||||
|
unsigned long leafNodeCount = VoxelNode::getLeafNodeCount();
|
||||||
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount);
|
||||||
|
|
||||||
|
double usecPerGet = (double)VoxelNode::getGetChildAtIndexTime() / (double)VoxelNode::getGetChildAtIndexCalls();
|
||||||
|
qDebug("getChildAtIndexCalls=%llu getChildAtIndexTime=%llu perGet=%lf \n",
|
||||||
|
VoxelNode::getGetChildAtIndexTime(), VoxelNode::getGetChildAtIndexCalls(), usecPerGet);
|
||||||
|
|
||||||
|
double usecPerSet = (double)VoxelNode::getSetChildAtIndexTime() / (double)VoxelNode::getSetChildAtIndexCalls();
|
||||||
|
qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n",
|
||||||
|
VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t MSECS_TO_USECS = 1000;
|
uint64_t MSECS_TO_USECS = 1000;
|
||||||
|
|
|
@ -18,15 +18,15 @@ extern EnvironmentData environmentData[3];
|
||||||
#include "VoxelServer.h"
|
#include "VoxelServer.h"
|
||||||
#include "VoxelServerConsts.h"
|
#include "VoxelServerConsts.h"
|
||||||
|
|
||||||
VoxelSendThread::VoxelSendThread(uint16_t nodeID, VoxelServer* myServer) :
|
VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) :
|
||||||
_nodeID(nodeID),
|
_nodeUUID(nodeUUID),
|
||||||
_myServer(myServer) {
|
_myServer(myServer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelSendThread::process() {
|
bool VoxelSendThread::process() {
|
||||||
uint64_t lastSendTime = usecTimestampNow();
|
uint64_t lastSendTime = usecTimestampNow();
|
||||||
|
|
||||||
Node* node = NodeList::getInstance()->nodeWithID(_nodeID);
|
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
||||||
VoxelNodeData* nodeData = NULL;
|
VoxelNodeData* nodeData = NULL;
|
||||||
|
|
||||||
if (node) {
|
if (node) {
|
||||||
|
@ -83,7 +83,7 @@ void VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
|
||||||
} else {
|
} else {
|
||||||
// just send the voxel packet
|
// just send the voxel packet
|
||||||
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(),
|
NodeList::getInstance()->getNodeSocket()->send(node->getActiveSocket(),
|
||||||
nodeData->getPacket(), nodeData->getPacketLength());
|
nodeData->getPacket(), nodeData->getPacketLength());
|
||||||
}
|
}
|
||||||
// remember to track our stats
|
// remember to track our stats
|
||||||
nodeData->stats.packetSent(nodeData->getPacketLength());
|
nodeData->stats.packetSent(nodeData->getPacketLength());
|
||||||
|
|
|
@ -21,13 +21,13 @@
|
||||||
/// Threaded processor for sending voxel packets to a single client
|
/// Threaded processor for sending voxel packets to a single client
|
||||||
class VoxelSendThread : public virtual GenericThread {
|
class VoxelSendThread : public virtual GenericThread {
|
||||||
public:
|
public:
|
||||||
VoxelSendThread(uint16_t nodeID, VoxelServer* myServer);
|
VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer);
|
||||||
protected:
|
protected:
|
||||||
/// Implements generic processing behavior for this thread.
|
/// Implements generic processing behavior for this thread.
|
||||||
virtual bool process();
|
virtual bool process();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint16_t _nodeID;
|
QUuid _nodeUUID;
|
||||||
VoxelServer* _myServer;
|
VoxelServer* _myServer;
|
||||||
|
|
||||||
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
|
void handlePacketSend(Node* node, VoxelNodeData* nodeData, int& trueBytesSent, int& truePacketsSent);
|
||||||
|
|
|
@ -11,8 +11,9 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QtCore/QDebug>
|
||||||
#include <QString>
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
#include <Logging.h>
|
#include <Logging.h>
|
||||||
#include <OctalCode.h>
|
#include <OctalCode.h>
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
#include <SceneUtils.h>
|
#include <SceneUtils.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <JurisdictionSender.h>
|
#include <JurisdictionSender.h>
|
||||||
|
#include <UUID.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Syssocket.h"
|
#include "Syssocket.h"
|
||||||
|
@ -136,18 +138,74 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
|
||||||
mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n");
|
mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n");
|
||||||
mg_printf(connection, "%s", "Your Voxel Server is running.\r\n");
|
mg_printf(connection, "%s", "Your Voxel Server is running.\r\n");
|
||||||
mg_printf(connection, "%s", "Current Statistics\r\n");
|
mg_printf(connection, "%s", "Current Statistics\r\n");
|
||||||
mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f);
|
mg_printf(connection, "%s", "\r\n");
|
||||||
mg_printf(connection, "Octcode Memory Usage: %f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f);
|
mg_printf(connection, "Voxel Node Memory Usage: %8.2f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f);
|
||||||
|
mg_printf(connection, "Octcode Memory Usage: %8.2f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f);
|
||||||
|
mg_printf(connection, "External Children Memory Usage: %8.2f MB\r\n",
|
||||||
|
VoxelNode::getExternalChildrenMemoryUsage() / 1000000.f);
|
||||||
|
mg_printf(connection, "%s", " -----------\r\n");
|
||||||
|
mg_printf(connection, " Total: %8.2f MB\r\n", VoxelNode::getTotalMemoryUsage() / 1000000.f);
|
||||||
|
|
||||||
VoxelTree* theTree = VoxelServer::GetInstance()->getTree();
|
unsigned long nodeCount = VoxelNode::getNodeCount();
|
||||||
unsigned long nodeCount = theTree->rootNode->getSubTreeNodeCount();
|
unsigned long internalNodeCount = VoxelNode::getInternalNodeCount();
|
||||||
unsigned long internalNodeCount = theTree->rootNode->getSubTreeInternalNodeCount();
|
unsigned long leafNodeCount = VoxelNode::getLeafNodeCount();
|
||||||
unsigned long leafNodeCount = theTree->rootNode->getSubTreeLeafNodeCount();
|
|
||||||
|
|
||||||
|
const float AS_PERCENT = 100.0;
|
||||||
|
|
||||||
|
mg_printf(connection, "%s", "\r\n");
|
||||||
mg_printf(connection, "%s", "Current Nodes in scene\r\n");
|
mg_printf(connection, "%s", "Current Nodes in scene\r\n");
|
||||||
mg_printf(connection, " Total Nodes: %lu nodes\r\n", nodeCount);
|
mg_printf(connection, " Total Nodes: %10.lu nodes\r\n", nodeCount);
|
||||||
mg_printf(connection, " Internal Nodes: %lu nodes\r\n", internalNodeCount);
|
mg_printf(connection, " Internal Nodes: %10.lu nodes (%5.2f%%)\r\n",
|
||||||
mg_printf(connection, " Leaf Nodes: %lu leaves\r\n", leafNodeCount);
|
internalNodeCount, ((float)internalNodeCount/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Leaf Nodes: %10.lu nodes (%5.2f%%)\r\n",
|
||||||
|
leafNodeCount, ((float)leafNodeCount/(float)nodeCount) * AS_PERCENT);
|
||||||
|
|
||||||
|
mg_printf(connection, "%s", "\r\n");
|
||||||
|
mg_printf(connection, "%s", "VoxelNode Children Encoding Statistics...\r\n");
|
||||||
|
mg_printf(connection, " Single or No Children: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getSingleChildrenCount(), ((float)VoxelNode::getSingleChildrenCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Two Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getTwoChildrenOffsetCount(),
|
||||||
|
((float)VoxelNode::getTwoChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Two Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getTwoChildrenExternalCount(),
|
||||||
|
((float)VoxelNode::getTwoChildrenExternalCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Three Children as Offset: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getThreeChildrenOffsetCount(),
|
||||||
|
((float)VoxelNode::getThreeChildrenOffsetCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Three Children as External: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getThreeChildrenExternalCount(),
|
||||||
|
((float)VoxelNode::getThreeChildrenExternalCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
mg_printf(connection, " Children as External Array: %10.llu nodes (%5.2f%%)\r\n",
|
||||||
|
VoxelNode::getExternalChildrenCount(),
|
||||||
|
((float)VoxelNode::getExternalChildrenCount()/(float)nodeCount) * AS_PERCENT);
|
||||||
|
|
||||||
|
uint64_t checkSum = VoxelNode::getSingleChildrenCount() +
|
||||||
|
VoxelNode::getTwoChildrenOffsetCount() + VoxelNode::getTwoChildrenExternalCount() +
|
||||||
|
VoxelNode::getThreeChildrenOffsetCount() + VoxelNode::getThreeChildrenExternalCount() +
|
||||||
|
VoxelNode::getExternalChildrenCount();
|
||||||
|
|
||||||
|
mg_printf(connection, "%s", " ----------------\r\n");
|
||||||
|
mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum);
|
||||||
|
mg_printf(connection, " Expected: %10.lu nodes\r\n", nodeCount);
|
||||||
|
|
||||||
|
mg_printf(connection, "%s", "\r\n");
|
||||||
|
mg_printf(connection, "%s", "VoxelNode Children Population Statistics...\r\n");
|
||||||
|
checkSum = 0;
|
||||||
|
for (int i=0; i <= NUMBER_OF_CHILDREN; i++) {
|
||||||
|
checkSum += VoxelNode::getChildrenCount(i);
|
||||||
|
mg_printf(connection, " Nodes with %d children: %10.llu nodes (%5.2f%%)\r\n", i,
|
||||||
|
VoxelNode::getChildrenCount(i), ((float)VoxelNode::getChildrenCount(i)/(float)nodeCount) * AS_PERCENT);
|
||||||
|
}
|
||||||
|
mg_printf(connection, "%s", " ----------------\r\n");
|
||||||
|
mg_printf(connection, " Total: %10.llu nodes\r\n", checkSum);
|
||||||
|
|
||||||
|
mg_printf(connection, "%s", "\r\n");
|
||||||
|
mg_printf(connection, "%s", "In other news....\r\n");
|
||||||
|
mg_printf(connection, "could store 4 children internally: %10.llu nodes\r\n",
|
||||||
|
VoxelNode::getCouldStoreFourChildrenInternally());
|
||||||
|
mg_printf(connection, "could NOT store 4 children internally: %10.llu nodes\r\n",
|
||||||
|
VoxelNode::getCouldNotStoreFourChildrenInternally());
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -373,7 +431,7 @@ void VoxelServer::run() {
|
||||||
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
// send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed
|
||||||
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) {
|
||||||
gettimeofday(&lastDomainServerCheckIn, NULL);
|
gettimeofday(&lastDomainServerCheckIn, NULL);
|
||||||
NodeList::getInstance()->sendDomainServerCheckIn(_uuid.toRfc4122().constData());
|
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) &&
|
if (nodeList->getNodeSocket()->receive(&senderAddress, packetData, &packetLength) &&
|
||||||
|
@ -384,12 +442,18 @@ void VoxelServer::run() {
|
||||||
if (packetData[0] == PACKET_TYPE_HEAD_DATA) {
|
if (packetData[0] == PACKET_TYPE_HEAD_DATA) {
|
||||||
// If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
|
// If we got a PACKET_TYPE_HEAD_DATA, then we're talking to an NODE_TYPE_AVATAR, and we
|
||||||
// need to make sure we have it in our nodeList.
|
// need to make sure we have it in our nodeList.
|
||||||
uint16_t nodeID = 0;
|
QUuid nodeUUID = QUuid::fromRfc4122(QByteArray((char*)packetData + numBytesPacketHeader,
|
||||||
unpackNodeId(packetData + numBytesPacketHeader, &nodeID);
|
NUM_BYTES_RFC4122_UUID));
|
||||||
Node* node = NodeList::getInstance()->addOrUpdateNode(&senderAddress,
|
|
||||||
&senderAddress,
|
Node* node = NodeList::getInstance()->addOrUpdateNode(nodeUUID,
|
||||||
NODE_TYPE_AGENT,
|
NODE_TYPE_AGENT,
|
||||||
nodeID);
|
&senderAddress,
|
||||||
|
&senderAddress);
|
||||||
|
|
||||||
|
// temp activation of public socket before server ping/reply is setup
|
||||||
|
if (!node->getActiveSocket()) {
|
||||||
|
node->activatePublicSocket();
|
||||||
|
}
|
||||||
|
|
||||||
NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength);
|
NodeList::getInstance()->updateNodeWithData(node, packetData, packetLength);
|
||||||
|
|
||||||
|
@ -398,8 +462,10 @@ void VoxelServer::run() {
|
||||||
nodeData->initializeVoxelSendThread(this);
|
nodeData->initializeVoxelSendThread(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (packetData[0] == PACKET_TYPE_PING) {
|
} else if (packetData[0] == PACKET_TYPE_PING
|
||||||
// If the packet is a ping, let processNodeData handle it.
|
|| packetData[0] == PACKET_TYPE_DOMAIN
|
||||||
|
|| packetData[0] == PACKET_TYPE_STUN_RESPONSE) {
|
||||||
|
// let processNodeData handle it.
|
||||||
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
||||||
} else if (packetData[0] == PACKET_TYPE_DOMAIN) {
|
} else if (packetData[0] == PACKET_TYPE_DOMAIN) {
|
||||||
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
NodeList::getInstance()->processNodeData(&senderAddress, packetData, packetLength);
|
||||||
|
|
|
@ -13,83 +13,66 @@
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
#include "GeometryUtil.h"
|
#include "GeometryUtil.h"
|
||||||
|
|
||||||
AABox::AABox(const glm::vec3& corner, float size) : _corner(corner), _size(size, size, size), _topFarLeft(_corner + _size)
|
AABox::AABox(const glm::vec3& corner, float size) :
|
||||||
{
|
_corner(corner), _scale(size) {
|
||||||
};
|
};
|
||||||
|
|
||||||
AABox::AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x, y, z), _topFarLeft(_corner + _size)
|
AABox::AABox() : _corner(0,0,0), _scale(0) {
|
||||||
{
|
|
||||||
};
|
};
|
||||||
|
|
||||||
AABox::AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size), _topFarLeft(_corner + _size)
|
glm::vec3 AABox::calcCenter() const {
|
||||||
{
|
glm::vec3 center(_corner);
|
||||||
};
|
center += (glm::vec3(_scale, _scale, _scale) * 0.5f);
|
||||||
|
return center;
|
||||||
|
}
|
||||||
|
|
||||||
AABox::AABox() : _corner(0,0,0), _size(0,0,0), _topFarLeft(0,0,0)
|
glm::vec3 AABox::calcTopFarLeft() const {
|
||||||
{
|
glm::vec3 topFarLeft(_corner);
|
||||||
|
topFarLeft += glm::vec3(_scale, _scale, _scale);
|
||||||
|
return topFarLeft;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void AABox::scale(float scale) {
|
void AABox::scale(float scale) {
|
||||||
_corner = _corner * scale;
|
_corner = _corner * scale;
|
||||||
_size = _size * scale;
|
_scale = _scale * scale;
|
||||||
_center = _center * scale;
|
|
||||||
_topFarLeft = _topFarLeft * scale;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
|
glm::vec3 AABox::getVertex(BoxVertex vertex) const {
|
||||||
switch (vertex) {
|
switch (vertex) {
|
||||||
case BOTTOM_LEFT_NEAR:
|
case BOTTOM_LEFT_NEAR:
|
||||||
return _corner + glm::vec3(_size.x, 0, 0);
|
return _corner + glm::vec3(_scale, 0, 0);
|
||||||
case BOTTOM_RIGHT_NEAR:
|
case BOTTOM_RIGHT_NEAR:
|
||||||
return _corner;
|
return _corner;
|
||||||
case TOP_RIGHT_NEAR:
|
case TOP_RIGHT_NEAR:
|
||||||
return _corner + glm::vec3(0, _size.y, 0);
|
return _corner + glm::vec3(0, _scale, 0);
|
||||||
case TOP_LEFT_NEAR:
|
case TOP_LEFT_NEAR:
|
||||||
return _corner + glm::vec3(_size.x, _size.y, 0);
|
return _corner + glm::vec3(_scale, _scale, 0);
|
||||||
case BOTTOM_LEFT_FAR:
|
case BOTTOM_LEFT_FAR:
|
||||||
return _corner + glm::vec3(_size.x, 0, _size.z);
|
return _corner + glm::vec3(_scale, 0, _scale);
|
||||||
case BOTTOM_RIGHT_FAR:
|
case BOTTOM_RIGHT_FAR:
|
||||||
return _corner + glm::vec3(0, 0, _size.z);
|
return _corner + glm::vec3(0, 0, _scale);
|
||||||
case TOP_RIGHT_FAR:
|
case TOP_RIGHT_FAR:
|
||||||
return _corner + glm::vec3(0, _size.y, _size.z);
|
return _corner + glm::vec3(0, _scale, _scale);
|
||||||
case TOP_LEFT_FAR:
|
case TOP_LEFT_FAR:
|
||||||
return _corner + _size;
|
return _corner + glm::vec3(_scale, _scale, _scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) {
|
void AABox::setBox(const glm::vec3& corner, float scale) {
|
||||||
_corner = corner;
|
_corner = corner;
|
||||||
_size = size;
|
_scale = scale;
|
||||||
|
|
||||||
// In the event that the caller gave us negative sizes, fix things up to be reasonable
|
|
||||||
if (_size.x < 0.0) {
|
|
||||||
_size.x = -size.x;
|
|
||||||
_corner.x -= _size.x;
|
|
||||||
}
|
|
||||||
if (_size.y < 0.0) {
|
|
||||||
_size.y = -size.y;
|
|
||||||
_corner.y -= _size.y;
|
|
||||||
}
|
|
||||||
if (_size.z < 0.0) {
|
|
||||||
_size.z = -size.z;
|
|
||||||
_corner.z -= _size.z;
|
|
||||||
}
|
|
||||||
_center = _corner + (_size * 0.5f);
|
|
||||||
_topFarLeft = _corner + _size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 AABox::getVertexP(const glm::vec3& normal) const {
|
glm::vec3 AABox::getVertexP(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
if (normal.x > 0) {
|
if (normal.x > 0) {
|
||||||
result.x += _size.x;
|
result.x += _scale;
|
||||||
}
|
}
|
||||||
if (normal.y > 0) {
|
if (normal.y > 0) {
|
||||||
result.y += _size.y;
|
result.y += _scale;
|
||||||
}
|
}
|
||||||
if (normal.z > 0) {
|
if (normal.z > 0) {
|
||||||
result.z += _size.z;
|
result.z += _scale;
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -98,15 +81,15 @@ glm::vec3 AABox::getVertexN(const glm::vec3& normal) const {
|
||||||
glm::vec3 result = _corner;
|
glm::vec3 result = _corner;
|
||||||
|
|
||||||
if (normal.x < 0) {
|
if (normal.x < 0) {
|
||||||
result.x += _size.x;
|
result.x += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.y < 0) {
|
if (normal.y < 0) {
|
||||||
result.y += _size.y;
|
result.y += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (normal.z < 0) {
|
if (normal.z < 0) {
|
||||||
result.z += _size.z;
|
result.z += _scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -118,9 +101,9 @@ static bool isWithin(float value, float corner, float size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AABox::contains(const glm::vec3& point) const {
|
bool AABox::contains(const glm::vec3& point) const {
|
||||||
return isWithin(point.x, _corner.x, _size.x) &&
|
return isWithin(point.x, _corner.x, _scale) &&
|
||||||
isWithin(point.y, _corner.y, _size.y) &&
|
isWithin(point.y, _corner.y, _scale) &&
|
||||||
isWithin(point.z, _corner.z, _size.z);
|
isWithin(point.z, _corner.z, _scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AABox::contains(const AABox& otherBox) const {
|
bool AABox::contains(const AABox& otherBox) const {
|
||||||
|
@ -140,9 +123,9 @@ static bool isWithinExpanded(float value, float corner, float size, float expans
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AABox::expandedContains(const glm::vec3& point, float expansion) const {
|
bool AABox::expandedContains(const glm::vec3& point, float expansion) const {
|
||||||
return isWithinExpanded(point.x, _corner.x, _size.x, expansion) &&
|
return isWithinExpanded(point.x, _corner.x, _scale, expansion) &&
|
||||||
isWithinExpanded(point.y, _corner.y, _size.y, expansion) &&
|
isWithinExpanded(point.y, _corner.y, _scale, expansion) &&
|
||||||
isWithinExpanded(point.z, _corner.z, _size.z, expansion);
|
isWithinExpanded(point.z, _corner.z, _scale, expansion);
|
||||||
}
|
}
|
||||||
|
|
||||||
// finds the intersection between a ray and the facing plane on one axis
|
// finds the intersection between a ray and the facing plane on one axis
|
||||||
|
@ -164,7 +147,7 @@ bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& e
|
||||||
}
|
}
|
||||||
// check each axis
|
// check each axis
|
||||||
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
|
glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion);
|
||||||
glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f;
|
glm::vec3 expandedSize = glm::vec3(_scale, _scale, _scale) + glm::vec3(expansion, expansion, expansion) * 2.0f;
|
||||||
glm::vec3 direction = end - start;
|
glm::vec3 direction = end - start;
|
||||||
float axisDistance;
|
float axisDistance;
|
||||||
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
|
return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) &&
|
||||||
|
@ -189,23 +172,23 @@ bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direct
|
||||||
}
|
}
|
||||||
// check each axis
|
// check each axis
|
||||||
float axisDistance;
|
float axisDistance;
|
||||||
if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 &&
|
if ((findIntersection(origin.x, direction.x, _corner.x, _scale, axisDistance) && axisDistance >= 0 &&
|
||||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
|
||||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) {
|
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||||
distance = axisDistance;
|
distance = axisDistance;
|
||||||
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
|
face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 &&
|
if ((findIntersection(origin.y, direction.y, _corner.y, _scale, axisDistance) && axisDistance >= 0 &&
|
||||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) &&
|
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale) &&
|
||||||
isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) {
|
isWithin(origin.z + axisDistance*direction.z, _corner.z, _scale))) {
|
||||||
distance = axisDistance;
|
distance = axisDistance;
|
||||||
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
|
face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if ((findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 &&
|
if ((findIntersection(origin.z, direction.z, _corner.z, _scale, axisDistance) && axisDistance >= 0 &&
|
||||||
isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) &&
|
isWithin(origin.y + axisDistance*direction.y, _corner.y, _scale) &&
|
||||||
isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) {
|
isWithin(origin.x + axisDistance*direction.x, _corner.x, _scale))) {
|
||||||
distance = axisDistance;
|
distance = axisDistance;
|
||||||
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE;
|
||||||
return true;
|
return true;
|
||||||
|
@ -268,27 +251,27 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) con
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case MIN_X_FACE:
|
case MIN_X_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||||
glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z));
|
glm::vec3(_corner.x, _corner.y + _scale, _corner.z + _scale));
|
||||||
|
|
||||||
case MAX_X_FACE:
|
case MAX_X_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z),
|
return glm::clamp(point, glm::vec3(_corner.x + _scale, _corner.y, _corner.z),
|
||||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||||
|
|
||||||
case MIN_Y_FACE:
|
case MIN_Y_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||||
glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z));
|
glm::vec3(_corner.x + _scale, _corner.y, _corner.z + _scale));
|
||||||
|
|
||||||
case MAX_Y_FACE:
|
case MAX_Y_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z),
|
return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _scale, _corner.z),
|
||||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||||
|
|
||||||
case MIN_Z_FACE:
|
case MIN_Z_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z),
|
||||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z));
|
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z));
|
||||||
|
|
||||||
case MAX_Z_FACE:
|
case MAX_Z_FACE:
|
||||||
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z),
|
return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _scale),
|
||||||
glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z));
|
glm::vec3(_corner.x + _scale, _corner.y + _scale, _corner.z + _scale));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +321,7 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
|
||||||
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
|
glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1));
|
||||||
|
|
||||||
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
|
glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f,
|
||||||
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f);
|
glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), glm::vec3(_scale, _scale, _scale)) * 0.5f);
|
||||||
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
|
glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset,
|
||||||
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
|
secondAxisMaxPlane + thirdAxisMaxPlane + offset };
|
||||||
|
|
||||||
|
@ -362,11 +345,11 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4&
|
||||||
glm::vec4 AABox::getPlane(BoxFace face) const {
|
glm::vec4 AABox::getPlane(BoxFace face) const {
|
||||||
switch (face) {
|
switch (face) {
|
||||||
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x);
|
||||||
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x);
|
case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _scale);
|
||||||
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
|
case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y);
|
||||||
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y);
|
case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _scale);
|
||||||
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
|
case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z);
|
||||||
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z);
|
case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,19 +36,14 @@ enum BoxVertex {
|
||||||
|
|
||||||
const int FACE_COUNT = 6;
|
const int FACE_COUNT = 6;
|
||||||
|
|
||||||
class AABox
|
class AABox {
|
||||||
{
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
AABox(const glm::vec3& corner, float size);
|
AABox(const glm::vec3& corner, float size);
|
||||||
AABox(const glm::vec3& corner, float x, float y, float z);
|
|
||||||
AABox(const glm::vec3& corner, const glm::vec3& size);
|
|
||||||
AABox();
|
AABox();
|
||||||
~AABox() {};
|
~AABox() {};
|
||||||
|
|
||||||
void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); };
|
void setBox(const glm::vec3& corner, float scale);
|
||||||
void setBox(const glm::vec3& corner, const glm::vec3& size);
|
|
||||||
|
|
||||||
// for use in frustum computations
|
// for use in frustum computations
|
||||||
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
glm::vec3 getVertexP(const glm::vec3& normal) const;
|
||||||
|
@ -57,9 +52,10 @@ public:
|
||||||
void scale(float scale);
|
void scale(float scale);
|
||||||
|
|
||||||
const glm::vec3& getCorner() const { return _corner; };
|
const glm::vec3& getCorner() const { return _corner; };
|
||||||
const glm::vec3& getSize() const { return _size; };
|
float getScale() const { return _scale; }
|
||||||
const glm::vec3& getCenter() const { return _center; };
|
|
||||||
const glm::vec3& getTopFarLeft() const { return _topFarLeft; };
|
glm::vec3 calcCenter() const;
|
||||||
|
glm::vec3 calcTopFarLeft() const;
|
||||||
|
|
||||||
glm::vec3 getVertex(BoxVertex vertex) const;
|
glm::vec3 getVertex(BoxVertex vertex) const;
|
||||||
|
|
||||||
|
@ -72,7 +68,6 @@ public:
|
||||||
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const;
|
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::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const;
|
||||||
glm::vec4 getPlane(BoxFace face) const;
|
glm::vec4 getPlane(BoxFace face) const;
|
||||||
|
@ -80,10 +75,7 @@ private:
|
||||||
static BoxFace getOppositeFace(BoxFace face);
|
static BoxFace getOppositeFace(BoxFace face);
|
||||||
|
|
||||||
glm::vec3 _corner;
|
glm::vec3 _corner;
|
||||||
glm::vec3 _center;
|
float _scale;
|
||||||
glm::vec3 _size;
|
|
||||||
glm::vec3 _topFarLeft;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -33,7 +33,7 @@ void JurisdictionListener::nodeAdded(Node* node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void JurisdictionListener::nodeKilled(Node* node) {
|
void JurisdictionListener::nodeKilled(Node* node) {
|
||||||
_jurisdictions.erase(_jurisdictions.find(node->getNodeID()));
|
_jurisdictions.erase(_jurisdictions.find(node->getUUID()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JurisdictionListener::queueJurisdictionRequest() {
|
bool JurisdictionListener::queueJurisdictionRequest() {
|
||||||
|
@ -66,10 +66,10 @@ void JurisdictionListener::processPacket(sockaddr& senderAddress, unsigned char*
|
||||||
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
|
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
|
||||||
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
if (node) {
|
if (node) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
QUuid nodeUUID = node->getUUID();
|
||||||
JurisdictionMap map;
|
JurisdictionMap map;
|
||||||
map.unpackFromMessage(packetData, packetLength);
|
map.unpackFromMessage(packetData, packetLength);
|
||||||
_jurisdictions[nodeID] = map;
|
_jurisdictions[nodeUUID] = map;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -132,7 +132,7 @@ void JurisdictionMap::init(unsigned char* rootOctalCode, const std::vector<unsig
|
||||||
_endNodes = endNodes;
|
_endNodes = endNodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const {
|
JurisdictionMap::Area JurisdictionMap::isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const {
|
||||||
// to be in our jurisdiction, we must be under the root...
|
// to be in our jurisdiction, we must be under the root...
|
||||||
|
|
||||||
// if the node is an ancestor of my root, then we return ABOVE
|
// if the node is an ancestor of my root, then we return ABOVE
|
||||||
|
|
|
@ -12,7 +12,9 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <QtCore/QString>
|
#include <QtCore/QString>
|
||||||
|
#include <QtCore/QUuid>
|
||||||
|
|
||||||
class JurisdictionMap {
|
class JurisdictionMap {
|
||||||
public:
|
public:
|
||||||
|
@ -41,7 +43,7 @@ public:
|
||||||
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
JurisdictionMap(const char* rootHextString, const char* endNodesHextString);
|
||||||
~JurisdictionMap();
|
~JurisdictionMap();
|
||||||
|
|
||||||
Area isMyJurisdiction(unsigned char* nodeOctalCode, int childIndex) const;
|
Area isMyJurisdiction(const unsigned char* nodeOctalCode, int childIndex) const;
|
||||||
|
|
||||||
bool writeToFile(const char* filename);
|
bool writeToFile(const char* filename);
|
||||||
bool readFromFile(const char* filename);
|
bool readFromFile(const char* filename);
|
||||||
|
@ -71,7 +73,7 @@ private:
|
||||||
|
|
||||||
/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are
|
/// Map between node IDs and their reported JurisdictionMap. Typically used by classes that need to know which nodes are
|
||||||
/// managing which jurisdictions.
|
/// managing which jurisdictions.
|
||||||
typedef std::map<uint16_t, JurisdictionMap> NodeToJurisdictionMap;
|
typedef std::map<QUuid, JurisdictionMap> NodeToJurisdictionMap;
|
||||||
|
|
||||||
|
|
||||||
#endif /* defined(__hifi__JurisdictionMap__) */
|
#endif /* defined(__hifi__JurisdictionMap__) */
|
||||||
|
|
|
@ -27,9 +27,9 @@ void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char*
|
||||||
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
|
if (packetData[0] == PACKET_TYPE_VOXEL_JURISDICTION_REQUEST) {
|
||||||
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||||
if (node) {
|
if (node) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
QUuid nodeUUID = node->getUUID();
|
||||||
lock();
|
lock();
|
||||||
_nodesRequestingJurisdictions.insert(nodeID);
|
_nodesRequestingJurisdictions.insert(nodeUUID);
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -52,11 +52,11 @@ bool JurisdictionSender::process() {
|
||||||
}
|
}
|
||||||
int nodeCount = 0;
|
int nodeCount = 0;
|
||||||
|
|
||||||
for (std::set<uint16_t>::iterator nodeIterator = _nodesRequestingJurisdictions.begin();
|
for (std::set<QUuid>::iterator nodeIterator = _nodesRequestingJurisdictions.begin();
|
||||||
nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) {
|
nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) {
|
||||||
|
|
||||||
uint16_t nodeID = *nodeIterator;
|
QUuid nodeUUID = *nodeIterator;
|
||||||
Node* node = NodeList::getInstance()->nodeWithID(nodeID);
|
Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||||
|
|
||||||
if (node->getActiveSocket() != NULL) {
|
if (node->getActiveSocket() != NULL) {
|
||||||
sockaddr* nodeAddress = node->getActiveSocket();
|
sockaddr* nodeAddress = node->getActiveSocket();
|
||||||
|
|
|
@ -35,6 +35,6 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JurisdictionMap* _jurisdictionMap;
|
JurisdictionMap* _jurisdictionMap;
|
||||||
std::set<uint16_t> _nodesRequestingJurisdictions;
|
std::set<QUuid> _nodesRequestingJurisdictions;
|
||||||
};
|
};
|
||||||
#endif // __shared__JurisdictionSender__
|
#endif // __shared__JurisdictionSender__
|
||||||
|
|
|
@ -543,7 +543,8 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_PROJECTED_POLYGON_VERT
|
||||||
|
|
||||||
VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
||||||
const glm::vec3& bottomNearRight = box.getCorner();
|
const glm::vec3& bottomNearRight = box.getCorner();
|
||||||
const glm::vec3& topFarLeft = box.getTopFarLeft();
|
glm::vec3 topFarLeft = box.calcTopFarLeft();
|
||||||
|
|
||||||
int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit
|
int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit
|
||||||
+ ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to
|
+ ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to
|
||||||
+ ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera
|
+ ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera
|
||||||
|
@ -596,7 +597,7 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
||||||
***/
|
***/
|
||||||
}
|
}
|
||||||
// set the distance from our camera position, to the closest vertex
|
// set the distance from our camera position, to the closest vertex
|
||||||
float distance = glm::distance(getPosition(), box.getCenter());
|
float distance = glm::distance(getPosition(), box.calcCenter());
|
||||||
projectedPolygon.setDistance(distance);
|
projectedPolygon.setDistance(distance);
|
||||||
projectedPolygon.setAnyInView(anyPointsInView);
|
projectedPolygon.setAnyInView(anyPointsInView);
|
||||||
projectedPolygon.setAllInView(allPointsInView);
|
projectedPolygon.setAllInView(allPointsInView);
|
||||||
|
@ -609,9 +610,9 @@ VoxelProjectedPolygon ViewFrustum::getProjectedPolygon(const AABox& box) const {
|
||||||
// axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for
|
// axis-aligned voxels to determine which of the voxels vertices must be the furthest. No need for
|
||||||
// squares and square-roots. Just compares.
|
// squares and square-roots. Just compares.
|
||||||
glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const {
|
glm::vec3 ViewFrustum::getFurthestPointFromCamera(const AABox& box) const {
|
||||||
const glm::vec3& center = box.getCenter();
|
|
||||||
const glm::vec3& bottomNearRight = box.getCorner();
|
const glm::vec3& bottomNearRight = box.getCorner();
|
||||||
const glm::vec3& topFarLeft = box.getTopFarLeft();
|
glm::vec3 center = box.calcCenter();
|
||||||
|
glm::vec3 topFarLeft = box.calcTopFarLeft();
|
||||||
|
|
||||||
glm::vec3 furthestPoint;
|
glm::vec3 furthestPoint;
|
||||||
if (_position.x < center.x) {
|
if (_position.x < center.x) {
|
||||||
|
|
|
@ -97,7 +97,6 @@ public:
|
||||||
glm::vec3 getFurthestPointFromCamera(const AABox& box) const;
|
glm::vec3 getFurthestPointFromCamera(const AABox& box) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
// Used for keyhole calculations
|
// Used for keyhole calculations
|
||||||
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
ViewFrustum::location pointInKeyhole(const glm::vec3& point) const;
|
||||||
ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const;
|
ViewFrustum::location sphereInKeyhole(const glm::vec3& center, float radius) const;
|
||||||
|
|
|
@ -17,8 +17,8 @@
|
||||||
#include "VoxelEditPacketSender.h"
|
#include "VoxelEditPacketSender.h"
|
||||||
|
|
||||||
|
|
||||||
EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssize_t length, uint16_t nodeID) {
|
EditPacketBuffer::EditPacketBuffer(PACKET_TYPE type, unsigned char* buffer, ssize_t length, QUuid nodeUUID) {
|
||||||
_nodeID = nodeID;
|
_nodeUUID = nodeUUID;
|
||||||
_currentType = type;
|
_currentType = type;
|
||||||
_currentSize = length;
|
_currentSize = length;
|
||||||
memcpy(_currentBuffer, buffer, length);
|
memcpy(_currentBuffer, buffer, length);
|
||||||
|
@ -89,8 +89,13 @@ bool VoxelEditPacketSender::voxelServersExist() const {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
return true;
|
if (node->getActiveSocket()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
// we don't have an active socket for this node, ping it
|
||||||
|
nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -98,14 +103,19 @@ bool VoxelEditPacketSender::voxelServersExist() const {
|
||||||
|
|
||||||
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
|
// This method is called when the edit packet layer has determined that it has a fully formed packet destined for
|
||||||
// a known nodeID. However, we also want to handle the case where the
|
// a known nodeID. However, we also want to handle the case where the
|
||||||
void VoxelEditPacketSender::queuePacketToNode(uint16_t nodeID, unsigned char* buffer, ssize_t length) {
|
void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, ssize_t length) {
|
||||||
NodeList* nodeList = NodeList::getInstance();
|
NodeList* nodeList = NodeList::getInstance();
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER &&
|
if (node->getType() == NODE_TYPE_VOXEL_SERVER &&
|
||||||
((node->getNodeID() == nodeID) || (nodeID == (uint16_t)UNKNOWN_NODE_ID)) ) {
|
((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
|
||||||
sockaddr* nodeAddress = node->getActiveSocket();
|
if (node->getActiveSocket()) {
|
||||||
queuePacketForSending(*nodeAddress, buffer, length);
|
sockaddr* nodeAddress = node->getActiveSocket();
|
||||||
|
queuePacketForSending(*nodeAddress, buffer, length);
|
||||||
|
} else {
|
||||||
|
// we don't have an active socket for this node, ping it
|
||||||
|
nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -170,14 +180,14 @@ void VoxelEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t le
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
QUuid nodeUUID = node->getUUID();
|
||||||
bool isMyJurisdiction = true;
|
bool isMyJurisdiction = true;
|
||||||
// we need to get the jurisdiction for this
|
// we need to get the jurisdiction for this
|
||||||
// here we need to get the "pending packet" for this server
|
// here we need to get the "pending packet" for this server
|
||||||
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeID];
|
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
|
||||||
isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
|
isMyJurisdiction = (map.isMyJurisdiction(octCode, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
|
||||||
if (isMyJurisdiction) {
|
if (isMyJurisdiction) {
|
||||||
queuePacketToNode(nodeID, buffer, length);
|
queuePacketToNode(nodeUUID, buffer, length);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,18 +226,18 @@ void VoxelEditPacketSender::queueVoxelEditMessage(PACKET_TYPE type, unsigned cha
|
||||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||||
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
if (node->getActiveSocket() != NULL && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||||
uint16_t nodeID = node->getNodeID();
|
QUuid nodeUUID = node->getUUID();
|
||||||
bool isMyJurisdiction = true;
|
bool isMyJurisdiction = true;
|
||||||
|
|
||||||
if (_voxelServerJurisdictions) {
|
if (_voxelServerJurisdictions) {
|
||||||
// we need to get the jurisdiction for this
|
// we need to get the jurisdiction for this
|
||||||
// here we need to get the "pending packet" for this server
|
// here we need to get the "pending packet" for this server
|
||||||
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeID];
|
const JurisdictionMap& map = (*_voxelServerJurisdictions)[nodeUUID];
|
||||||
isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
|
isMyJurisdiction = (map.isMyJurisdiction(codeColorBuffer, CHECK_NODE_ONLY) == JurisdictionMap::WITHIN);
|
||||||
}
|
}
|
||||||
if (isMyJurisdiction) {
|
if (isMyJurisdiction) {
|
||||||
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeID];
|
EditPacketBuffer& packetBuffer = _pendingEditPackets[nodeUUID];
|
||||||
packetBuffer._nodeID = nodeID;
|
packetBuffer._nodeUUID = nodeUUID;
|
||||||
|
|
||||||
// If we're switching type, then we send the last one and start over
|
// If we're switching type, then we send the last one and start over
|
||||||
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
|
if ((type != packetBuffer._currentType && packetBuffer._currentSize > 0) ||
|
||||||
|
@ -255,14 +265,14 @@ void VoxelEditPacketSender::releaseQueuedMessages() {
|
||||||
if (!voxelServersExist()) {
|
if (!voxelServersExist()) {
|
||||||
_releaseQueuedMessagesPending = true;
|
_releaseQueuedMessagesPending = true;
|
||||||
} else {
|
} else {
|
||||||
for (std::map<uint16_t,EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
|
for (std::map<QUuid, EditPacketBuffer>::iterator i = _pendingEditPackets.begin(); i != _pendingEditPackets.end(); i++) {
|
||||||
releaseQueuedPacket(i->second);
|
releaseQueuedPacket(i->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void VoxelEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) {
|
void VoxelEditPacketSender::releaseQueuedPacket(EditPacketBuffer& packetBuffer) {
|
||||||
queuePacketToNode(packetBuffer._nodeID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
|
queuePacketToNode(packetBuffer._nodeUUID, &packetBuffer._currentBuffer[0], packetBuffer._currentSize);
|
||||||
packetBuffer._currentSize = 0;
|
packetBuffer._currentSize = 0;
|
||||||
packetBuffer._currentType = PACKET_TYPE_UNKNOWN;
|
packetBuffer._currentType = PACKET_TYPE_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,9 +19,9 @@
|
||||||
/// Used for construction of edit voxel packets
|
/// Used for construction of edit voxel packets
|
||||||
class EditPacketBuffer {
|
class EditPacketBuffer {
|
||||||
public:
|
public:
|
||||||
EditPacketBuffer() { _currentSize = 0; _currentType = PACKET_TYPE_UNKNOWN; _nodeID = UNKNOWN_NODE_ID; }
|
EditPacketBuffer() : _nodeUUID(), _currentType(PACKET_TYPE_UNKNOWN), _currentSize(0) { }
|
||||||
EditPacketBuffer(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length, uint16_t nodeID = UNKNOWN_NODE_ID);
|
EditPacketBuffer(PACKET_TYPE type, unsigned char* codeColorBuffer, ssize_t length, const QUuid nodeUUID = QUuid());
|
||||||
uint16_t _nodeID;
|
QUuid _nodeUUID;
|
||||||
PACKET_TYPE _currentType;
|
PACKET_TYPE _currentType;
|
||||||
unsigned char _currentBuffer[MAX_PACKET_SIZE];
|
unsigned char _currentBuffer[MAX_PACKET_SIZE];
|
||||||
ssize_t _currentSize;
|
ssize_t _currentSize;
|
||||||
|
@ -83,18 +83,20 @@ public:
|
||||||
|
|
||||||
// the default number of pending messages we will store if no voxel servers are available
|
// the default number of pending messages we will store if no voxel servers are available
|
||||||
static const int DEFAULT_MAX_PENDING_MESSAGES;
|
static const int DEFAULT_MAX_PENDING_MESSAGES;
|
||||||
|
|
||||||
|
bool voxelServersExist() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _shouldSend;
|
bool _shouldSend;
|
||||||
void queuePacketToNode(uint16_t nodeID, unsigned char* buffer, ssize_t length);
|
void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length);
|
||||||
void queuePacketToNodes(unsigned char* buffer, ssize_t length);
|
void queuePacketToNodes(unsigned char* buffer, ssize_t length);
|
||||||
void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type);
|
void initializePacket(EditPacketBuffer& packetBuffer, PACKET_TYPE type);
|
||||||
void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
|
void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet
|
||||||
bool voxelServersExist() const;
|
|
||||||
void processPreServerExistsPackets();
|
void processPreServerExistsPackets();
|
||||||
|
|
||||||
// These are packets which are destined from know servers but haven't been released because they're still too small
|
// These are packets which are destined from know servers but haven't been released because they're still too small
|
||||||
std::map<uint16_t,EditPacketBuffer> _pendingEditPackets;
|
std::map<QUuid, EditPacketBuffer> _pendingEditPackets;
|
||||||
|
|
||||||
// These are packets that are waiting to be processed because we don't yet know if there are voxel servers
|
// These are packets that are waiting to be processed because we don't yet know if there are voxel servers
|
||||||
int _maxPendingMessages;
|
int _maxPendingMessages;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -41,8 +41,8 @@ public:
|
||||||
VoxelNode(unsigned char * octalCode); // regular constructor
|
VoxelNode(unsigned char * octalCode); // regular constructor
|
||||||
~VoxelNode();
|
~VoxelNode();
|
||||||
|
|
||||||
unsigned char* getOctalCode() const { return _octalCode; }
|
const unsigned char* getOctalCode() const { return (_octcodePointer) ? _octalCode.pointer : &_octalCode.buffer[0]; }
|
||||||
VoxelNode* getChildAtIndex(int childIndex) const { return _children[childIndex]; }
|
VoxelNode* getChildAtIndex(int childIndex) const;
|
||||||
void deleteChildAtIndex(int childIndex);
|
void deleteChildAtIndex(int childIndex);
|
||||||
VoxelNode* removeChildAtIndex(int childIndex);
|
VoxelNode* removeChildAtIndex(int childIndex);
|
||||||
VoxelNode* addChildAtIndex(int childIndex);
|
VoxelNode* addChildAtIndex(int childIndex);
|
||||||
|
@ -53,10 +53,9 @@ public:
|
||||||
bool collapseIdenticalLeaves();
|
bool collapseIdenticalLeaves();
|
||||||
|
|
||||||
const AABox& getAABox() const { return _box; }
|
const AABox& getAABox() const { return _box; }
|
||||||
const glm::vec3& getCenter() const { return _box.getCenter(); }
|
|
||||||
const glm::vec3& getCorner() const { return _box.getCorner(); }
|
const glm::vec3& getCorner() const { return _box.getCorner(); }
|
||||||
float getScale() const { return _box.getSize().x; } // voxelScale = (1 / powf(2, *node->getOctalCode())); }
|
float getScale() const { return _box.getScale(); }
|
||||||
int getLevel() const { return *_octalCode + 1; } // one based or zero based? this doesn't correctly handle 2 byte case
|
int getLevel() const { return numberOfThreeBitSectionsInCode(getOctalCode()) + 1; }
|
||||||
|
|
||||||
float getEnclosingRadius() const;
|
float getEnclosingRadius() const;
|
||||||
|
|
||||||
|
@ -72,8 +71,8 @@ public:
|
||||||
float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this.
|
float distanceSquareToPoint(const glm::vec3& point) const; // when you don't need the actual distance, use this.
|
||||||
float distanceToPoint(const glm::vec3& point) const;
|
float distanceToPoint(const glm::vec3& point) const;
|
||||||
|
|
||||||
bool isLeaf() const { return _childCount == 0; }
|
bool isLeaf() const { return getChildCount() == 0; }
|
||||||
int getChildCount() const { return _childCount; }
|
int getChildCount() const { return numberOfOnes(_childBitmask); }
|
||||||
void printDebugDetails(const char* label) const;
|
void printDebugDetails(const char* label) const;
|
||||||
bool isDirty() const { return _isDirty; }
|
bool isDirty() const { return _isDirty; }
|
||||||
void clearDirtyBit() { _isDirty = false; }
|
void clearDirtyBit() { _isDirty = false; }
|
||||||
|
@ -84,37 +83,30 @@ public:
|
||||||
void handleSubtreeChanged(VoxelTree* myTree);
|
void handleSubtreeChanged(VoxelTree* myTree);
|
||||||
|
|
||||||
glBufferIndex getBufferIndex() const { return _glBufferIndex; }
|
glBufferIndex getBufferIndex() const { return _glBufferIndex; }
|
||||||
bool isKnownBufferIndex() const { return (_glBufferIndex != GLBUFFER_INDEX_UNKNOWN); }
|
bool isKnownBufferIndex() const { return !_unknownBufferIndex; }
|
||||||
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; }
|
void setBufferIndex(glBufferIndex index) { _glBufferIndex = index; _unknownBufferIndex =(index == GLBUFFER_INDEX_UNKNOWN);}
|
||||||
VoxelSystem* getVoxelSystem() const { return _voxelSystem; }
|
VoxelSystem* getVoxelSystem() const;
|
||||||
void setVoxelSystem(VoxelSystem* voxelSystem) { _voxelSystem = voxelSystem; }
|
void setVoxelSystem(VoxelSystem* voxelSystem);
|
||||||
|
|
||||||
|
|
||||||
// Used by VoxelSystem for rendering in/out of view and LOD
|
// Used by VoxelSystem for rendering in/out of view and LOD
|
||||||
void setShouldRender(bool shouldRender);
|
void setShouldRender(bool shouldRender);
|
||||||
bool getShouldRender() const { return _shouldRender; }
|
bool getShouldRender() const { return _shouldRender; }
|
||||||
|
|
||||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
|
||||||
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
void setFalseColor(colorPart red, colorPart green, colorPart blue);
|
||||||
void setFalseColored(bool isFalseColored);
|
void setFalseColored(bool isFalseColored);
|
||||||
bool getFalseColored() { return _falseColored; }
|
bool getFalseColored() { return _falseColored; }
|
||||||
void setColor(const nodeColor& color);
|
void setColor(const nodeColor& color);
|
||||||
const nodeColor& getTrueColor() const { return _trueColor; }
|
const nodeColor& getTrueColor() const { return _trueColor; }
|
||||||
const nodeColor& getColor() const { return _currentColor; }
|
const nodeColor& getColor() const { return _currentColor; }
|
||||||
#else
|
|
||||||
void setFalseColor(colorPart red, colorPart green, colorPart blue) { /* no op */ };
|
|
||||||
void setFalseColored(bool isFalseColored) { /* no op */ };
|
|
||||||
bool getFalseColored() { return false; };
|
|
||||||
void setColor(const nodeColor& color) { memcpy(_trueColor,color,sizeof(nodeColor)); };
|
|
||||||
void setDensity(const float density) { _density = density; };
|
|
||||||
const nodeColor& getTrueColor() const { return _trueColor; };
|
|
||||||
const nodeColor& getColor() const { return _trueColor; };
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void setDensity(float density) { _density = density; }
|
void setDensity(float density) { _density = density; }
|
||||||
float getDensity() const { return _density; }
|
float getDensity() const { return _density; }
|
||||||
void setSourceID(uint16_t sourceID) { _sourceID = sourceID; }
|
|
||||||
uint16_t getSourceID() const { return _sourceID; }
|
void setSourceUUID(const QUuid& sourceID);
|
||||||
|
QUuid getSourceUUID() const;
|
||||||
|
uint16_t getSourceUUIDKey() const { return _sourceUUIDKey; }
|
||||||
|
bool matchesSourceUUID(const QUuid& sourceUUID) const;
|
||||||
|
static uint16_t getSourceNodeUUIDKey(const QUuid& sourceUUID);
|
||||||
|
|
||||||
static void addDeleteHook(VoxelNodeDeleteHook* hook);
|
static void addDeleteHook(VoxelNodeDeleteHook* hook);
|
||||||
static void removeDeleteHook(VoxelNodeDeleteHook* hook);
|
static void removeDeleteHook(VoxelNodeDeleteHook* hook);
|
||||||
|
@ -122,49 +114,131 @@ public:
|
||||||
static void addUpdateHook(VoxelNodeUpdateHook* hook);
|
static void addUpdateHook(VoxelNodeUpdateHook* hook);
|
||||||
static void removeUpdateHook(VoxelNodeUpdateHook* hook);
|
static void removeUpdateHook(VoxelNodeUpdateHook* hook);
|
||||||
|
|
||||||
void recalculateSubTreeNodeCount();
|
static unsigned long getNodeCount() { return _voxelNodeCount; }
|
||||||
unsigned long getSubTreeNodeCount() const { return _subtreeNodeCount; }
|
static unsigned long getInternalNodeCount() { return _voxelNodeCount - _voxelNodeLeafCount; }
|
||||||
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; }
|
static unsigned long getLeafNodeCount() { return _voxelNodeLeafCount; }
|
||||||
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; }
|
|
||||||
|
|
||||||
static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; }
|
static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; }
|
||||||
static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
|
static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
|
||||||
|
static uint64_t getExternalChildrenMemoryUsage() { return _externalChildrenMemoryUsage; }
|
||||||
|
static uint64_t getTotalMemoryUsage() { return _voxelMemoryUsage + _octcodeMemoryUsage + _externalChildrenMemoryUsage; }
|
||||||
|
|
||||||
|
static uint64_t getGetChildAtIndexTime() { return _getChildAtIndexTime; }
|
||||||
|
static uint64_t getGetChildAtIndexCalls() { return _getChildAtIndexCalls; }
|
||||||
|
static uint64_t getSetChildAtIndexTime() { return _setChildAtIndexTime; }
|
||||||
|
static uint64_t getSetChildAtIndexCalls() { return _setChildAtIndexCalls; }
|
||||||
|
|
||||||
|
static uint64_t getSingleChildrenCount() { return _singleChildrenCount; }
|
||||||
|
static uint64_t getTwoChildrenOffsetCount() { return _twoChildrenOffsetCount; }
|
||||||
|
static uint64_t getTwoChildrenExternalCount() { return _twoChildrenExternalCount; }
|
||||||
|
static uint64_t getThreeChildrenOffsetCount() { return _threeChildrenOffsetCount; }
|
||||||
|
static uint64_t getThreeChildrenExternalCount() { return _threeChildrenExternalCount; }
|
||||||
|
static uint64_t getExternalChildrenCount() { return _externalChildrenCount; }
|
||||||
|
static uint64_t getChildrenCount(int childCount) { return _childrenCount[childCount]; }
|
||||||
|
|
||||||
|
static uint64_t getCouldStoreFourChildrenInternally() { return _couldStoreFourChildrenInternally; }
|
||||||
|
static uint64_t getCouldNotStoreFourChildrenInternally() { return _couldNotStoreFourChildrenInternally; }
|
||||||
|
|
||||||
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
|
void auditChildren(const char* label) const;
|
||||||
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void setChildAtIndex(int childIndex, VoxelNode* child);
|
||||||
|
void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo);
|
||||||
|
void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo);
|
||||||
|
void storeThreeChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree);
|
||||||
|
void retrieveThreeChildren(VoxelNode*& childOne, VoxelNode*& childTwo, VoxelNode*& childThree);
|
||||||
|
void decodeThreeOffsets(int64_t& offsetOne, int64_t& offsetTwo, int64_t& offsetThree) const;
|
||||||
|
void encodeThreeOffsets(int64_t offsetOne, int64_t offsetTwo, int64_t offsetThree);
|
||||||
|
void checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo, VoxelNode* childThree, VoxelNode* childFour);
|
||||||
|
|
||||||
void calculateAABox();
|
void calculateAABox();
|
||||||
void init(unsigned char * octalCode);
|
void init(unsigned char * octalCode);
|
||||||
void notifyDeleteHooks();
|
void notifyDeleteHooks();
|
||||||
void notifyUpdateHooks();
|
void notifyUpdateHooks();
|
||||||
|
|
||||||
VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes
|
|
||||||
AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
|
AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes
|
||||||
unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes
|
|
||||||
|
/// Client and server, buffer containing the octal code or a pointer to octal code for this node, 8 bytes
|
||||||
|
union octalCode_t {
|
||||||
|
unsigned char buffer[8];
|
||||||
|
unsigned char* pointer;
|
||||||
|
} _octalCode;
|
||||||
|
|
||||||
uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes
|
uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes
|
||||||
unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes
|
|
||||||
unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes
|
|
||||||
|
|
||||||
glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes
|
/// Client and server, pointers to child nodes, various encodings
|
||||||
VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes
|
union children_t {
|
||||||
|
VoxelNode* single;
|
||||||
|
int32_t offsetsTwoChildren[2];
|
||||||
|
uint64_t offsetsThreeChildrenEncoded;
|
||||||
|
VoxelNode** external;
|
||||||
|
} _children;
|
||||||
|
|
||||||
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
|
VoxelNode* _childrenArray[8]; /// Only used when HAS_AUDIT_CHILDREN is enabled to help debug children encoding
|
||||||
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
|
|
||||||
|
uint32_t _glBufferIndex : 24, /// Client only, vbo index for this voxel if being rendered, 3 bytes
|
||||||
|
_voxelSystemIndex : 8; /// Client only, index to the VoxelSystem rendering this voxel, 1 bytes
|
||||||
|
|
||||||
|
// Support for _voxelSystemIndex, we use these static member variables to track the VoxelSystems that are
|
||||||
|
// in use by various voxel nodes. We map the VoxelSystem pointers into an 1 byte key, this limits us to at
|
||||||
|
// most 255 voxel systems in use at a time within the client. Which is far more than we need.
|
||||||
|
static uint8_t _nextIndex;
|
||||||
|
static std::map<VoxelSystem*, uint8_t> _mapVoxelSystemPointersToIndex;
|
||||||
|
static std::map<uint8_t, VoxelSystem*> _mapIndexToVoxelSystemPointers;
|
||||||
|
|
||||||
float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes
|
float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes
|
||||||
int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes
|
|
||||||
|
|
||||||
nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes
|
nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes
|
||||||
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
|
||||||
nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes
|
nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes
|
||||||
bool _falseColored; /// Client only, is this voxel false colored, 1 bytes
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte
|
|
||||||
bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte
|
|
||||||
uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
|
||||||
|
|
||||||
|
uint16_t _sourceUUIDKey; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
||||||
|
|
||||||
|
// Support for _sourceUUID, we use these static member variables to track the UUIDs that are
|
||||||
|
// in use by various voxel server nodes. We map the UUID strings into an 16 bit key, this limits us to at
|
||||||
|
// most 65k voxel servers in use at a time within the client. Which is far more than we need.
|
||||||
|
static uint16_t _nextUUIDKey; // start at 1, 0 is reserved for NULL
|
||||||
|
static std::map<QString, uint16_t> _mapSourceUUIDsToKeys;
|
||||||
|
static std::map<uint16_t, QString> _mapKeysToSourceUUIDs;
|
||||||
|
|
||||||
|
unsigned char _childBitmask; // 1 byte
|
||||||
|
|
||||||
|
bool _falseColored : 1, /// Client only, is this voxel false colored, 1 bit
|
||||||
|
_isDirty : 1, /// Client only, has this voxel changed since being rendered, 1 bit
|
||||||
|
_shouldRender : 1, /// Client only, should this voxel render at this time, 1 bit
|
||||||
|
_octcodePointer : 1, /// Client and Server only, is this voxel's octal code a pointer or buffer, 1 bit
|
||||||
|
_unknownBufferIndex : 1,
|
||||||
|
_childrenExternal : 1; /// Client only, is this voxel's VBO buffer the unknown buffer index, 1 bit
|
||||||
|
|
||||||
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
|
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
|
||||||
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
|
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
|
||||||
|
|
||||||
|
static uint64_t _voxelNodeCount;
|
||||||
|
static uint64_t _voxelNodeLeafCount;
|
||||||
|
|
||||||
static uint64_t _voxelMemoryUsage;
|
static uint64_t _voxelMemoryUsage;
|
||||||
static uint64_t _octcodeMemoryUsage;
|
static uint64_t _octcodeMemoryUsage;
|
||||||
|
static uint64_t _externalChildrenMemoryUsage;
|
||||||
|
|
||||||
|
static uint64_t _getChildAtIndexTime;
|
||||||
|
static uint64_t _getChildAtIndexCalls;
|
||||||
|
static uint64_t _setChildAtIndexTime;
|
||||||
|
static uint64_t _setChildAtIndexCalls;
|
||||||
|
|
||||||
|
static uint64_t _singleChildrenCount;
|
||||||
|
static uint64_t _twoChildrenOffsetCount;
|
||||||
|
static uint64_t _twoChildrenExternalCount;
|
||||||
|
static uint64_t _threeChildrenOffsetCount;
|
||||||
|
static uint64_t _threeChildrenExternalCount;
|
||||||
|
static uint64_t _externalChildrenCount;
|
||||||
|
static uint64_t _childrenCount[NUMBER_OF_CHILDREN + 1];
|
||||||
|
|
||||||
|
static uint64_t _couldStoreFourChildrenInternally;
|
||||||
|
static uint64_t _couldNotStoreFourChildrenInternally;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__VoxelNode__) */
|
#endif /* defined(__hifi__VoxelNode__) */
|
|
@ -33,9 +33,10 @@ void VoxelSceneStats::sceneStarted(bool isFullScene, bool isMoving, VoxelNode* r
|
||||||
reset(); // resets packet and voxel stats
|
reset(); // resets packet and voxel stats
|
||||||
_isStarted = true;
|
_isStarted = true;
|
||||||
_start = usecTimestampNow();
|
_start = usecTimestampNow();
|
||||||
_totalVoxels = root->getSubTreeNodeCount();
|
|
||||||
_totalInternal = root->getSubTreeInternalNodeCount();
|
_totalVoxels = VoxelNode::getNodeCount();
|
||||||
_totalLeaves = root->getSubTreeLeafNodeCount();
|
_totalInternal = VoxelNode::getInternalNodeCount();
|
||||||
|
_totalLeaves = VoxelNode::getLeafNodeCount();
|
||||||
|
|
||||||
_isFullScene = isFullScene;
|
_isFullScene = isFullScene;
|
||||||
_isMoving = isMoving;
|
_isMoving = isMoving;
|
||||||
|
|
|
@ -134,7 +134,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV
|
||||||
|
|
||||||
|
|
||||||
VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode,
|
VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode,
|
||||||
unsigned char* needleCode, VoxelNode** parentOfFoundNode) const {
|
const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const {
|
||||||
// find the appropriate branch index based on this ancestorNode
|
// find the appropriate branch index based on this ancestorNode
|
||||||
if (*needleCode > 0) {
|
if (*needleCode > 0) {
|
||||||
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode);
|
||||||
|
@ -221,7 +221,7 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData,
|
||||||
if (childNodeAt) {
|
if (childNodeAt) {
|
||||||
nodeWasDirty = childNodeAt->isDirty();
|
nodeWasDirty = childNodeAt->isDirty();
|
||||||
childNodeAt->setColor(newColor);
|
childNodeAt->setColor(newColor);
|
||||||
childNodeAt->setSourceID(args.sourceID);
|
childNodeAt->setSourceUUID(args.sourceUUID);
|
||||||
|
|
||||||
// if we had a local version of the node already, it's possible that we have it in the VBO but
|
// if we had a local version of the node already, it's possible that we have it in the VBO but
|
||||||
// with the same color data, so this won't count as a change. To address this we check the following
|
// with the same color data, so this won't count as a change. To address this we check the following
|
||||||
|
@ -630,9 +630,22 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode)
|
// Note: this is an expensive call. Don't call it unless you really need to reaverage the entire tree (from startNode)
|
||||||
void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
void VoxelTree::reaverageVoxelColors(VoxelNode* startNode) {
|
||||||
// if our tree is a reaveraging tree, then we do this, otherwise we don't do anything
|
// if our tree is a reaveraging tree, then we do this, otherwise we don't do anything
|
||||||
if (_shouldReaverage) {
|
if (_shouldReaverage) {
|
||||||
|
static int recursionCount;
|
||||||
|
if (startNode == rootNode) {
|
||||||
|
recursionCount = 0;
|
||||||
|
} else {
|
||||||
|
recursionCount++;
|
||||||
|
}
|
||||||
|
const int UNREASONABLY_DEEP_RECURSION = 20;
|
||||||
|
if (recursionCount > UNREASONABLY_DEEP_RECURSION) {
|
||||||
|
qDebug("VoxelTree::reaverageVoxelColors()... bailing out of UNREASONABLY_DEEP_RECURSION\n");
|
||||||
|
recursionCount--;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
bool hasChildren = false;
|
bool hasChildren = false;
|
||||||
|
|
||||||
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
|
||||||
|
@ -647,9 +660,7 @@ void VoxelTree::reaverageVoxelColors(VoxelNode *startNode) {
|
||||||
if (hasChildren && !startNode->collapseIdenticalLeaves()) {
|
if (hasChildren && !startNode->collapseIdenticalLeaves()) {
|
||||||
startNode->setColorFromAverageOfChildren();
|
startNode->setColorFromAverageOfChildren();
|
||||||
}
|
}
|
||||||
|
recursionCount--;
|
||||||
// this is also a good time to recalculateSubTreeNodeCount()
|
|
||||||
startNode->recalculateSubTreeNodeCount();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -713,6 +724,11 @@ VoxelNode* VoxelTree::getVoxelAt(float x, float y, float z, float s) const {
|
||||||
node = NULL;
|
node = NULL;
|
||||||
}
|
}
|
||||||
delete[] octalCode; // cleanup memory
|
delete[] octalCode; // cleanup memory
|
||||||
|
#ifdef HAS_AUDIT_CHILDREN
|
||||||
|
if (node) {
|
||||||
|
node->auditChildren("VoxelTree::getVoxelAt()");
|
||||||
|
}
|
||||||
|
#endif // def HAS_AUDIT_CHILDREN
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1555,7 +1571,7 @@ bool VoxelTree::readFromSVOFile(const char* fileName) {
|
||||||
unsigned char* entireFile = new unsigned char[fileLength];
|
unsigned char* entireFile = new unsigned char[fileLength];
|
||||||
file.read((char*)entireFile, fileLength);
|
file.read((char*)entireFile, fileLength);
|
||||||
bool wantImportProgress = true;
|
bool wantImportProgress = true;
|
||||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, UNKNOWN_NODE_ID, wantImportProgress);
|
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, NULL, 0, wantImportProgress);
|
||||||
readBitstreamToTree(entireFile, fileLength, args);
|
readBitstreamToTree(entireFile, fileLength, args);
|
||||||
delete[] entireFile;
|
delete[] entireFile;
|
||||||
|
|
||||||
|
@ -1815,7 +1831,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin
|
||||||
|
|
||||||
// ask destination tree to read the bitstream
|
// ask destination tree to read the bitstream
|
||||||
bool wantImportProgress = true;
|
bool wantImportProgress = true;
|
||||||
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, UNKNOWN_NODE_ID, wantImportProgress);
|
ReadBitstreamToTreeParams args(WANT_COLOR, NO_EXISTS_BITS, destinationNode, 0, wantImportProgress);
|
||||||
readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
|
readBitstreamToTree(&outputBuffer[0], bytesWritten, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1981,7 +1997,7 @@ bool VoxelTree::nudgeCheck(VoxelNode* node, void* extraData) {
|
||||||
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
||||||
|
|
||||||
// get octal code of this node
|
// get octal code of this node
|
||||||
unsigned char* octalCode = node->getOctalCode();
|
const unsigned char* octalCode = node->getOctalCode();
|
||||||
|
|
||||||
// get voxel position/size
|
// get voxel position/size
|
||||||
VoxelPositionSize unNudgedDetails;
|
VoxelPositionSize unNudgedDetails;
|
||||||
|
@ -2020,7 +2036,7 @@ void VoxelTree::nudgeLeaf(VoxelNode* node, void* extraData) {
|
||||||
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
NodeChunkArgs* args = (NodeChunkArgs*)extraData;
|
||||||
|
|
||||||
// get octal code of this node
|
// get octal code of this node
|
||||||
unsigned char* octalCode = node->getOctalCode();
|
const unsigned char* octalCode = node->getOctalCode();
|
||||||
|
|
||||||
// get voxel position/size
|
// get voxel position/size
|
||||||
VoxelPositionSize unNudgedDetails;
|
VoxelPositionSize unNudgedDetails;
|
||||||
|
|
|
@ -101,19 +101,19 @@ public:
|
||||||
bool includeColor;
|
bool includeColor;
|
||||||
bool includeExistsBits;
|
bool includeExistsBits;
|
||||||
VoxelNode* destinationNode;
|
VoxelNode* destinationNode;
|
||||||
uint16_t sourceID;
|
QUuid sourceUUID;
|
||||||
bool wantImportProgress;
|
bool wantImportProgress;
|
||||||
|
|
||||||
ReadBitstreamToTreeParams(
|
ReadBitstreamToTreeParams(
|
||||||
bool includeColor = WANT_COLOR,
|
bool includeColor = WANT_COLOR,
|
||||||
bool includeExistsBits = WANT_EXISTS_BITS,
|
bool includeExistsBits = WANT_EXISTS_BITS,
|
||||||
VoxelNode* destinationNode = NULL,
|
VoxelNode* destinationNode = NULL,
|
||||||
uint16_t sourceID = UNKNOWN_NODE_ID,
|
QUuid sourceUUID = QUuid(),
|
||||||
bool wantImportProgress = false) :
|
bool wantImportProgress = false) :
|
||||||
includeColor(includeColor),
|
includeColor(includeColor),
|
||||||
includeExistsBits(includeExistsBits),
|
includeExistsBits(includeExistsBits),
|
||||||
destinationNode(destinationNode),
|
destinationNode(destinationNode),
|
||||||
sourceID(sourceID),
|
sourceUUID(sourceUUID),
|
||||||
wantImportProgress(wantImportProgress)
|
wantImportProgress(wantImportProgress)
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -214,7 +214,7 @@ private:
|
||||||
|
|
||||||
static bool countVoxelsOperation(VoxelNode* node, void* extraData);
|
static bool countVoxelsOperation(VoxelNode* node, void* extraData);
|
||||||
|
|
||||||
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
|
VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, const unsigned char* needleCode, VoxelNode** parentOfFoundNode) const;
|
||||||
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
|
VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate);
|
||||||
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, ReadBitstreamToTreeParams& args);
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ private:
|
||||||
|
|
||||||
/// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and
|
/// Octal Codes of any subtrees currently being encoded. While any of these codes is being encoded, ancestors and
|
||||||
/// descendants of them can not be deleted.
|
/// descendants of them can not be deleted.
|
||||||
std::set<unsigned char*> _codesBeingEncoded;
|
std::set<const unsigned char*> _codesBeingEncoded;
|
||||||
/// mutex lock to protect the encoding set
|
/// mutex lock to protect the encoding set
|
||||||
pthread_mutex_t _encodeSetLock;
|
pthread_mutex_t _encodeSetLock;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//
|
//
|
||||||
// main.cpp
|
// main.cpp
|
||||||
// Voxel Edit
|
// Voxel Edit
|
||||||
//
|
//
|
||||||
|
@ -233,7 +233,7 @@ void processFillSVOFile(const char* fillSVOFile) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, const char * argv[])
|
int old_main(int argc, const char * argv[])
|
||||||
{
|
{
|
||||||
qInstallMessageHandler(sharedMessageHandler);
|
qInstallMessageHandler(sharedMessageHandler);
|
||||||
|
|
||||||
|
@ -294,4 +294,76 @@ int main(int argc, const char * argv[])
|
||||||
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unitTest(VoxelTree * tree) {
|
||||||
|
printf("unit tests...\n");
|
||||||
|
|
||||||
|
// We want our corner voxels to be about 1/2 meter high, and our TREE_SCALE is in meters, so...
|
||||||
|
float voxelSize = 0.5f;
|
||||||
|
|
||||||
|
// Here's an example of how to create a voxel.
|
||||||
|
printf("creating corner points...\n");
|
||||||
|
tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
|
||||||
|
|
||||||
|
// Here's an example of how to test if a voxel exists
|
||||||
|
VoxelNode* node = tree->getVoxelAt(0, 0, 0, voxelSize);
|
||||||
|
if (node) {
|
||||||
|
// and how to access it's color
|
||||||
|
printf("corner point 0,0,0 exists... color is (%d,%d,%d) \n",
|
||||||
|
node->getColor()[0], node->getColor()[1], node->getColor()[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// here's an example of how to delete a voxel
|
||||||
|
printf("attempting to delete corner point 0,0,0\n");
|
||||||
|
tree->deleteVoxelAt(0, 0, 0, voxelSize);
|
||||||
|
|
||||||
|
// Test to see that the delete worked... it should be FALSE...
|
||||||
|
if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
|
||||||
|
printf("corner point 0,0,0 exists...\n");
|
||||||
|
} else {
|
||||||
|
printf("corner point 0,0,0 does not exists...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->createVoxel(0, 0, 0, voxelSize, 255, 255 ,255);
|
||||||
|
if (tree->getVoxelAt(0, 0, 0, voxelSize)) {
|
||||||
|
printf("corner point 0,0,0 exists...\n");
|
||||||
|
} else {
|
||||||
|
printf("corner point 0,0,0 does not exists...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->createVoxel(voxelSize, 0, 0, voxelSize, 255, 255 ,255);
|
||||||
|
if (tree->getVoxelAt(voxelSize, 0, 0, voxelSize)) {
|
||||||
|
printf("corner point voxelSize,0,0 exists...\n");
|
||||||
|
} else {
|
||||||
|
printf("corner point voxelSize,0,0 does not exists...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->createVoxel(0, 0, voxelSize, voxelSize, 255, 255 ,255);
|
||||||
|
if (tree->getVoxelAt(0, 0, voxelSize, voxelSize)) {
|
||||||
|
printf("corner point 0, 0, voxelSize exists...\n");
|
||||||
|
} else {
|
||||||
|
printf("corner point 0, 0, voxelSize does not exists...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree->createVoxel(voxelSize, 0, voxelSize, voxelSize, 255, 255 ,255);
|
||||||
|
if (tree->getVoxelAt(voxelSize, 0, voxelSize, voxelSize)) {
|
||||||
|
printf("corner point voxelSize, 0, voxelSize exists...\n");
|
||||||
|
} else {
|
||||||
|
printf("corner point voxelSize, 0, voxelSize does not exists...\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("check root voxel exists...\n");
|
||||||
|
if (tree->getVoxelAt(0,0,0,1.0)) {
|
||||||
|
printf("of course it does\n");
|
||||||
|
} else {
|
||||||
|
printf("WTH!?!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, const char * argv[]) {
|
||||||
|
unitTest(&myTree);
|
||||||
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue