Merge branch 'master' of https://github.com/highfidelity/hifi into removed_gettimeofday

This commit is contained in:
Atlante45 2014-04-23 10:38:29 -07:00
commit ae566c55f6
31 changed files with 610 additions and 190 deletions

View file

@ -22,6 +22,7 @@
#include <PacketHeaders.h>
#include <SharedUtil.h>
#include "AssignmentFactory.h"
#include "AssignmentThread.h"
@ -30,11 +31,12 @@
const QString ASSIGNMENT_CLIENT_TARGET_NAME = "assignment-client";
const long long ASSIGNMENT_REQUEST_INTERVAL_MSECS = 1 * 1000;
SharedAssignmentPointer AssignmentClient::_currentAssignment;
int hifiSockAddrMeta = qRegisterMetaType<HifiSockAddr>("HifiSockAddr");
AssignmentClient::AssignmentClient(int &argc, char **argv) :
QCoreApplication(argc, argv),
_currentAssignment(),
_assignmentServerHostname(DEFAULT_ASSIGNMENT_SERVER_HOSTNAME)
{
DTLSClientSession::globalInit();

View file

@ -20,15 +20,17 @@ class AssignmentClient : public QCoreApplication {
Q_OBJECT
public:
AssignmentClient(int &argc, char **argv);
static const SharedAssignmentPointer& getCurrentAssignment() { return _currentAssignment; }
~AssignmentClient();
private slots:
void sendAssignmentRequest();
void readPendingDatagrams();
void assignmentCompleted();
void handleAuthenticationRequest();
private:
Assignment _requestAssignment;
SharedAssignmentPointer _currentAssignment;
static SharedAssignmentPointer _currentAssignment;
QString _assignmentServerHostname;
};

View file

@ -47,41 +47,54 @@ OctreeQueryNode::OctreeQueryNode() :
OctreeQueryNode::~OctreeQueryNode() {
_isShuttingDown = true;
const bool extraDebugging = false;
if (extraDebugging) {
qDebug() << "OctreeQueryNode::~OctreeQueryNode()";
}
if (_octreeSendThread) {
if (extraDebugging) {
qDebug() << "OctreeQueryNode::~OctreeQueryNode()... calling _octreeSendThread->terminate()";
}
_octreeSendThread->terminate();
if (extraDebugging) {
qDebug() << "OctreeQueryNode::~OctreeQueryNode()... calling delete _octreeSendThread";
}
delete _octreeSendThread;
forceNodeShutdown();
}
delete[] _octreePacket;
delete[] _lastOctreePacket;
if (extraDebugging) {
qDebug() << "OctreeQueryNode::~OctreeQueryNode()... DONE...";
}
}
void OctreeQueryNode::deleteLater() {
void OctreeQueryNode::nodeKilled() {
_isShuttingDown = true;
nodeBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications
if (_octreeSendThread) {
// just tell our thread we want to shutdown, this is asynchronous, and fast, we don't need or want it to block
// while the thread actually shuts down
_octreeSendThread->setIsShuttingDown();
}
OctreeQuery::deleteLater();
}
void OctreeQueryNode::forceNodeShutdown() {
_isShuttingDown = true;
nodeBag.unhookNotifications(); // if our node is shutting down, then we no longer need octree element notifications
if (_octreeSendThread) {
// we really need to force our thread to shutdown, this is synchronous, we will block while the thread actually
// shuts down because we really need it to shutdown, and it's ok if we wait for it to complete
OctreeSendThread* sendThread = _octreeSendThread;
_octreeSendThread = NULL;
sendThread->setIsShuttingDown();
sendThread->terminate();
delete sendThread;
}
}
void OctreeQueryNode::initializeOctreeSendThread(OctreeServer* octreeServer, SharedNodePointer node) {
// Create octree sending thread...
_octreeSendThread = new OctreeSendThread(octreeServer, node);
void OctreeQueryNode::sendThreadFinished() {
// We've been notified by our thread that it is shutting down. So we can clean up our reference to it, and
// delete the actual thread object. Cleaning up our thread will correctly unroll all refereces to shared
// pointers to our node as well as the octree server assignment
if (_octreeSendThread) {
OctreeSendThread* sendThread = _octreeSendThread;
_octreeSendThread = NULL;
delete sendThread;
}
}
void OctreeQueryNode::initializeOctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node) {
_octreeSendThread = new OctreeSendThread(myAssignment, node);
// we want to be notified when the thread finishes
connect(_octreeSendThread, &GenericThread::finished, this, &OctreeQueryNode::sendThreadFinished);
_octreeSendThread->initialize(true);
}

View file

@ -13,25 +13,25 @@
#define hifi_OctreeQueryNode_h
#include <iostream>
#include <NodeData.h>
#include <OctreePacketData.h>
#include <OctreeQuery.h>
#include <CoverageMap.h>
#include <NodeData.h>
#include <OctreeConstants.h>
#include <OctreeElementBag.h>
#include <OctreePacketData.h>
#include <OctreeQuery.h>
#include <OctreeSceneStats.h>
#include <ThreadedAssignment.h> // for SharedAssignmentPointer
class OctreeSendThread;
class OctreeServer;
class OctreeQueryNode : public OctreeQuery {
Q_OBJECT
public:
OctreeQueryNode();
virtual ~OctreeQueryNode();
virtual void deleteLater();
void init(); // called after creation to set up some virtual items
virtual PacketType getMyPacketType() const = 0;
@ -86,7 +86,7 @@ public:
OctreeSceneStats stats;
void initializeOctreeSendThread(OctreeServer* octreeServer, SharedNodePointer node);
void initializeOctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node);
bool isOctreeSendThreadInitalized() { return _octreeSendThread; }
void dumpOutOfView();
@ -96,8 +96,13 @@ public:
unsigned int getlastOctreePacketLength() const { return _lastOctreePacketLength; }
int getDuplicatePacketCount() const { return _duplicatePacketCount; }
void nodeKilled();
void forceNodeShutdown();
bool isShuttingDown() const { return _isShuttingDown; }
private slots:
void sendThreadFinished();
private:
OctreeQueryNode(const OctreeQueryNode &);
OctreeQueryNode& operator= (const OctreeQueryNode&);

View file

@ -23,12 +23,13 @@
quint64 startSceneSleepTime = 0;
quint64 endSceneSleepTime = 0;
OctreeSendThread::OctreeSendThread(OctreeServer* myServer, SharedNodePointer node) :
_myServer(myServer),
OctreeSendThread::OctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node) :
_myAssignment(myAssignment),
_myServer(static_cast<OctreeServer*>(myAssignment.data())),
_node(node),
_nodeUUID(node->getUUID()),
_packetData(),
_nodeMissingCount(0),
_processLock(),
_isShuttingDown(false)
{
QString safeServerName("Octree");
@ -41,22 +42,24 @@ OctreeSendThread::OctreeSendThread(OctreeServer* myServer, SharedNodePointer nod
OctreeServer::clientConnected();
}
OctreeSendThread::~OctreeSendThread() {
OctreeSendThread::~OctreeSendThread() {
QString safeServerName("Octree");
if (_myServer) {
safeServerName = _myServer->getMyServerName();
}
qDebug() << qPrintable(safeServerName) << "server [" << _myServer << "]: client disconnected "
"- ending sending thread [" << this << "]";
OctreeServer::clientDisconnected();
OctreeServer::stopTrackingThread(this);
_node.clear();
_myAssignment.clear();
}
void OctreeSendThread::setIsShuttingDown() {
_isShuttingDown = true;
OctreeServer::stopTrackingThread(this);
// this will cause us to wait till the process loop is complete, we do this after we change _isShuttingDown
QMutexLocker locker(&_processLock);
}
@ -65,47 +68,29 @@ bool OctreeSendThread::process() {
return false; // exit early if we're shutting down
}
// check that our server and assignment is still valid
if (!_myServer || !_myAssignment) {
return false; // exit early if it's not, it means the server is shutting down
}
OctreeServer::didProcess(this);
float lockWaitElapsedUsec = OctreeServer::SKIP_TIME;
quint64 lockWaitStart = usecTimestampNow();
_processLock.lock();
quint64 lockWaitEnd = usecTimestampNow();
lockWaitElapsedUsec = (float)(lockWaitEnd - lockWaitStart);
OctreeServer::trackProcessWaitTime(lockWaitElapsedUsec);
quint64 start = usecTimestampNow();
// don't do any send processing until the initial load of the octree is complete...
if (_myServer->isInitialLoadComplete()) {
SharedNodePointer node = NodeList::getInstance()->nodeWithUUID(_nodeUUID, false);
if (node) {
if (_node) {
_nodeMissingCount = 0;
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(_node->getLinkedData());
// Sometimes the node data has not yet been linked, in which case we can't really do anything
if (nodeData && !nodeData->isShuttingDown()) {
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
packetDistributor(node, nodeData, viewFrustumChanged);
}
} else {
_nodeMissingCount++;
const int MANY_FAILED_LOCKS = 1;
if (_nodeMissingCount >= MANY_FAILED_LOCKS) {
QString safeServerName("Octree");
if (_myServer) {
safeServerName = _myServer->getMyServerName();
}
qDebug() << qPrintable(safeServerName) << "server: sending thread [" << this << "]"
<< "failed to get nodeWithUUID() " << _nodeUUID <<". Failed:" << _nodeMissingCount << "times";
packetDistributor(nodeData, viewFrustumChanged);
}
}
}
_processLock.unlock();
if (_isShuttingDown) {
return false; // exit early if we're shutting down
}
@ -135,8 +120,7 @@ quint64 OctreeSendThread::_totalBytes = 0;
quint64 OctreeSendThread::_totalWastedBytes = 0;
quint64 OctreeSendThread::_totalPackets = 0;
int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) {
int OctreeSendThread::handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent) {
OctreeServer::didHandlePacketSend(this);
@ -196,12 +180,12 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
// actually send it
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, SharedNodePointer(node));
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
packetSent = true;
} else {
// not enough room in the packet, send two packets
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, SharedNodePointer(node));
NodeList::getInstance()->writeDatagram((char*) statsMessage, statsMessageLength, _node);
// since a stats message is only included on end of scene, don't consider any of these bytes "wasted", since
// there was nothing else to send.
@ -220,8 +204,7 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
packetsSent++;
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
SharedNodePointer(node));
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node);
packetSent = true;
@ -241,8 +224,7 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
if (nodeData->isPacketWaiting() && !nodeData->isShuttingDown()) {
// just send the voxel packet
OctreeServer::didCallWriteDatagram(this);
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(),
SharedNodePointer(node));
NodeList::getInstance()->writeDatagram((char*) nodeData->getPacket(), nodeData->getPacketLength(), _node);
packetSent = true;
int thisWastedBytes = MAX_PACKET_SIZE - nodeData->getPacketLength();
@ -269,7 +251,8 @@ int OctreeSendThread::handlePacketSend(const SharedNodePointer& node,
}
/// Version of voxel distributor that sends the deepest LOD level at once
int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged) {
int OctreeSendThread::packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged) {
OctreeServer::didPacketDistributor(this);
// if shutting down, exit early
@ -299,7 +282,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
// then let's just send that waiting packet.
if (!nodeData->getCurrentPacketFormatMatches()) {
if (nodeData->isPacketWaiting()) {
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent);
} else {
nodeData->resetOctreePacket();
}
@ -340,7 +323,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
//unsigned long encodeTime = nodeData->stats.getTotalEncodeTime();
//unsigned long elapsedTime = nodeData->stats.getElapsedTime();
int packetsJustSent = handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
int packetsJustSent = handlePacketSend(nodeData, trueBytesSent, truePacketsSent);
packetsSentThisInterval += packetsJustSent;
// If we're starting a full scene, then definitely we want to empty the nodeBag
@ -491,7 +474,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
if (writtenSize > nodeData->getAvailable()) {
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent);
}
nodeData->writeToPacket(_packetData.getFinalizedData(), _packetData.getFinalizedSize());
@ -513,7 +496,7 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
int targetSize = MAX_OCTREE_PACKET_DATA_SIZE;
if (sendNow) {
quint64 packetSendingStart = usecTimestampNow();
packetsSentThisInterval += handlePacketSend(node, nodeData, trueBytesSent, truePacketsSent);
packetsSentThisInterval += handlePacketSend(nodeData, trueBytesSent, truePacketsSent);
quint64 packetSendingEnd = usecTimestampNow();
packetSendingElapsedUsec = (float)(packetSendingEnd - packetSendingStart);
@ -546,8 +529,8 @@ int OctreeSendThread::packetDistributor(const SharedNodePointer& node, OctreeQue
// Here's where we can/should allow the server to send other data...
// send the environment packet
// TODO: should we turn this into a while loop to better handle sending multiple special packets
if (_myServer->hasSpecialPacketToSend(node) && !nodeData->isShuttingDown()) {
trueBytesSent += _myServer->sendSpecialPacket(node);
if (_myServer->hasSpecialPacketToSend(_node) && !nodeData->isShuttingDown()) {
trueBytesSent += _myServer->sendSpecialPacket(_node);
truePacketsSent++;
packetsSentThisInterval++;
}

View file

@ -17,15 +17,16 @@
#include <GenericThread.h>
#include <NetworkPacket.h>
#include <OctreeElementBag.h>
#include "OctreeQueryNode.h"
#include "OctreeServer.h"
#include "OctreeQueryNode.h"
class OctreeServer;
/// Threaded processor for sending voxel packets to a single client
class OctreeSendThread : public GenericThread {
Q_OBJECT
public:
OctreeSendThread(OctreeServer* myServer, SharedNodePointer node);
OctreeSendThread(const SharedAssignmentPointer& myAssignment, const SharedNodePointer& node);
virtual ~OctreeSendThread();
void setIsShuttingDown();
@ -42,16 +43,17 @@ protected:
virtual bool process();
private:
SharedAssignmentPointer _myAssignment;
OctreeServer* _myServer;
SharedNodePointer _node;
QUuid _nodeUUID;
int handlePacketSend(const SharedNodePointer& node, OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
int packetDistributor(const SharedNodePointer& node, OctreeQueryNode* nodeData, bool viewFrustumChanged);
int handlePacketSend(OctreeQueryNode* nodeData, int& trueBytesSent, int& truePacketsSent);
int packetDistributor(OctreeQueryNode* nodeData, bool viewFrustumChanged);
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;
};

View file

@ -19,6 +19,8 @@
#include <Logging.h>
#include <UUID.h>
#include "../AssignmentClient.h"
#include "OctreeServer.h"
#include "OctreeServerConsts.h"
@ -206,7 +208,7 @@ void OctreeServer::trackProcessWaitTime(float time) {
}
void OctreeServer::attachQueryNodeToNode(Node* newNode) {
if (!newNode->getLinkedData()) {
if (!newNode->getLinkedData() && _instance) {
OctreeQueryNode* newQueryNodeData = _instance->createOctreeQueryNode();
newQueryNodeData->init();
newNode->setLinkedData(newQueryNodeData);
@ -234,7 +236,13 @@ OctreeServer::OctreeServer(const QByteArray& packet) :
_started(time(0)),
_startedUSecs(usecTimestampNow())
{
if (_instance) {
qDebug() << "Octree Server starting... while old instance still running _instance=["<<_instance<<"] this=[" << this << "]";
}
qDebug() << "Octree Server starting... setting _instance to=[" << this << "]";
_instance = this;
_averageLoopTime.updateAverage(0);
qDebug() << "Octree server starting... [" << this << "]";
}
@ -265,6 +273,16 @@ OctreeServer::~OctreeServer() {
delete _jurisdiction;
_jurisdiction = NULL;
// cleanup our tree here...
qDebug() << qPrintable(_safeServerName) << "server START cleaning up octree... [" << this << "]";
delete _tree;
_tree = NULL;
qDebug() << qPrintable(_safeServerName) << "server DONE cleaning up octree... [" << this << "]";
if (_instance == this) {
_instance = NULL; // we are gone
}
qDebug() << qPrintable(_safeServerName) << "server DONE shutting down... [" << this << "]";
}
@ -812,33 +830,22 @@ void OctreeServer::readPendingDatagrams() {
while (readAvailableDatagram(receivedPacket, senderSockAddr)) {
if (nodeList->packetVersionAndHashMatch(receivedPacket)) {
PacketType packetType = packetTypeForPacket(receivedPacket);
SharedNodePointer matchingNode = nodeList->sendingNodeForPacket(receivedPacket);
if (packetType == getMyQueryMessageType()) {
bool debug = false;
if (debug) {
if (matchingNode) {
qDebug() << "Got PacketTypeVoxelQuery at" << usecTimestampNow() << "node:" << *matchingNode;
} else {
qDebug() << "Got PacketTypeVoxelQuery at" << usecTimestampNow() << "node: ??????";
}
}
// If we got a PacketType_VOXEL_QUERY, then we're talking to an NodeType_t_AVATAR, and we
// need to make sure we have it in our nodeList.
if (matchingNode) {
if (debug) {
qDebug() << "calling updateNodeWithDataFromPacket()... node:" << *matchingNode;
}
nodeList->updateNodeWithDataFromPacket(matchingNode, receivedPacket);
OctreeQueryNode* nodeData = (OctreeQueryNode*) matchingNode->getLinkedData();
if (nodeData && !nodeData->isOctreeSendThreadInitalized()) {
if (debug) {
qDebug() << "calling initializeOctreeSendThread()... node:" << *matchingNode;
}
nodeData->initializeOctreeSendThread(this, matchingNode);
// NOTE: this is an important aspect of the proper ref counting. The send threads/node data need to
// know that the OctreeServer/Assignment will not get deleted on it while it's still active. The
// solution is to get the shared pointer for the current assignment. We need to make sure this is the
// same SharedAssignmentPointer that was ref counted by the assignment client.
SharedAssignmentPointer sharedAssignment = AssignmentClient::getCurrentAssignment();
nodeData->initializeOctreeSendThread(sharedAssignment, matchingNode);
}
}
} else if (packetType == PacketTypeJurisdictionRequest) {
@ -1042,23 +1049,46 @@ void OctreeServer::nodeAdded(SharedNodePointer node) {
}
void OctreeServer::nodeKilled(SharedNodePointer node) {
quint64 start = usecTimestampNow();
qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node;
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
if (nodeData) {
qDebug() << qPrintable(_safeServerName) << "server resetting Linked Data for node:" << *node;
node->setLinkedData(NULL); // set this first in case another thread comes through and tryes to acces this
qDebug() << qPrintable(_safeServerName) << "server deleting Linked Data for node:" << *node;
nodeData->deleteLater();
nodeData->nodeKilled(); // tell our node data and sending threads that we'd like to shut down
} else {
qDebug() << qPrintable(_safeServerName) << "server node missing linked data node:" << *node;
}
quint64 end = usecTimestampNow();
quint64 usecsElapsed = (end - start);
if (usecsElapsed > 1000) {
qDebug() << qPrintable(_safeServerName) << "server nodeKilled() took: " << usecsElapsed << " usecs for node:" << *node;
}
}
void OctreeServer::forceNodeShutdown(SharedNodePointer node) {
quint64 start = usecTimestampNow();
qDebug() << qPrintable(_safeServerName) << "server killed node:" << *node;
OctreeQueryNode* nodeData = static_cast<OctreeQueryNode*>(node->getLinkedData());
if (nodeData) {
nodeData->forceNodeShutdown(); // tell our node data and sending threads that we'd like to shut down
} else {
qDebug() << qPrintable(_safeServerName) << "server node missing linked data node:" << *node;
}
quint64 end = usecTimestampNow();
quint64 usecsElapsed = (end - start);
qDebug() << qPrintable(_safeServerName) << "server forceNodeShutdown() took: "
<< usecsElapsed << " usecs for node:" << *node;
}
void OctreeServer::aboutToFinish() {
qDebug() << qPrintable(_safeServerName) << "server STARTING about to finish...";
foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) {
qDebug() << qPrintable(_safeServerName) << "server about to finish while node still connected node:" << *node;
nodeKilled(node);
forceNodeShutdown(node);
}
qDebug() << qPrintable(_safeServerName) << "server ENDING about to finish...";
}

View file

@ -117,6 +117,7 @@ public:
bool handleHTTPRequest(HTTPConnection* connection, const QUrl& url);
virtual void aboutToFinish();
void forceNodeShutdown(SharedNodePointer node);
public slots:
/// runs the voxel server assignment

View file

@ -7,6 +7,8 @@
//
// Tools for manipulating the attributes of the AudioReflector behavior
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//

View file

@ -50,7 +50,7 @@ function maybePlaySound(deltaTime) {
const CLAP_DISTANCE = 0.2;
if (!clapping[palm] && (distanceBetween < CLAP_DISTANCE) && (speed > CLAP_SPEED)) {
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
options.position = palm1Position;
options.volume = speed / 2.0;
if (options.volume > 1.0) options.volume = 1.0;

View file

@ -61,7 +61,7 @@ function checkSticks(deltaTime) {
// Waiting for change in velocity direction or slowing to trigger drum sound
if ((palmVelocity.y > 0.0) || (speed < STOP_SPEED)) {
state[palm] = 0;
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
options.position = Controller.getSpatialControlPosition(palm * 2 + 1);
if (strokeSpeed[palm] > 1.0) { strokeSpeed[palm] = 1.0; }
options.volume = strokeSpeed[palm];

View file

@ -9,12 +9,12 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
// First, load the clap sound from a URL
var clap = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw");
var clap = new Sound("https://s3-us-west-1.amazonaws.com/highfidelity-public/sounds/Animals/bushtit_1.raw");
function maybePlaySound(deltaTime) {
if (Math.random() < 0.01) {
// Set the location and other info for the sound to play
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
var palmPosition = Controller.getSpatialControlPosition(0);
options.position = palmPosition;
options.volume = 0.5;

View file

@ -217,7 +217,7 @@ function update(deltaTime) {
if (invaderStepOfCycle % stepsPerSound == 0) {
// play the move sound
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
@ -329,7 +329,7 @@ function fireMissile() {
lifetime: 5
});
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
@ -379,7 +379,7 @@ function deleteIfInvader(possibleInvaderParticle) {
Particles.deleteParticle(myMissile);
// play the hit sound
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
if (soundInMyHead) {
options.position = { x: MyAvatar.position.x + 0.0,
y: MyAvatar.position.y + 0.1,
@ -417,4 +417,3 @@ initializeInvaders();
// shut down the game after 1 minute
var gameTimer = Script.setTimeout(endGame, itemLifetimes * 1000);

View file

@ -0,0 +1,94 @@
//
// testingVoxelSeeingRestart.js
// hifi
//
// Created by Brad Hefta-Gaub on 2/26/14
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var count = 0;
var yawDirection = -1;
var yaw = 45;
var yawMax = 70;
var yawMin = 20;
var vantagePoint = {x: 5000, y: 500, z: 5000};
var isLocal = false;
// set up our VoxelViewer with a position and orientation
var orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0);
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function init() {
if (isLocal) {
MyAvatar.position = vantagePoint;
MyAvatar.orientation = orientation;
} else {
VoxelViewer.setPosition(vantagePoint);
VoxelViewer.setOrientation(orientation);
VoxelViewer.queryOctree();
Agent.isAvatar = true;
}
}
function keepLooking(deltaTime) {
//print("count =" + count);
if (count == 0) {
init();
}
count++;
if (count % getRandomInt(5, 15) == 0) {
yaw += yawDirection;
orientation = Quat.fromPitchYawRollDegrees(0, yaw, 0);
if (yaw > yawMax || yaw < yawMin) {
yawDirection = yawDirection * -1;
}
//if (count % 10000 == 0) {
// print("calling VoxelViewer.queryOctree()... count=" + count + " yaw=" + yaw);
//}
if (isLocal) {
MyAvatar.orientation = orientation;
} else {
VoxelViewer.setOrientation(orientation);
VoxelViewer.queryOctree();
//if (count % 10000 == 0) {
// print("VoxelViewer.getOctreeElementsCount()=" + VoxelViewer.getOctreeElementsCount());
//}
}
}
// approximately every second, consider stopping
if (count % 60 == 0) {
print("considering stop.... elementCount:" + VoxelViewer.getOctreeElementsCount());
var stopProbability = 0.05; // 5% chance of stopping
if (Math.random() < stopProbability) {
print("stopping.... elementCount:" + VoxelViewer.getOctreeElementsCount());
Script.stop();
}
}
}
function scriptEnding() {
print("SCRIPT ENDNG!!!\n");
}
// register the call back so it fires before each data send
Script.update.connect(keepLooking);
// register our scriptEnding callback
Script.scriptEnding.connect(scriptEnding);
// test for local...
Menu.isOptionChecked("Voxels");
isLocal = true; // will only get here on local client

View file

@ -111,7 +111,7 @@ function checkControllerSide(whichSide) {
velocity : { x: 0, y: 0, z: 0}, inHand: true };
Particles.editParticle(closestParticle, properties);
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
options.position = ballPosition;
options.volume = 1.0;
Audio.playSound(catchSound, options);
@ -152,7 +152,7 @@ function checkControllerSide(whichSide) {
}
// Play a new ball sound
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
options.position = ballPosition;
options.volume = 1.0;
Audio.playSound(catchSound, options);
@ -201,7 +201,7 @@ function checkControllerSide(whichSide) {
rightHandParticle = false;
}
var options = new AudioInjectionOptions();
var options = new AudioInjectionOptions();
options.position = ballPosition;
options.volume = 1.0;
Audio.playSound(throwSound, options);

View file

@ -64,7 +64,7 @@ collisionBubble[1] = Overlays.addOverlay("sphere",
visible: false
});
var audioOptions = new AudioInjectionOptions();
var audioOptions = new AudioInjectionOptions();
audioOptions.position = { x: MyAvatar.position.x, y: MyAvatar.position.y + 1, z: MyAvatar.position.z };
audioOptions.volume = 1;

View file

@ -2207,7 +2207,7 @@ void Application::queryOctree(NodeType_t serverType, PacketType packetType, Node
int packetLength = endOfQueryPacket - queryPacket;
// make sure we still have an active socket
nodeList->writeDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
// Feed number of bytes to corresponding channel of the bandwidth meter
_bandwidthMeter.outputStream(BandwidthMeter::VOXELS).updateValue(packetLength);
@ -2644,6 +2644,8 @@ void Application::displayOverlay() {
audioMeterY,
Menu::getInstance()->isOptionChecked(MenuOption::Mirror));
_audio.renderScope(_glWidget->width(), _glWidget->height());
glBegin(GL_QUADS);
if (isClipping) {
glColor3f(1, 0, 0);

View file

@ -92,7 +92,14 @@ Audio::Audio(int16_t initialJitterBufferSamples, QObject* parent) :
_processSpatialAudio(false),
_spatialAudioStart(0),
_spatialAudioFinish(0),
_spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true) // random access mode
_spatialAudioRingBuffer(NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL, true), // random access mode
_scopeEnabled(false),
_scopeEnabledPause(false),
_scopeInputOffset(0),
_scopeOutputOffset(0),
_scopeInput(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0),
_scopeOutputLeft(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0),
_scopeOutputRight(SAMPLES_PER_SCOPE_WIDTH * sizeof(int16_t), 0)
{
// clear the array of locally injected samples
memset(_localProceduralSamples, 0, NETWORK_BUFFER_LENGTH_BYTES_PER_CHANNEL);
@ -575,6 +582,14 @@ void Audio::handleAudioInput() {
processProceduralAudio(monoAudioSamples, NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
}
if (_scopeEnabled && !_scopeEnabledPause) {
unsigned int numMonoAudioChannels = 1;
unsigned int monoAudioChannel = 0;
addBufferToScope(_scopeInput, _scopeInputOffset, monoAudioSamples, monoAudioChannel, numMonoAudioChannels);
_scopeInputOffset += NETWORK_SAMPLES_PER_FRAME;
_scopeInputOffset %= SAMPLES_PER_SCOPE_WIDTH;
}
NodeList* nodeList = NodeList::getInstance();
SharedNodePointer audioMixer = nodeList->soloNodeOfType(NodeType::AudioMixer);
@ -810,6 +825,30 @@ void Audio::processReceivedAudio(const QByteArray& audioByteArray) {
if (_outputDevice) {
_outputDevice->write(outputBuffer);
}
if (_scopeEnabled && !_scopeEnabledPause) {
unsigned int numAudioChannels = _desiredOutputFormat.channelCount();
int16_t* samples = ringBufferSamples;
for (int numSamples = numNetworkOutputSamples / numAudioChannels; numSamples > 0; numSamples -= NETWORK_SAMPLES_PER_FRAME) {
unsigned int audioChannel = 0;
addBufferToScope(
_scopeOutputLeft,
_scopeOutputOffset,
samples, audioChannel, numAudioChannels);
audioChannel = 1;
addBufferToScope(
_scopeOutputRight,
_scopeOutputOffset,
samples, audioChannel, numAudioChannels);
_scopeOutputOffset += NETWORK_SAMPLES_PER_FRAME;
_scopeOutputOffset %= SAMPLES_PER_SCOPE_WIDTH;
samples += NETWORK_SAMPLES_PER_FRAME * numAudioChannels;
}
}
delete[] ringBufferSamples;
}
}
@ -1016,6 +1055,140 @@ void Audio::renderToolBox(int x, int y, bool boxed) {
glDisable(GL_TEXTURE_2D);
}
void Audio::toggleScopePause() {
_scopeEnabledPause = !_scopeEnabledPause;
}
void Audio::toggleScope() {
_scopeEnabled = !_scopeEnabled;
if (_scopeEnabled) {
static const int width = SAMPLES_PER_SCOPE_WIDTH;
_scopeInputOffset = 0;
_scopeOutputOffset = 0;
memset(_scopeInput.data(), 0, width * sizeof(int16_t));
memset(_scopeOutputLeft.data(), 0, width * sizeof(int16_t));
memset(_scopeOutputRight.data(), 0, width * sizeof(int16_t));
}
}
void Audio::addBufferToScope(
QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels) {
// Constant multiplier to map sample value to vertical size of scope
float multiplier = (float)MULTIPLIER_SCOPE_HEIGHT / logf(2.0f);
// Temporary variable receives sample value
float sample;
// Temporary variable receives mapping of sample value
int16_t value;
// Short int pointer to mapped samples in byte array
int16_t* destination = (int16_t*) byteArray.data();
for (int i = 0; i < NETWORK_SAMPLES_PER_FRAME; i++) {
sample = (float)source[i * sourceNumberOfChannels + sourceChannel];
if (sample > 0) {
value = (int16_t)(multiplier * logf(sample));
} else if (sample < 0) {
value = (int16_t)(-multiplier * logf(-sample));
} else {
value = 0;
}
destination[i + frameOffset] = value;
}
}
void Audio::renderScope(int width, int height) {
if (!_scopeEnabled)
return;
static const float backgroundColor[4] = { 0.2f, 0.2f, 0.2f, 0.6f };
static const float gridColor[4] = { 0.3f, 0.3f, 0.3f, 0.6f };
static const float inputColor[4] = { 0.3f, .7f, 0.3f, 0.6f };
static const float outputLeftColor[4] = { 0.7f, .3f, 0.3f, 0.6f };
static const float outputRightColor[4] = { 0.3f, .3f, 0.7f, 0.6f };
static const int gridRows = 2;
static const int gridCols = 5;
int x = (width - SAMPLES_PER_SCOPE_WIDTH) / 2;
int y = (height - SAMPLES_PER_SCOPE_HEIGHT) / 2;
int w = SAMPLES_PER_SCOPE_WIDTH;
int h = SAMPLES_PER_SCOPE_HEIGHT;
renderBackground(backgroundColor, x, y, w, h);
renderGrid(gridColor, x, y, w, h, gridRows, gridCols);
renderLineStrip(inputColor, x, y, w, _scopeInputOffset, _scopeInput);
renderLineStrip(outputLeftColor, x, y, w, _scopeOutputOffset, _scopeOutputLeft);
renderLineStrip(outputRightColor, x, y, w, _scopeOutputOffset, _scopeOutputRight);
}
void Audio::renderBackground(const float* color, int x, int y, int width, int height) {
glColor4fv(color);
glBegin(GL_QUADS);
glVertex2i(x, y);
glVertex2i(x + width, y);
glVertex2i(x + width, y + height);
glVertex2i(x , y + height);
glEnd();
glColor4f(1, 1, 1, 1);
}
void Audio::renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols) {
glColor4fv(color);
glBegin(GL_LINES);
int dx = width / cols;
int dy = height / rows;
int tx = x;
int ty = y;
// Draw horizontal grid lines
for (int i = rows + 1; --i >= 0; ) {
glVertex2i(x, ty);
glVertex2i(x + width, ty);
ty += dy;
}
// Draw vertical grid lines
for (int i = cols + 1; --i >= 0; ) {
glVertex2i(tx, y);
glVertex2i(tx, y + height);
tx += dx;
}
glEnd();
glColor4f(1, 1, 1, 1);
}
void Audio::renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray& byteArray) {
glColor4fv(color);
glBegin(GL_LINE_STRIP);
int16_t sample;
int16_t* samples = ((int16_t*) byteArray.data()) + offset;
y += SAMPLES_PER_SCOPE_HEIGHT / 2;
for (int i = n - offset; --i >= 0; ) {
sample = *samples++;
glVertex2i(x++, y - sample);
}
samples = (int16_t*) byteArray.data();
for (int i = offset; --i >= 0; ) {
sample = *samples++;
glVertex2i(x++, y - sample);
}
glEnd();
glColor4f(1, 1, 1, 1);
}
bool Audio::switchInputToAudioDevice(const QAudioDeviceInfo& inputDeviceInfo) {
bool supportedFormat = false;

View file

@ -25,6 +25,7 @@
#include <QtCore/QVector>
#include <QtMultimedia/QAudioFormat>
#include <QVector>
#include <QByteArray>
#include <AbstractAudioInterface.h>
#include <AudioRingBuffer.h>
@ -64,6 +65,7 @@ public:
bool mousePressEvent(int x, int y);
void renderToolBox(int x, int y, bool boxed);
void renderScope(int width, int height);
int getNetworkSampleRate() { return SAMPLE_RATE; }
int getNetworkBufferLengthSamplesPerChannel() { return NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; }
@ -80,6 +82,8 @@ public slots:
void toggleMute();
void toggleAudioNoiseReduction();
void toggleToneInjection();
void toggleScope();
void toggleScopePause();
void toggleAudioSpatialProcessing();
virtual void handleAudioByteArray(const QByteArray& audioByteArray);
@ -193,6 +197,29 @@ private:
int calculateNumberOfFrameSamples(int numBytes);
float calculateDeviceToNetworkInputRatio(int numBytes);
// Audio scope methods for data acquisition
void addBufferToScope(
QByteArray& byteArray, unsigned int frameOffset, const int16_t* source, unsigned int sourceChannel, unsigned int sourceNumberOfChannels);
// Audio scope methods for rendering
void renderBackground(const float* color, int x, int y, int width, int height);
void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols);
void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray& byteArray);
// Audio scope data
static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL;
static const unsigned int FRAMES_PER_SCOPE = 5;
static const unsigned int SAMPLES_PER_SCOPE_WIDTH = FRAMES_PER_SCOPE * NETWORK_SAMPLES_PER_FRAME;
static const unsigned int MULTIPLIER_SCOPE_HEIGHT = 20;
static const unsigned int SAMPLES_PER_SCOPE_HEIGHT = 2 * 15 * MULTIPLIER_SCOPE_HEIGHT;
bool _scopeEnabled;
bool _scopeEnabledPause;
int _scopeInputOffset;
int _scopeOutputOffset;
QByteArray _scopeInput;
QByteArray _scopeOutputLeft;
QByteArray _scopeOutputRight;
};

View file

@ -5,6 +5,9 @@
// Created by Brad Hefta-Gaub on 4/2/2014
// Copyright (c) 2014 High Fidelity, Inc. All rights reserved.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#ifndef interface_AudioReflector_h
#define interface_AudioReflector_h

View file

@ -260,6 +260,9 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Bandwidth, 0, true);
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, this, SLOT(bandwidthDetails()));
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, this, SLOT(octreeStatsDetails()));
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::AudioScope, 0, false,
appInstance->getAudio(),
SLOT(toggleScope()));
QMenu* developerMenu = addMenu("Developer");
@ -386,6 +389,11 @@ Menu::Menu() :
false,
appInstance->getAudio(),
SLOT(toggleToneInjection()));
addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioScopePause,
Qt::CTRL | Qt::Key_P,
false,
appInstance->getAudio(),
SLOT(toggleScopePause()));
QMenu* spatialAudioMenu = audioDebugMenu->addMenu("Spatial Audio");

View file

@ -259,8 +259,9 @@ namespace MenuOption {
const QString AmbientOcclusion = "Ambient Occlusion";
const QString Atmosphere = "Atmosphere";
const QString AudioNoiseReduction = "Audio Noise Reduction";
const QString AudioScope = "Audio Scope";
const QString AudioScopePause = "Pause Audio Scope";
const QString AudioToneInjection = "Inject Test Tone";
const QString AudioSpatialProcessing = "Audio Spatial Processing";
const QString AudioSpatialProcessingHeadOriented = "Head Oriented";
const QString AudioSpatialProcessingIncludeOriginal = "Includes Network Original";

View file

@ -106,7 +106,7 @@ private:
/// Copy constructor prohibited.
///
Primitive(
const Primitive& prim
const Primitive& copy
);
// SPI methods are defined here
@ -153,14 +153,14 @@ public:
/// Configuration dependency injection constructor.
///
Cube(
float x,
float y,
float z,
float s,
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char faces
float x, ///< Cube location on X-axis
float y, ///< Cube location on Y-axis
float z, ///< Cube location on Z-axis
float s, ///< Cube size
unsigned char r, ///< Cube red color component
unsigned char g, ///< Cube green color component
unsigned char b, ///< Cube blue color component
unsigned char faces ///< Bitmask of faces of cube excluded from construction
);
~Cube();
@ -172,36 +172,48 @@ private:
const Cube& cube
);
/// Cube initialization
///
void init(
float x,
float y,
float z,
float s,
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char faceExclusions
float x, ///< Cube location on X-axis
float y, ///< Cube location on Y-axis
float z, ///< Cube location on Z-axis
float s, ///< Cube size
unsigned char r, ///< Cube red color component
unsigned char g, ///< Cube green color component
unsigned char b, ///< Cube blue color component
unsigned char faceExclusions ///< Bitmask of faces of cube excluded from construction
);
/// Cube termination
///
void terminate();
/// Initialize cube's vertex list
///
void initializeVertices(
float x,
float y,
float z,
float s,
unsigned char r,
unsigned char g,
unsigned char b,
unsigned char faceExclusions
float x, ///< Cube location on X-axis
float y, ///< Cube location on Y-axis
float z, ///< Cube location on Z-axis
float s, ///< Cube size
unsigned char r, ///< Cube red color component
unsigned char g, ///< Cube green color component
unsigned char b, ///< Cube blue color component
unsigned char faceExclusions ///< Bitmask of faces of cube excluded from construction
);
/// Terminate cube's vertex list
///
void terminateVertices();
/// Initialize cube's triangle list
///
void initializeTris(
unsigned char faceExclusions
);
/// Terminate cube's triangle list
///
void terminateTris();
// SPI virtual override methods go here
@ -219,11 +231,11 @@ private:
unsigned long _cpuMemoryUsage; ///< Memory allocation of object
static const int _sNumFacesPerCube = 6;
static const int _sNumVerticesPerCube = 24;
static unsigned char _sFaceIndexToHalfSpaceMask[6];
static float _sVertexIndexToConstructionVector[24][3];
static float _sVertexIndexToNormalVector[6][3];
static const int _sNumFacesPerCube = 6; ///< Number of faces per cube
static const int _sNumVerticesPerCube = 24; ///< Number of vertices per cube
static unsigned char _sFaceIndexToHalfSpaceMask[6]; ///< index to bitmask map
static float _sVertexIndexToConstructionVector[24][3]; ///< Vertex index to construction vector map
static float _sVertexIndexToNormalVector[6][3]; ///< Vertex index to normal vector map
};
@ -242,13 +254,13 @@ public:
/// Add primitive to renderer database.
///
int add(
Primitive* primitive ///< Pointer to primitive
Primitive* primitive ///< Primitive instance to be added
);
/// Remove primitive from renderer database.
///
void remove(
int id ///< Primitive id
int id ///< Primitive id to be removed
);
/// Clear all primitives from renderer database
@ -278,7 +290,7 @@ private:
/// Copy constructor prohibited.
///
Renderer(
const Renderer& primitive
const Renderer& copy
);
// SPI methods are defined here
@ -286,10 +298,10 @@ private:
/// Add primitive to renderer database.
/// Service implementer to provide private override for this method
/// in derived class
/// @return primitive id
/// @return Primitive id
///
virtual int vAdd(
Primitive* primitive ///< Pointer to primitive
Primitive* primitive ///< Primitive instance to be added
) = 0;
/// Remove primitive from renderer database.
@ -297,7 +309,7 @@ private:
/// in derived class
///
virtual void vRemove(
int id ///< Primitive id
int id ///< Primitive id
) = 0;
/// Clear all primitives from renderer database
@ -332,7 +344,7 @@ public:
/// Configuration dependency injection constructor.
///
PrimitiveRenderer(
int maxCount
int maxCount ///< Max count
);
~PrimitiveRenderer();
@ -365,39 +377,39 @@ private:
/// Construct the elements of the faces of the primitive.
///
void constructElements(
Primitive* primitive
Primitive* primitive ///< Primitive instance
);
/// Deconstruct the elements of the faces of the primitive.
///
void deconstructElements(
Primitive* primitive
Primitive* primitive ///< Primitive instance
);
/// Deconstruct the triangle element from the GL buffer.
///
void deconstructTriElement(
int idx
int idx ///< Triangle element index
);
/// Deconstruct the vertex element from the GL buffer.
///
void deconstructVertexElement(
int idx
int idx ///< Vertex element index
);
/// Transfer the vertex element to the GL buffer.
///
void transferVertexElement(
int idx,
VertexElement *vertex
int idx, ///< Vertex element index
VertexElement *vertex ///< Vertex element instance
);
/// Transfer the triangle element to the GL buffer.
///
void transferTriElement(
int idx,
int tri[3]
int idx, ///< Triangle element index
int tri[3] ///< Triangle element data
);
/// Get available primitive index.
@ -424,13 +436,13 @@ private:
/// Add primitive to renderer database.
///
int vAdd(
Primitive* primitive
Primitive* primitive ///< Primitive instance to be added
);
/// Remove primitive from renderer database.
///
void vRemove(
int id
int id ///< Primitive id to be removed
);
/// Clear all primitives from renderer database
@ -451,7 +463,7 @@ private:
private:
int _maxCount;
int _maxCount; ///< Maximum count of tris
// GL related parameters
@ -479,8 +491,8 @@ private:
// Statistics parameters, not necessary for proper operation
unsigned long _gpuMemoryUsage;
unsigned long _cpuMemoryUsage;
unsigned long _gpuMemoryUsage; ///< GPU memory used by this instance
unsigned long _cpuMemoryUsage; ///< CPU memory used by this instance
static const int _sIndicesPerTri = 3;

View file

@ -938,6 +938,8 @@ void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart,
}
void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
static unsigned int lockForReadAttempt = 0;
static unsigned int lockForWriteAttempt = 0;
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"copyWrittenDataToReadArrays()");
@ -946,7 +948,9 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
// time around, the only side effect is the VBOs won't be updated this frame
const int WAIT_FOR_LOCK_IN_MS = 5;
if (_readArraysLock.tryLockForWrite(WAIT_FOR_LOCK_IN_MS)) {
lockForWriteAttempt = 0;
if (_writeArraysLock.tryLockForRead(WAIT_FOR_LOCK_IN_MS)) {
lockForReadAttempt = 0;
if (_voxelsDirty && _voxelsUpdated) {
if (fullVBOs) {
copyWrittenDataToReadArraysFullVBOs();
@ -956,11 +960,19 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) {
}
_writeArraysLock.unlock();
} else {
qDebug() << "couldn't get _writeArraysLock.LockForRead()...";
lockForReadAttempt++;
// only report error of first failure
if (lockForReadAttempt == 1) {
qDebug() << "couldn't get _writeArraysLock.LockForRead()...";
}
}
_readArraysLock.unlock();
} else {
qDebug() << "couldn't get _readArraysLock.LockForWrite()...";
lockForWriteAttempt++;
// only report error of first failure
if (lockForWriteAttempt == 1) {
qDebug() << "couldn't get _readArraysLock.LockForWrite()...";
}
}
}
@ -1683,11 +1695,12 @@ bool VoxelSystem::inspectForExteriorOcclusionsOperation(OctreeElement* element,
//qDebug("Completely occupied voxel at %f %f %f size: %f", v.x, v.y, v.z, s);
// TODO: All of the exterior faces of this voxel element are
// occluders, which means that this element is completely
// occupied. Hence, the subtree from this node could be
// pruned and replaced by a leaf voxel, if the visible
// properties of the children are the same
// All of the exterior faces of this voxel element are
// occluders, which means that this element is completely
// occupied. Hence, the subtree from this node could be
// pruned and replaced by a leaf voxel, if the visible
// properties of the children are the same
} else if (exteriorOcclusions != OctreeElement::HalfSpace::None) {
//const glm::vec3& v = voxel->getCorner();
//float s = voxel->getScale();

View file

@ -227,7 +227,30 @@ qint64 LimitedNodeList::writeDatagram(const QByteArray& datagram, const SharedNo
}
}
writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
return writeDatagram(datagram, *destinationSockAddr, destinationNode->getConnectionSecret());
}
// didn't have a destinationNode to send to, return 0
return 0;
}
qint64 LimitedNodeList::writeUnverifiedDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr) {
if (destinationNode) {
// if we don't have an ovveriden address, assume they want to send to the node's active socket
const HifiSockAddr* destinationSockAddr = &overridenSockAddr;
if (overridenSockAddr.isNull()) {
if (destinationNode->getActiveSocket()) {
// use the node's active socket as the destination socket
destinationSockAddr = destinationNode->getActiveSocket();
} else {
// we don't have a socket to send to, return 0
return 0;
}
}
// don't use the node secret!
return writeDatagram(datagram, *destinationSockAddr, QUuid());
}
// didn't have a destinationNode to send to, return 0
@ -243,6 +266,11 @@ qint64 LimitedNodeList::writeDatagram(const char* data, qint64 size, const Share
return writeDatagram(QByteArray(data, size), destinationNode, overridenSockAddr);
}
qint64 LimitedNodeList::writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr) {
return writeUnverifiedDatagram(QByteArray(data, size), destinationNode, overridenSockAddr);
}
void LimitedNodeList::processNodeData(const HifiSockAddr& senderSockAddr, const QByteArray& packet) {
// the node decided not to do anything with this packet
// if it comes from a known source we should keep that node alive

View file

@ -66,10 +66,17 @@ public:
qint64 writeDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
qint64 writeUnverifiedDatagram(const QByteArray& datagram, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
qint64 writeUnverifiedDatagram(const QByteArray& datagram, const HifiSockAddr& destinationSockAddr);
qint64 writeDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
qint64 writeUnverifiedDatagram(const char* data, qint64 size, const SharedNodePointer& destinationNode,
const HifiSockAddr& overridenSockAddr = HifiSockAddr());
void(*linkedDataCreateCallback)(Node *);
NodeHash getNodeHash();

View file

@ -69,7 +69,7 @@ const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
<< PacketTypeDomainList << PacketTypeDomainListRequest
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse
<< PacketTypeNodeJsonStats;
<< PacketTypeNodeJsonStats << PacketTypeVoxelQuery << PacketTypeParticleQuery;
const int NUM_BYTES_MD5_HASH = 16;
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;

View file

@ -16,13 +16,21 @@ OctreeElementBag::OctreeElementBag() :
_bagElements()
{
OctreeElement::addDeleteHook(this);
_hooked = true;
};
OctreeElementBag::~OctreeElementBag() {
OctreeElement::removeDeleteHook(this);
unhookNotifications();
deleteAll();
}
void OctreeElementBag::unhookNotifications() {
if (_hooked) {
OctreeElement::removeDeleteHook(this);
_hooked = false;
}
}
void OctreeElementBag::elementDeleted(OctreeElement* element) {
remove(element); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains()
}

View file

@ -36,8 +36,11 @@ public:
void deleteAll();
virtual void elementDeleted(OctreeElement* element);
void unhookNotifications();
private:
QSet<OctreeElement*> _bagElements;
bool _hooked;
};
#endif // hifi_OctreeElementBag_h

View file

@ -221,7 +221,7 @@ void OctreeHeadlessViewer::queryOctree() {
int packetLength = endOfQueryPacket - queryPacket;
// make sure we still have an active socket
nodeList->writeDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
nodeList->writeUnverifiedDatagram(reinterpret_cast<const char*>(queryPacket), packetLength, node);
}
}
}

View file

@ -130,9 +130,11 @@ void ViewFrustum::calculate() {
// Also calculate our projection matrix in case people want to project points...
// Projection matrix : Field of View, ratio, display range : near to far
glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, _farClip);
glm::vec3 lookAt = _position + _direction;
glm::mat4 view = glm::lookAt(_position, lookAt, _up);
const float CLIP_NUDGE = 1.0f;
float farClip = (_farClip != _nearClip) ? _farClip : _nearClip + CLIP_NUDGE; // don't allow near and far to be equal
glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, farClip);
glm::vec3 lookAt = _position + _direction;
glm::mat4 view = glm::lookAt(_position, lookAt, _up);
// Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it)
_ourModelViewProjectionMatrix = projection * view; // Remember, matrix multiplication is the other way around