mirror of
https://github.com/lubosz/overte.git
synced 2025-04-24 02:53:43 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into 19507
This commit is contained in:
commit
51db3dc3e1
15 changed files with 199 additions and 128 deletions
|
@ -63,4 +63,5 @@ To test things out you'll want to run the Interface client.
|
|||
|
||||
To access your local domain in Interface, open your Preferences -- on OS X this is available in the Interface menu, on Linux you'll find it in the File menu. Enter "localhost" in the "Domain server" field.
|
||||
|
||||
If everything worked you should see that you are connected to at least one server. Nice work!
|
||||
If everything worked you should see that you are connected to at least one server.
|
||||
Nice work!
|
||||
|
|
|
@ -189,4 +189,9 @@ void Agent::run() {
|
|||
|
||||
_scriptEngine.setScriptContents(scriptContents);
|
||||
_scriptEngine.run();
|
||||
setFinished(true);
|
||||
}
|
||||
|
||||
void Agent::aboutToFinish() {
|
||||
_scriptEngine.stop();
|
||||
}
|
||||
|
|
|
@ -41,6 +41,8 @@ public:
|
|||
bool isListeningToAudioStream() const { return _scriptEngine.isListeningToAudioStream(); }
|
||||
void setIsListeningToAudioStream(bool isListeningToAudioStream)
|
||||
{ _scriptEngine.setIsListeningToAudioStream(isListeningToAudioStream); }
|
||||
|
||||
virtual void aboutToFinish();
|
||||
|
||||
public slots:
|
||||
void run();
|
||||
|
|
|
@ -66,7 +66,8 @@ void attachNewBufferToNode(Node *newNode) {
|
|||
AudioMixer::AudioMixer(const QByteArray& packet) :
|
||||
ThreadedAssignment(packet),
|
||||
_trailingSleepRatio(1.0f),
|
||||
_minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f)
|
||||
_minAudibilityThreshold(LOUDNESS_TO_DISTANCE_RATIO / 2.0f),
|
||||
_numClientsMixedInFrame(0)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -80,15 +81,22 @@ void AudioMixer::addBufferToMixForListeningNodeWithBuffer(PositionalAudioRingBuf
|
|||
|
||||
if (bufferToAdd != listeningNodeBuffer) {
|
||||
// if the two buffer pointers do not match then these are different buffers
|
||||
|
||||
glm::vec3 relativePosition = bufferToAdd->getPosition() - listeningNodeBuffer->getPosition();
|
||||
|
||||
if (bufferToAdd->getAverageLoudness() / glm::length(relativePosition) <= _minAudibilityThreshold) {
|
||||
float distanceBetween = glm::length(relativePosition);
|
||||
|
||||
if (distanceBetween < EPSILON) {
|
||||
distanceBetween = EPSILON;
|
||||
}
|
||||
|
||||
if (bufferToAdd->getAverageLoudness() / distanceBetween <= _minAudibilityThreshold) {
|
||||
// according to mixer performance we have decided this does not get to be mixed in
|
||||
// bail out
|
||||
return;
|
||||
}
|
||||
|
||||
++_numClientsMixedInFrame;
|
||||
|
||||
glm::quat inverseOrientation = glm::inverse(listeningNodeBuffer->getOrientation());
|
||||
|
||||
float distanceSquareToSource = glm::dot(relativePosition, relativePosition);
|
||||
|
@ -364,6 +372,9 @@ void AudioMixer::run() {
|
|||
|
||||
int usecToSleep = BUFFER_SEND_INTERVAL_USECS;
|
||||
float audabilityCutoffRatio = 0;
|
||||
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
int framesSinceCutoffEvent = TRAILING_AVERAGE_FRAMES;
|
||||
|
||||
while (!_isFinished) {
|
||||
|
||||
|
@ -374,10 +385,9 @@ void AudioMixer::run() {
|
|||
}
|
||||
|
||||
const float STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.10f;
|
||||
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.30f;
|
||||
const float CUTOFF_EPSILON = 0.0001f;
|
||||
const float BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD = 0.20f;
|
||||
const float CUTOFF_DELTA = 0.02f;
|
||||
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
|
||||
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
|
||||
|
||||
|
@ -391,30 +401,40 @@ void AudioMixer::run() {
|
|||
float lastCutoffRatio = audabilityCutoffRatio;
|
||||
bool hasRatioChanged = false;
|
||||
|
||||
if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) {
|
||||
// we're struggling - change our min required loudness to reduce some load
|
||||
audabilityCutoffRatio += (1.0f - audabilityCutoffRatio) / 2.0f;
|
||||
|
||||
qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||
<< lastCutoffRatio << "and is now" << audabilityCutoffRatio;
|
||||
hasRatioChanged = true;
|
||||
} else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) {
|
||||
// we've recovered and can back off the required loudness
|
||||
audabilityCutoffRatio -= audabilityCutoffRatio / 2.0f;
|
||||
|
||||
if (audabilityCutoffRatio < CUTOFF_EPSILON) {
|
||||
audabilityCutoffRatio = 0.0f;
|
||||
if (framesSinceCutoffEvent >= TRAILING_AVERAGE_FRAMES) {
|
||||
if (_trailingSleepRatio <= STRUGGLE_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD) {
|
||||
// we're struggling - change our min required loudness to reduce some load
|
||||
audabilityCutoffRatio += CUTOFF_DELTA;
|
||||
|
||||
if (audabilityCutoffRatio >= 1) {
|
||||
audabilityCutoffRatio = 1 - CUTOFF_DELTA;
|
||||
}
|
||||
|
||||
qDebug() << "Mixer is struggling, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||
<< lastCutoffRatio << "and is now" << audabilityCutoffRatio;
|
||||
hasRatioChanged = true;
|
||||
} else if (_trailingSleepRatio >= BACK_OFF_TRIGGER_SLEEP_PERCENTAGE_THRESHOLD && audabilityCutoffRatio != 0) {
|
||||
// we've recovered and can back off the required loudness
|
||||
audabilityCutoffRatio -= CUTOFF_DELTA;
|
||||
|
||||
if (audabilityCutoffRatio < 0) {
|
||||
audabilityCutoffRatio = 0;
|
||||
}
|
||||
|
||||
qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||
<< lastCutoffRatio << "and is now" << audabilityCutoffRatio;
|
||||
hasRatioChanged = true;
|
||||
}
|
||||
|
||||
qDebug() << "Mixer is recovering, sleeping" << _trailingSleepRatio * 100 << "% of frame time. Old cutoff was"
|
||||
<< lastCutoffRatio << "and is now" << audabilityCutoffRatio;
|
||||
hasRatioChanged = true;
|
||||
}
|
||||
|
||||
if (hasRatioChanged) {
|
||||
// set out min required loudness from the new ratio
|
||||
_minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio));
|
||||
qDebug() << "Minimum loudness required to be mixed is now" << _minAudibilityThreshold;
|
||||
if (hasRatioChanged) {
|
||||
// set out min audability threshold from the new ratio
|
||||
_minAudibilityThreshold = LOUDNESS_TO_DISTANCE_RATIO / (2.0f * (1.0f - audabilityCutoffRatio));
|
||||
qDebug() << "Minimum audability required to be mixed is now" << _minAudibilityThreshold;
|
||||
|
||||
framesSinceCutoffEvent = 0;
|
||||
}
|
||||
} else {
|
||||
framesSinceCutoffEvent++;
|
||||
}
|
||||
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
@ -428,6 +448,8 @@ void AudioMixer::run() {
|
|||
nodeList->writeDatagram(clientMixBuffer, NETWORK_BUFFER_LENGTH_BYTES_STEREO + numBytesPacketHeader, node);
|
||||
}
|
||||
}
|
||||
|
||||
_numClientsMixedInFrame = 0;
|
||||
|
||||
// push forward the next output pointers for any audio buffers we used
|
||||
foreach (const SharedNodePointer& node, nodeList->getNodeHash()) {
|
||||
|
@ -446,10 +468,7 @@ void AudioMixer::run() {
|
|||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
} else {
|
||||
qDebug() << "AudioMixer loop took" << -usecToSleep << "of extra time. Not sleeping.";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
delete[] clientMixBuffer;
|
||||
|
|
|
@ -42,6 +42,7 @@ private:
|
|||
|
||||
float _trailingSleepRatio;
|
||||
float _minAudibilityThreshold;
|
||||
int _numClientsMixedInFrame;
|
||||
};
|
||||
|
||||
#endif /* defined(__hifi__AudioMixer__) */
|
||||
|
|
|
@ -67,6 +67,14 @@ OctreeQueryNode::~OctreeQueryNode() {
|
|||
}
|
||||
|
||||
|
||||
void OctreeQueryNode::deleteLater() {
|
||||
_isShuttingDown = true;
|
||||
if (_octreeSendThread) {
|
||||
_octreeSendThread->setIsShuttingDown();
|
||||
}
|
||||
OctreeQuery::deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* octreeServer, const QUuid& nodeUUID) {
|
||||
// Create octree sending thread...
|
||||
|
|
|
@ -27,6 +27,7 @@ class OctreeQueryNode : public OctreeQuery {
|
|||
public:
|
||||
OctreeQueryNode();
|
||||
virtual ~OctreeQueryNode();
|
||||
virtual void deleteLater();
|
||||
|
||||
void init(); // called after creation to set up some virtual items
|
||||
virtual PacketType getMyPacketType() const = 0;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||
//
|
||||
|
||||
#include <QMutexLocker>
|
||||
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PerfStat.h>
|
||||
|
@ -21,7 +23,9 @@ OctreeSendThread::OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer
|
|||
_nodeUUID(nodeUUID),
|
||||
_myServer(myServer),
|
||||
_packetData(),
|
||||
_nodeMissingCount(0)
|
||||
_nodeMissingCount(0),
|
||||
_processLock(),
|
||||
_isShuttingDown(false)
|
||||
{
|
||||
QString safeServerName("Octree");
|
||||
if (_myServer) {
|
||||
|
@ -43,8 +47,19 @@ OctreeSendThread::~OctreeSendThread() {
|
|||
OctreeServer::clientDisconnected();
|
||||
}
|
||||
|
||||
void OctreeSendThread::setIsShuttingDown() {
|
||||
QMutexLocker locker(&_processLock); // this will cause us to wait till the process loop is complete
|
||||
_isShuttingDown = true;
|
||||
}
|
||||
|
||||
|
||||
bool OctreeSendThread::process() {
|
||||
QMutexLocker locker(&_processLock);
|
||||
|
||||
if (_isShuttingDown) {
|
||||
return false; // exit early if we're shutting down
|
||||
}
|
||||
|
||||
const int MAX_NODE_MISSING_CHECKS = 10;
|
||||
if (_nodeMissingCount > MAX_NODE_MISSING_CHECKS) {
|
||||
qDebug() << "our target node:" << _nodeUUID << "has been missing the last" << _nodeMissingCount
|
||||
|
@ -56,7 +71,10 @@ bool OctreeSendThread::process() {
|
|||
|
||||
// don't do any send processing until the initial load of the octree is complete...
|
||||
if (_myServer->isInitialLoadComplete()) {
|
||||
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
||||
|
||||
// see if we can get access to our node, but don't wait on the lock, if the nodeList is busy
|
||||
// it might not return a node that is known, but that's ok we can handle that case.
|
||||
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID, false);
|
||||
|
||||
if (node) {
|
||||
_nodeMissingCount = 0;
|
||||
|
@ -113,19 +131,6 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
|
|||
bool packetSent = false; // did we send a packet?
|
||||
int packetsSent = 0;
|
||||
|
||||
// double check that the node has an active socket, otherwise, don't send...
|
||||
|
||||
quint64 lockWaitStart = usecTimestampNow();
|
||||
QMutexLocker locker(&node->getMutex());
|
||||
quint64 lockWaitEnd = usecTimestampNow();
|
||||
float lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
|
||||
OctreeServer::trackNodeWaitTime(lockWaitElapsedUsec);
|
||||
|
||||
const HifiSockAddr* nodeAddress = node->getActiveSocket();
|
||||
if (!nodeAddress) {
|
||||
return packetsSent; // without sending...
|
||||
}
|
||||
|
||||
// Here's where we check to see if this packet is a duplicate of the last packet. If it is, we will silently
|
||||
// obscure the packet and not send it. This allows the callers and upper level logic to not need to know about
|
||||
// this rate control savings.
|
||||
|
|
|
@ -23,6 +23,8 @@ class OctreeSendThread : public GenericThread {
|
|||
public:
|
||||
OctreeSendThread(const QUuid& nodeUUID, OctreeServer* myServer);
|
||||
virtual ~OctreeSendThread();
|
||||
|
||||
void setIsShuttingDown();
|
||||
|
||||
static quint64 _totalBytes;
|
||||
static quint64 _totalWastedBytes;
|
||||
|
@ -45,6 +47,8 @@ private:
|
|||
OctreePacketData _packetData;
|
||||
|
||||
int _nodeMissingCount;
|
||||
QMutex _processLock; // don't allow us to have our nodeData, or our thread to be deleted while we're processing
|
||||
bool _isShuttingDown;
|
||||
};
|
||||
|
||||
#endif // __octree_server__OctreeSendThread__
|
||||
|
|
|
@ -32,8 +32,6 @@ var MIN_PASTE_VOXEL_SCALE = .256;
|
|||
var zFightingSizeAdjust = 0.002; // used to adjust preview voxels to prevent z fighting
|
||||
var previewLineWidth = 1.5;
|
||||
|
||||
var oldMode = Camera.getMode();
|
||||
var trackAsOrbitOrPan = false;
|
||||
var isAdding = false;
|
||||
var isExtruding = false;
|
||||
var extrudeDirection = { x: 0, y: 0, z: 0 };
|
||||
|
@ -614,8 +612,6 @@ function showPreviewVoxel() {
|
|||
var guidePosition;
|
||||
if (trackAsRecolor || recolorToolSelected || trackAsEyedropper || eyedropperToolSelected) {
|
||||
Overlays.editOverlay(voxelPreview, { visible: true });
|
||||
} else if (trackAsOrbitOrPan) {
|
||||
Overlays.editOverlay(voxelPreview, { visible: false });
|
||||
} else if (voxelToolSelected && !isExtruding) {
|
||||
Overlays.editOverlay(voxelPreview, { visible: true });
|
||||
} else if (isExtruding) {
|
||||
|
@ -706,15 +702,12 @@ function showPreviewGuides() {
|
|||
}
|
||||
|
||||
function trackMouseEvent(event) {
|
||||
if (!trackAsOrbitOrPan) {
|
||||
trackLastMouseX = event.x;
|
||||
trackLastMouseY = event.y;
|
||||
trackAsDelete = event.isControl;
|
||||
trackAsRecolor = event.isShifted;
|
||||
trackAsEyedropper = event.isMeta;
|
||||
trackAsOrbitOrPan = event.isAlt; // TODO: double check this...??
|
||||
showPreviewGuides();
|
||||
}
|
||||
trackLastMouseX = event.x;
|
||||
trackLastMouseY = event.y;
|
||||
trackAsDelete = event.isControl;
|
||||
trackAsRecolor = event.isShifted;
|
||||
trackAsEyedropper = event.isMeta;
|
||||
showPreviewGuides();
|
||||
}
|
||||
|
||||
function trackKeyPressEvent(event) {
|
||||
|
@ -742,6 +735,7 @@ function trackKeyReleaseEvent(event) {
|
|||
if (event.text == "TAB") {
|
||||
editToolsOn = !editToolsOn;
|
||||
moveTools();
|
||||
showPreviewGuides();
|
||||
Audio.playSound(clickSound, audioOptions);
|
||||
}
|
||||
|
||||
|
@ -788,67 +782,64 @@ function mousePressEvent(event) {
|
|||
return;
|
||||
}
|
||||
|
||||
// no clicking on overlays while in panning mode
|
||||
if (!trackAsOrbitOrPan) {
|
||||
var clickedOnSomething = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
|
||||
// If the user clicked on the thumb, handle the slider logic
|
||||
if (clickedOverlay == thumb) {
|
||||
isMovingSlider = true;
|
||||
thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb
|
||||
clickedOnSomething = true;
|
||||
|
||||
Overlays.editOverlay(thumb, { imageURL: toolIconUrl + "voxel-size-slider-handle.svg", });
|
||||
|
||||
} else if (clickedOverlay == voxelTool) {
|
||||
voxelToolSelected = true;
|
||||
recolorToolSelected = false;
|
||||
eyedropperToolSelected = false;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == recolorTool) {
|
||||
voxelToolSelected = false;
|
||||
recolorToolSelected = true;
|
||||
eyedropperToolSelected = false;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == eyedropperTool) {
|
||||
voxelToolSelected = false;
|
||||
recolorToolSelected = false;
|
||||
eyedropperToolSelected = true;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == slider) {
|
||||
|
||||
if (event.x < sliderX + minThumbX) {
|
||||
thumbX -= thumbDeltaPerStep;
|
||||
calcScaleFromThumb(thumbX);
|
||||
}
|
||||
|
||||
if (event.x > sliderX + maxThumbX) {
|
||||
thumbX += thumbDeltaPerStep;
|
||||
calcScaleFromThumb(thumbX);
|
||||
}
|
||||
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else {
|
||||
// if the user clicked on one of the color swatches, update the selectedSwatch
|
||||
for (s = 0; s < numColors; s++) {
|
||||
if (clickedOverlay == swatches[s]) {
|
||||
whichColor = s;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
var clickedOnSomething = false;
|
||||
var clickedOverlay = Overlays.getOverlayAtPoint({x: event.x, y: event.y});
|
||||
|
||||
// If the user clicked on the thumb, handle the slider logic
|
||||
if (clickedOverlay == thumb) {
|
||||
isMovingSlider = true;
|
||||
thumbClickOffsetX = event.x - (sliderX + thumbX); // this should be the position of the mouse relative to the thumb
|
||||
clickedOnSomething = true;
|
||||
|
||||
Overlays.editOverlay(thumb, { imageURL: toolIconUrl + "voxel-size-slider-handle.svg", });
|
||||
|
||||
} else if (clickedOverlay == voxelTool) {
|
||||
voxelToolSelected = true;
|
||||
recolorToolSelected = false;
|
||||
eyedropperToolSelected = false;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == recolorTool) {
|
||||
voxelToolSelected = false;
|
||||
recolorToolSelected = true;
|
||||
eyedropperToolSelected = false;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == eyedropperTool) {
|
||||
voxelToolSelected = false;
|
||||
recolorToolSelected = false;
|
||||
eyedropperToolSelected = true;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else if (clickedOverlay == slider) {
|
||||
|
||||
if (event.x < sliderX + minThumbX) {
|
||||
thumbX -= thumbDeltaPerStep;
|
||||
calcScaleFromThumb(thumbX);
|
||||
}
|
||||
if (clickedOnSomething) {
|
||||
return; // no further processing
|
||||
|
||||
if (event.x > sliderX + maxThumbX) {
|
||||
thumbX += thumbDeltaPerStep;
|
||||
calcScaleFromThumb(thumbX);
|
||||
}
|
||||
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
} else {
|
||||
// if the user clicked on one of the color swatches, update the selectedSwatch
|
||||
for (s = 0; s < numColors; s++) {
|
||||
if (clickedOverlay == swatches[s]) {
|
||||
whichColor = s;
|
||||
moveTools();
|
||||
clickedOnSomething = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (clickedOnSomething) {
|
||||
return; // no further processing
|
||||
}
|
||||
|
||||
// TODO: does any of this stuff need to execute if we're panning or orbiting?
|
||||
trackMouseEvent(event); // used by preview support
|
||||
mouseX = event.x;
|
||||
|
@ -1071,7 +1062,7 @@ function mouseMoveEvent(event) {
|
|||
}
|
||||
|
||||
|
||||
if (!trackAsOrbitOrPan && isMovingSlider) {
|
||||
if (isMovingSlider) {
|
||||
thumbX = (event.x - thumbClickOffsetX) - sliderX;
|
||||
if (thumbX < minThumbX) {
|
||||
thumbX = minThumbX;
|
||||
|
@ -1081,7 +1072,7 @@ function mouseMoveEvent(event) {
|
|||
}
|
||||
calcScaleFromThumb(thumbX);
|
||||
|
||||
} else if (!trackAsOrbitOrPan && isAdding) {
|
||||
} else if (isAdding) {
|
||||
// Watch the drag direction to tell which way to 'extrude' this voxel
|
||||
if (!isExtruding) {
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
// Dragging the mouse will move your camera according to the mode you are in.
|
||||
//
|
||||
|
||||
var PI = 3.14 // No need for something more precise
|
||||
|
||||
var AZIMUTH_RATE = 90.0;
|
||||
var ALTITUDE_RATE = 200.0;
|
||||
var RADIUS_RATE = 20.0;
|
||||
var RADIUS_RATE = 1.0 / 100.0;
|
||||
var PAN_RATE = 50.0;
|
||||
|
||||
var alt = false;
|
||||
|
@ -46,7 +48,7 @@ var altitude = 0.0;
|
|||
|
||||
function handleRadialMode(dx, dy) {
|
||||
azimuth += dx / AZIMUTH_RATE;
|
||||
radius += radius * dy / RADIUS_RATE;
|
||||
radius += radius * dy * RADIUS_RATE;
|
||||
if (radius < 1) {
|
||||
radius = 1;
|
||||
}
|
||||
|
@ -61,6 +63,12 @@ function handleRadialMode(dx, dy) {
|
|||
function handleOrbitMode(dx, dy) {
|
||||
azimuth += dx / AZIMUTH_RATE;
|
||||
altitude += dy / ALTITUDE_RATE;
|
||||
if (altitude > PI / 2.0) {
|
||||
altitude = PI / 2.0;
|
||||
}
|
||||
if (altitude < -PI / 2.0) {
|
||||
altitude = -PI / 2.0;
|
||||
}
|
||||
|
||||
vector = { x:(Math.cos(altitude) * Math.cos(azimuth)) * radius,
|
||||
y:Math.sin(altitude) * radius,
|
||||
|
@ -165,7 +173,7 @@ function keyReleaseEvent(event) {
|
|||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
if (alt) {
|
||||
if (alt && !isActive) {
|
||||
isActive = true;
|
||||
mouseLastX = event.x;
|
||||
mouseLastY = event.y;
|
||||
|
|
|
@ -3252,6 +3252,9 @@ void Application::domainChanged(const QString& domainHostname) {
|
|||
|
||||
// reset the particle renderer
|
||||
_particles.clear();
|
||||
|
||||
// reset the voxels renderer
|
||||
_voxels.killLocalVoxels();
|
||||
}
|
||||
|
||||
void Application::connectedToDomain(const QString& hostname) {
|
||||
|
|
|
@ -67,7 +67,20 @@ void AudioRingBuffer::updateAverageLoudnessForBoundarySamples(int numSamples) {
|
|||
nextLoudness /= numSamples;
|
||||
nextLoudness /= MAX_SAMPLE_VALUE;
|
||||
|
||||
_averageLoudness = nextLoudness;
|
||||
const int TRAILING_AVERAGE_FRAMES = 100;
|
||||
const float CURRENT_FRAME_RATIO = 1.0f / TRAILING_AVERAGE_FRAMES;
|
||||
const float PREVIOUS_FRAMES_RATIO = 1.0f - CURRENT_FRAME_RATIO;
|
||||
const float LOUDNESS_EPSILON = 0.01f;
|
||||
|
||||
if (nextLoudness >= _averageLoudness) {
|
||||
_averageLoudness = nextLoudness;
|
||||
} else {
|
||||
_averageLoudness = (_averageLoudness * PREVIOUS_FRAMES_RATIO) + (CURRENT_FRAME_RATIO * nextLoudness);
|
||||
|
||||
if (_averageLoudness < LOUDNESS_EPSILON) {
|
||||
_averageLoudness = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qint64 AudioRingBuffer::readSamples(int16_t* destination, qint64 maxSamples) {
|
||||
|
|
|
@ -308,9 +308,18 @@ int NodeList::findNodeAndUpdateWithDataFromPacket(const QByteArray& packet) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID) {
|
||||
QMutexLocker locker(&_nodeHashMutex);
|
||||
return _nodeHash.value(nodeUUID);
|
||||
SharedNodePointer NodeList::nodeWithUUID(const QUuid& nodeUUID, bool blockingLock) {
|
||||
SharedNodePointer node;
|
||||
// if caller wants us to block and guarantee the correct answer, then honor that request
|
||||
if (blockingLock) {
|
||||
// this will block till we can get access
|
||||
QMutexLocker locker(&_nodeHashMutex);
|
||||
node = _nodeHash.value(nodeUUID);
|
||||
} else if (_nodeHashMutex.tryLock()) { // some callers are willing to get wrong answers but not block
|
||||
node = _nodeHash.value(nodeUUID);
|
||||
_nodeHashMutex.unlock();
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
SharedNodePointer NodeList::sendingNodeForPacket(const QByteArray& packet) {
|
||||
|
|
|
@ -101,7 +101,8 @@ public:
|
|||
QByteArray constructPingReplyPacket(const QByteArray& pingPacket);
|
||||
void pingPublicAndLocalSocketsForInactiveNode(const SharedNodePointer& node);
|
||||
|
||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID);
|
||||
/// passing false for blockingLock, will tryLock, and may return NULL when a node with the UUID actually does exist
|
||||
SharedNodePointer nodeWithUUID(const QUuid& nodeUUID, bool blockingLock = true);
|
||||
SharedNodePointer sendingNodeForPacket(const QByteArray& packet);
|
||||
|
||||
SharedNodePointer addOrUpdateNode(const QUuid& uuid, char nodeType,
|
||||
|
|
Loading…
Reference in a new issue