mirror of
https://github.com/overte-org/overte.git
synced 2025-04-23 15:13:41 +02:00
Merge branch 'master' of https://github.com/worklist/hifi
This commit is contained in:
commit
dabb670f1a
25 changed files with 307 additions and 155 deletions
|
@ -57,7 +57,7 @@ void Agent::run() {
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
nodeList->setOwnerType(NODE_TYPE_AGENT);
|
||||
|
||||
const char AGENT_NODE_TYPES_OF_INTEREST[2] = { NODE_TYPE_VOXEL_SERVER, NODE_TYPE_AUDIO_MIXER };
|
||||
const char AGENT_NODE_TYPES_OF_INTEREST[1] = { NODE_TYPE_VOXEL_SERVER };
|
||||
|
||||
nodeList->setNodeTypesOfInterest(AGENT_NODE_TYPES_OF_INTEREST, sizeof(AGENT_NODE_TYPES_OF_INTEREST));
|
||||
|
||||
|
@ -114,9 +114,11 @@ void Agent::run() {
|
|||
|
||||
QScriptValue treeScaleValue = engine.newVariant(QVariant(TREE_SCALE));
|
||||
engine.globalObject().setProperty("TREE_SCALE", treeScaleValue);
|
||||
|
||||
const unsigned int VISUAL_DATA_CALLBACK_USECS = (1.0 / 60.0) * 1000 * 1000;
|
||||
|
||||
// let the VoxelPacketSender know how frequently we plan to call it
|
||||
voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(INJECT_INTERVAL_USECS);
|
||||
voxelScripter.getVoxelPacketSender()->setProcessCallIntervalHint(VISUAL_DATA_CALLBACK_USECS);
|
||||
|
||||
// hook in a constructor for audio injectorss
|
||||
AudioInjector scriptedAudioInjector(BUFFER_LENGTH_SAMPLES_PER_CHANNEL);
|
||||
|
@ -158,28 +160,14 @@ void Agent::run() {
|
|||
NodeList::getInstance()->sendDomainServerCheckIn();
|
||||
}
|
||||
|
||||
// find the audio-mixer in the NodeList so we can inject audio at it
|
||||
Node* audioMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AUDIO_MIXER);
|
||||
|
||||
|
||||
if (audioMixer && audioMixer->getActiveSocket()) {
|
||||
emit willSendAudioDataCallback();
|
||||
}
|
||||
|
||||
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * INJECT_INTERVAL_USECS) - usecTimestampNow();
|
||||
int usecToSleep = usecTimestamp(&startTime) + (thisFrame++ * VISUAL_DATA_CALLBACK_USECS) - usecTimestampNow();
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
}
|
||||
|
||||
if (audioMixer && NodeList::getInstance()->getNodeActiveSocketOrPing(audioMixer) && scriptedAudioInjector.hasSamplesToInject()) {
|
||||
// we have an audio mixer and samples to inject, send those off
|
||||
scriptedAudioInjector.injectAudio(NodeList::getInstance()->getNodeSocket(), audioMixer->getActiveSocket());
|
||||
|
||||
// clear out the audio injector so that it doesn't re-send what we just sent
|
||||
scriptedAudioInjector.clear();
|
||||
}
|
||||
|
||||
if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) {
|
||||
timeval thisSend = {};
|
||||
gettimeofday(&thisSend, NULL);
|
||||
// allow the scripter's call back to setup visual data
|
||||
emit willSendVisualDataCallback();
|
||||
|
||||
|
@ -188,14 +176,13 @@ void Agent::run() {
|
|||
|
||||
// since we're in non-threaded mode, call process so that the packets are sent
|
||||
voxelScripter.getVoxelPacketSender()->process();
|
||||
|
||||
}
|
||||
|
||||
if (engine.hasUncaughtException()) {
|
||||
int line = engine.uncaughtExceptionLineNumber();
|
||||
qDebug() << "Uncaught exception at line" << line << ":" << engine.uncaughtException().toString() << "\n";
|
||||
}
|
||||
|
||||
|
||||
while (NodeList::getInstance()->getNodeSocket()->receive((sockaddr*) &senderAddress, receivedData, &receivedBytes)
|
||||
&& packetVersionMatch(receivedData)) {
|
||||
if (receivedData[0] == PACKET_TYPE_VOXEL_JURISDICTION) {
|
||||
|
|
|
@ -12,9 +12,6 @@
|
|||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
|
||||
#include <Logging.h>
|
||||
#include <NodeList.h>
|
||||
#include <PacketHeaders.h>
|
||||
|
|
|
@ -78,6 +78,11 @@ function updateCells() {
|
|||
nextCells[i][j] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (Math.random() < 0.001) {
|
||||
// Random mutation to keep things interesting in there.
|
||||
nextCells[i][j] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4094,11 +4094,13 @@ void Application::nodeKilled(Node* node) {
|
|||
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||
|
||||
// Add the jurisditionDetails object to the list of "fade outs"
|
||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFades.push_back(fade);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) {
|
||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_KILLED_RED, NODE_KILLED_GREEN, NODE_KILLED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFades.push_back(fade);
|
||||
}
|
||||
}
|
||||
} else if (node->getLinkedData() == _lookatTargetAvatar) {
|
||||
_lookatTargetAvatar = NULL;
|
||||
|
@ -4127,11 +4129,13 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
|
|||
rootDetails.x, rootDetails.y, rootDetails.z, rootDetails.s);
|
||||
|
||||
// Add the jurisditionDetails object to the list of "fade outs"
|
||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFades.push_back(fade);
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::DontFadeOnVoxelServerChanges)) {
|
||||
VoxelFade fade(VoxelFade::FADE_OUT, NODE_ADDED_RED, NODE_ADDED_GREEN, NODE_ADDED_BLUE);
|
||||
fade.voxelDetails = rootDetails;
|
||||
const float slightly_smaller = 0.99;
|
||||
fade.voxelDetails.s = fade.voxelDetails.s * slightly_smaller;
|
||||
_voxelFades.push_back(fade);
|
||||
}
|
||||
}
|
||||
// store jurisdiction details for later use
|
||||
// This is bit of fiddling is because JurisdictionMap assumes it is the owner of the values used to construct it
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <QSlider>
|
||||
#include <QStandardPaths>
|
||||
#include <QUuid>
|
||||
#include <QWindow>
|
||||
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -282,6 +283,7 @@ Menu::Menu() :
|
|||
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontFadeOnVoxelServerChanges);
|
||||
addActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L, this, SLOT(lodTools()));
|
||||
|
||||
QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options");
|
||||
|
@ -718,16 +720,13 @@ void Menu::aboutApp() {
|
|||
InfoView::forcedShow();
|
||||
}
|
||||
|
||||
void updateDSHostname(const QString& domainServerHostname) {
|
||||
QString newHostname(DEFAULT_DOMAIN_HOSTNAME);
|
||||
void sendFakeEnterEvent() {
|
||||
QPoint lastCursorPosition = QCursor::pos();
|
||||
QGLWidget* glWidget = Application::getInstance()->getGLWidget();
|
||||
|
||||
if (domainServerHostname.size() > 0) {
|
||||
// the user input a new hostname, use that
|
||||
newHostname = domainServerHostname;
|
||||
}
|
||||
|
||||
// give our nodeList the new domain-server hostname
|
||||
NodeList::getInstance()->setDomainHostname(newHostname);
|
||||
QPoint windowPosition = glWidget->mapFromGlobal(lastCursorPosition);
|
||||
QEnterEvent enterEvent = QEnterEvent(windowPosition, windowPosition, lastCursorPosition);
|
||||
QCoreApplication::sendEvent(glWidget, &enterEvent);
|
||||
}
|
||||
|
||||
const int QLINE_MINIMUM_WIDTH = 400;
|
||||
|
@ -743,11 +742,15 @@ void Menu::login() {
|
|||
loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height());
|
||||
|
||||
int dialogReturn = loginDialog.exec();
|
||||
|
||||
if (dialogReturn == QDialog::Accepted && !loginDialog.textValue().isEmpty() && loginDialog.textValue() != username) {
|
||||
// there has been a username change
|
||||
// ask for a profile reset with the new username
|
||||
Application::getInstance()->resetProfile(loginDialog.textValue());
|
||||
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::editPreferences() {
|
||||
|
@ -811,52 +814,52 @@ void Menu::editPreferences() {
|
|||
layout->addWidget(buttons);
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QUrl faceModelURL(faceURLEdit->text());
|
||||
|
||||
if (faceModelURL.toString() != faceURLString) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
applicationInstance->getProfile()->setFaceModelURL(faceModelURL);
|
||||
if (ret == QDialog::Accepted) {
|
||||
QUrl faceModelURL(faceURLEdit->text());
|
||||
|
||||
// send the new face mesh URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKey(DataServerKey::FaceMeshURL,
|
||||
faceModelURL.toString().toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
QUrl skeletonModelURL(skeletonURLEdit->text());
|
||||
|
||||
if (skeletonModelURL.toString() != skeletonURLString) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
applicationInstance->getProfile()->setSkeletonModelURL(skeletonModelURL);
|
||||
if (faceModelURL.toString() != faceURLString) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
applicationInstance->getProfile()->setFaceModelURL(faceModelURL);
|
||||
|
||||
// send the new face mesh URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKey(DataServerKey::FaceMeshURL,
|
||||
faceModelURL.toString().toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
// send the new skeleton model URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKey(DataServerKey::SkeletonURL,
|
||||
skeletonModelURL.toString().toLocal8Bit().constData());
|
||||
QUrl skeletonModelURL(skeletonURLEdit->text());
|
||||
|
||||
if (skeletonModelURL.toString() != skeletonURLString) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
applicationInstance->getProfile()->setSkeletonModelURL(skeletonModelURL);
|
||||
|
||||
// send the new skeleton model URL to the data-server (if we have a client UUID)
|
||||
DataServerClient::putValueForKey(DataServerKey::SkeletonURL,
|
||||
skeletonModelURL.toString().toLocal8Bit().constData());
|
||||
}
|
||||
|
||||
QUrl avatarVoxelURL(avatarURL->text());
|
||||
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
||||
|
||||
Avatar::sendAvatarURLsMessage(avatarVoxelURL);
|
||||
|
||||
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
|
||||
|
||||
_maxVoxels = maxVoxels->value();
|
||||
applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels);
|
||||
|
||||
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
|
||||
|
||||
_audioJitterBufferSamples = audioJitterBufferSamples->value();
|
||||
|
||||
if (_audioJitterBufferSamples != 0) {
|
||||
applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples);
|
||||
}
|
||||
|
||||
_fieldOfView = fieldOfView->value();
|
||||
applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height());
|
||||
}
|
||||
|
||||
QUrl avatarVoxelURL(avatarURL->text());
|
||||
applicationInstance->getAvatar()->getVoxels()->setVoxelURL(avatarVoxelURL);
|
||||
|
||||
Avatar::sendAvatarURLsMessage(avatarVoxelURL);
|
||||
|
||||
applicationInstance->getAvatar()->getHead().setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
|
||||
|
||||
_maxVoxels = maxVoxels->value();
|
||||
applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels);
|
||||
|
||||
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
|
||||
|
||||
_audioJitterBufferSamples = audioJitterBufferSamples->value();
|
||||
|
||||
if (_audioJitterBufferSamples != 0) {
|
||||
applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples);
|
||||
}
|
||||
|
||||
_fieldOfView = fieldOfView->value();
|
||||
applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height());
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToDomain() {
|
||||
|
@ -876,9 +879,19 @@ void Menu::goToDomain() {
|
|||
domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height());
|
||||
|
||||
int dialogReturn = domainDialog.exec();
|
||||
if (dialogReturn == QDialog::Accepted && !domainDialog.textValue().isEmpty()) {
|
||||
updateDSHostname(domainDialog.textValue());
|
||||
if (dialogReturn == QDialog::Accepted) {
|
||||
QString newHostname(DEFAULT_DOMAIN_HOSTNAME);
|
||||
|
||||
if (domainDialog.textValue().size() > 0) {
|
||||
// the user input a new hostname, use that
|
||||
newHostname = domainDialog.textValue();
|
||||
}
|
||||
|
||||
// give our nodeList the new domain-server hostname
|
||||
NodeList::getInstance()->setDomainHostname(domainDialog.textValue());
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToLocation() {
|
||||
|
@ -918,6 +931,8 @@ void Menu::goToLocation() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToUser() {
|
||||
|
@ -935,6 +950,8 @@ void Menu::goToUser() {
|
|||
DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position),
|
||||
userDialog.textValue());
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::bandwidthDetails() {
|
||||
|
|
|
@ -165,6 +165,7 @@ namespace MenuOption {
|
|||
const QString EchoAudio = "Echo Audio";
|
||||
const QString ExportVoxels = "Export Voxels";
|
||||
const QString ExtraDebugging = "Extra Debugging";
|
||||
const QString DontFadeOnVoxelServerChanges = "Don't Fade In/Out on Voxel Server Changes";
|
||||
const QString HeadMouse = "Head Mouse";
|
||||
const QString FaceMode = "Cycle Face Mode";
|
||||
const QString FaceshiftTCP = "Faceshift (TCP)";
|
||||
|
|
|
@ -2645,23 +2645,8 @@ bool VoxelSystem::killSourceVoxelsOperation(VoxelNode* node, void* extraData) {
|
|||
void VoxelSystem::nodeKilled(Node* node) {
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
_voxelServerCount--;
|
||||
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
|
||||
qDebug("VoxelSystem... voxel server %s removed...\n", nodeUUID.toString().toLocal8Bit().constData());
|
||||
|
||||
if (_voxelServerCount > 0) {
|
||||
// Kill any voxels from the local tree that match this nodeID
|
||||
// commenting out for removal of 16 bit node IDs
|
||||
lockTree();
|
||||
_tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID);
|
||||
unlockTree();
|
||||
_tree->setDirtyBit();
|
||||
setupNewVoxelsForDrawing();
|
||||
} else {
|
||||
// Last server, take the easy way and kill all the local voxels!
|
||||
killLocalVoxels();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -255,6 +255,11 @@ Avatar::~Avatar() {
|
|||
delete _balls;
|
||||
}
|
||||
|
||||
void Avatar::deleteOrDeleteLater() {
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void Avatar::init() {
|
||||
_head.init();
|
||||
_hand.init();
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
|
||||
Avatar(Node* owningNode = NULL);
|
||||
~Avatar();
|
||||
void deleteOrDeleteLater();
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
|
|
|
@ -44,7 +44,7 @@ Node::~Node() {
|
|||
delete _localSocket;
|
||||
|
||||
if (_linkedData) {
|
||||
_linkedData->deleteLater();
|
||||
_linkedData->deleteOrDeleteLater();
|
||||
}
|
||||
|
||||
delete _bytesReceivedMovingAverage;
|
||||
|
|
|
@ -16,4 +16,8 @@ NodeData::NodeData(Node* owningNode) :
|
|||
|
||||
NodeData::~NodeData() {
|
||||
|
||||
}
|
||||
|
||||
void NodeData::deleteOrDeleteLater() {
|
||||
delete this;
|
||||
}
|
|
@ -21,6 +21,8 @@ public:
|
|||
virtual ~NodeData() = 0;
|
||||
virtual int parseData(unsigned char* sourceBuffer, int numBytes) = 0;
|
||||
|
||||
virtual void deleteOrDeleteLater();
|
||||
|
||||
Node* getOwningNode() { return _owningNode; }
|
||||
protected:
|
||||
Node* _owningNode;
|
||||
|
|
|
@ -35,6 +35,8 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) :
|
|||
_lastVoxelPacketLength = 0;
|
||||
_duplicatePacketCount = 0;
|
||||
resetVoxelPacket();
|
||||
|
||||
qDebug("VoxelNodeData::VoxelNodeData() this=%p owningNode=%p\n", this, owningNode);
|
||||
}
|
||||
|
||||
void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
||||
|
@ -42,6 +44,10 @@ void VoxelNodeData::initializeVoxelSendThread(VoxelServer* voxelServer) {
|
|||
QUuid nodeUUID = getOwningNode()->getUUID();
|
||||
_voxelSendThread = new VoxelSendThread(nodeUUID, voxelServer);
|
||||
_voxelSendThread->initialize(true);
|
||||
|
||||
qDebug("VoxelNodeData::initializeVoxelSendThread() this=%p owningNode=%p _voxelSendThread=%p\n",
|
||||
this, getOwningNode(), _voxelSendThread);
|
||||
qDebug() << "VoxelNodeData::initializeVoxelSendThread() nodeUUID=" << nodeUUID << "\n";
|
||||
}
|
||||
|
||||
bool VoxelNodeData::packetIsDuplicate() const {
|
||||
|
@ -111,12 +117,19 @@ void VoxelNodeData::writeToPacket(unsigned char* buffer, int bytes) {
|
|||
}
|
||||
|
||||
VoxelNodeData::~VoxelNodeData() {
|
||||
|
||||
qDebug("VoxelNodeData::~VoxelNodeData() this=%p owningNode=%p _voxelSendThread=%p\n",
|
||||
this, getOwningNode(), _voxelSendThread);
|
||||
QUuid nodeUUID = getOwningNode()->getUUID();
|
||||
qDebug() << "VoxelNodeData::~VoxelNodeData() nodeUUID=" << nodeUUID << "\n";
|
||||
|
||||
delete[] _voxelPacket;
|
||||
delete[] _lastVoxelPacket;
|
||||
|
||||
if (_voxelSendThread) {
|
||||
_voxelSendThread->terminate();
|
||||
delete _voxelSendThread;
|
||||
qDebug("VoxelNodeData::~VoxelNodeData() DELETED _voxelSendThread=%p\n", _voxelSendThread);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class VoxelServer;
|
|||
class VoxelNodeData : public VoxelQuery {
|
||||
public:
|
||||
VoxelNodeData(Node* owningNode);
|
||||
~VoxelNodeData();
|
||||
virtual ~VoxelNodeData();
|
||||
|
||||
void resetVoxelPacket(); // resets voxel packet to after "V" header
|
||||
|
||||
|
|
|
@ -20,30 +20,28 @@ VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, in
|
|||
_tree(tree),
|
||||
_filename(filename),
|
||||
_persistInterval(persistInterval),
|
||||
_initialLoad(false) {
|
||||
_initialLoadComplete(false),
|
||||
_loadTimeUSecs(0) {
|
||||
}
|
||||
|
||||
bool VoxelPersistThread::process() {
|
||||
|
||||
if (!_initialLoad) {
|
||||
_initialLoad = true;
|
||||
if (!_initialLoadComplete) {
|
||||
uint64_t loadStarted = usecTimestampNow();
|
||||
qDebug("loading voxels from file: %s...\n", _filename);
|
||||
|
||||
bool persistantFileRead;
|
||||
|
||||
|
||||
_tree->lockForWrite();
|
||||
{
|
||||
PerformanceWarning warn(true, "Loading Voxel File", true);
|
||||
persistantFileRead = _tree->readFromSVOFile(_filename);
|
||||
}
|
||||
_tree->unlock();
|
||||
|
||||
if (persistantFileRead) {
|
||||
PerformanceWarning warn(true, "Voxels Re-Averaging", true);
|
||||
|
||||
// after done inserting all these voxels, then reaverage colors
|
||||
qDebug("BEGIN Voxels Re-Averaging\n");
|
||||
_tree->reaverageVoxelColors(_tree->rootNode);
|
||||
qDebug("DONE WITH Voxels Re-Averaging\n");
|
||||
}
|
||||
_loadCompleted = time(0);
|
||||
uint64_t loadDone = usecTimestampNow();
|
||||
_loadTimeUSecs = loadDone - loadStarted;
|
||||
|
||||
_tree->clearDirtyBit(); // the tree is clean since we just loaded it
|
||||
qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead));
|
||||
|
@ -61,6 +59,7 @@ bool VoxelPersistThread::process() {
|
|||
qDebug("setChildAtIndexCalls=%llu setChildAtIndexTime=%llu perSet=%lf\n",
|
||||
VoxelNode::getSetChildAtIndexTime(), VoxelNode::getSetChildAtIndexCalls(), usecPerSet);
|
||||
|
||||
_initialLoadComplete = true;
|
||||
}
|
||||
|
||||
uint64_t MSECS_TO_USECS = 1000;
|
||||
|
|
|
@ -21,6 +21,12 @@ public:
|
|||
static const int DEFAULT_PERSIST_INTERVAL = 1000 * 30; // every 30 seconds
|
||||
|
||||
VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval = DEFAULT_PERSIST_INTERVAL);
|
||||
|
||||
bool isInitialLoadComplete() const { return _initialLoadComplete; }
|
||||
|
||||
time_t* getLoadCompleted() { return &_loadCompleted; }
|
||||
uint64_t getLoadElapsedTime() const { return _loadTimeUSecs; }
|
||||
|
||||
protected:
|
||||
/// Implements generic processing behavior for this thread.
|
||||
virtual bool process();
|
||||
|
@ -28,7 +34,10 @@ private:
|
|||
VoxelTree* _tree;
|
||||
const char* _filename;
|
||||
int _persistInterval;
|
||||
bool _initialLoad;
|
||||
bool _initialLoadComplete;
|
||||
|
||||
time_t _loadCompleted;
|
||||
uint64_t _loadTimeUSecs;
|
||||
};
|
||||
|
||||
#endif // __voxel_server__VoxelPersistThread__
|
||||
|
|
|
@ -26,28 +26,39 @@ VoxelSendThread::VoxelSendThread(const QUuid& nodeUUID, VoxelServer* myServer) :
|
|||
bool VoxelSendThread::process() {
|
||||
uint64_t start = usecTimestampNow();
|
||||
|
||||
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
||||
VoxelNodeData* nodeData = NULL;
|
||||
// don't do any send processing until the initial load of the voxels is complete...
|
||||
if (_myServer->isInitialLoadComplete()) {
|
||||
Node* node = NodeList::getInstance()->nodeWithUUID(_nodeUUID);
|
||||
|
||||
if (node) {
|
||||
nodeData = (VoxelNodeData*) node->getLinkedData();
|
||||
}
|
||||
if (node) {
|
||||
node->lock(); // make sure the node list doesn't kill our node while we're using it
|
||||
VoxelNodeData* nodeData = NULL;
|
||||
|
||||
int packetsSent = 0;
|
||||
nodeData = (VoxelNodeData*) node->getLinkedData();
|
||||
|
||||
int packetsSent = 0;
|
||||
|
||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||
if (nodeData) {
|
||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||
if (_myServer->wantsDebugVoxelSending()) {
|
||||
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||
}
|
||||
packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
|
||||
}
|
||||
// Sometimes the node data has not yet been linked, in which case we can't really do anything
|
||||
if (nodeData) {
|
||||
bool viewFrustumChanged = nodeData->updateCurrentViewFrustum();
|
||||
if (_myServer->wantsDebugVoxelSending()) {
|
||||
printf("nodeData->updateCurrentViewFrustum() changed=%s\n", debug::valueOf(viewFrustumChanged));
|
||||
}
|
||||
packetsSent = deepestLevelVoxelDistributor(node, nodeData, viewFrustumChanged);
|
||||
}
|
||||
|
||||
node->unlock(); // we're done with this node for now.
|
||||
}
|
||||
} else {
|
||||
if (_myServer->wantsDebugVoxelSending()) {
|
||||
qDebug("VoxelSendThread::process() waiting for isInitialLoadComplete()\n");
|
||||
}
|
||||
}
|
||||
|
||||
// dynamically sleep until we need to fire off the next set of voxels
|
||||
int elapsed = (usecTimestampNow() - start);
|
||||
int usecToSleep = VOXEL_SEND_INTERVAL_USECS - elapsed;
|
||||
|
||||
|
||||
if (usecToSleep > 0) {
|
||||
usleep(usecToSleep);
|
||||
} else {
|
||||
|
@ -55,6 +66,7 @@ bool VoxelSendThread::process() {
|
|||
std::cout << "Last send took too much time, not sleeping!\n";
|
||||
}
|
||||
}
|
||||
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
||||
|
||||
|
@ -112,8 +124,6 @@ int VoxelSendThread::handlePacketSend(Node* node, VoxelNodeData* nodeData, int&
|
|||
/// Version of voxel distributor that sends the deepest LOD level at once
|
||||
int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nodeData, bool viewFrustumChanged) {
|
||||
|
||||
_myServer->lockTree();
|
||||
|
||||
int truePacketsSent = 0;
|
||||
int trueBytesSent = 0;
|
||||
int packetsSentThisInterval = 0;
|
||||
|
@ -284,10 +294,13 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
|
|||
nodeData->getLastTimeBagEmpty(),
|
||||
isFullScene, &nodeData->stats, _myServer->getJurisdiction());
|
||||
|
||||
|
||||
_myServer->getServerTree().lockForRead();
|
||||
nodeData->stats.encodeStarted();
|
||||
bytesWritten = _myServer->getServerTree().encodeTreeBitstream(subTree, _tempOutputBuffer, MAX_VOXEL_PACKET_SIZE - 1,
|
||||
nodeData->nodeBag, params);
|
||||
nodeData->stats.encodeStopped();
|
||||
_myServer->getServerTree().unlock();
|
||||
|
||||
if (nodeData->getAvailable() >= bytesWritten) {
|
||||
nodeData->writeToPacket(_tempOutputBuffer, bytesWritten);
|
||||
|
@ -355,8 +368,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
|
|||
|
||||
} // end if bag wasn't empty, and so we sent stuff...
|
||||
|
||||
_myServer->unlockTree();
|
||||
|
||||
return truePacketsSent;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,11 @@ const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxe
|
|||
|
||||
void attachVoxelNodeDataToNode(Node* newNode) {
|
||||
if (newNode->getLinkedData() == NULL) {
|
||||
newNode->setLinkedData(new VoxelNodeData(newNode));
|
||||
VoxelNodeData* voxelNodeData = new VoxelNodeData(newNode);
|
||||
QUuid nodeUUID = newNode->getUUID();
|
||||
qDebug("attachVoxelNodeDataToNode() newNode=%p voxelNodeData=%p\n", newNode, voxelNodeData);
|
||||
qDebug() << "attachVoxelNodeDataToNode() node UUID:" << nodeUUID << "\n";
|
||||
newNode->setLinkedData(voxelNodeData);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +175,47 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
|
|||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
|
||||
|
||||
// display voxel file load time
|
||||
if (GetInstance()->isInitialLoadComplete()) {
|
||||
tm* voxelsLoadedAtLocal = localtime(GetInstance()->getLoadCompleted());
|
||||
const int MAX_TIME_LENGTH = 128;
|
||||
char buffer[MAX_TIME_LENGTH];
|
||||
strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtLocal);
|
||||
mg_printf(connection, "Voxels Loaded At: %s", buffer);
|
||||
|
||||
// Convert now to tm struct for UTC
|
||||
tm* voxelsLoadedAtUTM = gmtime(GetInstance()->getLoadCompleted());
|
||||
if (gmtm != NULL) {
|
||||
strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", voxelsLoadedAtUTM);
|
||||
mg_printf(connection, " [%s UTM] ", buffer);
|
||||
}
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
|
||||
|
||||
uint64_t msecsElapsed = GetInstance()->getLoadElapsedTime() / USECS_PER_MSEC;;
|
||||
float seconds = (msecsElapsed % MSECS_PER_MIN)/(float)MSECS_PER_SEC;
|
||||
int minutes = (msecsElapsed/(MSECS_PER_MIN)) % MIN_PER_HOUR;
|
||||
int hours = (msecsElapsed/(MSECS_PER_MIN * MIN_PER_HOUR));
|
||||
|
||||
mg_printf(connection, "%s", "Voxels Load Took: ");
|
||||
if (hours > 0) {
|
||||
mg_printf(connection, "%d hour%s ", hours, (hours > 1) ? "s" : "" );
|
||||
}
|
||||
if (minutes > 0) {
|
||||
mg_printf(connection, "%d minute%s ", minutes, (minutes > 1) ? "s" : "");
|
||||
}
|
||||
if (seconds > 0) {
|
||||
mg_printf(connection, "%.3f seconds", seconds);
|
||||
}
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
|
||||
} else {
|
||||
mg_printf(connection, "%s", "Voxels not yet loaded...\r\n");
|
||||
}
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
mg_printf(connection, "%s", "Configuration: \r\n ");
|
||||
for (int i = 1; i < GetInstance()->_argc; i++) {
|
||||
|
@ -339,8 +384,6 @@ void VoxelServer::run() {
|
|||
parsePayload();
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_treeLock, NULL);
|
||||
|
||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
||||
|
||||
const char* STATUS_PORT = "--statusPort";
|
||||
|
@ -510,8 +553,8 @@ void VoxelServer::run() {
|
|||
|
||||
// loop to send to nodes requesting data
|
||||
while (true) {
|
||||
|
||||
if (NodeList::getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS) {
|
||||
qDebug() << "Exit loop... getInstance()->getNumNoReplyDomainCheckIns() == MAX_SILENT_DOMAIN_SERVER_CHECK_INS\n";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -567,28 +610,39 @@ void VoxelServer::run() {
|
|||
}
|
||||
}
|
||||
}
|
||||
qDebug() << "VoxelServer::run()... AFTER loop...\n";
|
||||
|
||||
delete _jurisdiction;
|
||||
// call NodeList::clear() so that all of our node specific objects, including our sending threads, are
|
||||
// properly shutdown and cleaned up.
|
||||
NodeList::getInstance()->clear();
|
||||
|
||||
qDebug() << "VoxelServer::run()... terminating _jurisdictionSender\n";
|
||||
if (_jurisdictionSender) {
|
||||
_jurisdictionSender->terminate();
|
||||
delete _jurisdictionSender;
|
||||
}
|
||||
|
||||
qDebug() << "VoxelServer::run()... terminating _voxelServerPacketProcessor\n";
|
||||
if (_voxelServerPacketProcessor) {
|
||||
_voxelServerPacketProcessor->terminate();
|
||||
delete _voxelServerPacketProcessor;
|
||||
}
|
||||
|
||||
qDebug() << "VoxelServer::run()... terminating _voxelPersistThread\n";
|
||||
if (_voxelPersistThread) {
|
||||
_voxelPersistThread->terminate();
|
||||
delete _voxelPersistThread;
|
||||
}
|
||||
|
||||
// tell our NodeList we're done with notifications
|
||||
qDebug() << "VoxelServer::run()... nodeList->removeHook(&_nodeWatcher)\n";
|
||||
nodeList->removeHook(&_nodeWatcher);
|
||||
|
||||
pthread_mutex_destroy(&_treeLock);
|
||||
|
||||
qDebug() << "VoxelServer::run()... deleting _jurisdiction\n";
|
||||
delete _jurisdiction;
|
||||
_jurisdiction = NULL;
|
||||
|
||||
qDebug() << "VoxelServer::run()... DONE\n";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -48,10 +48,6 @@ public:
|
|||
VoxelTree& getServerTree() { return _serverTree; }
|
||||
JurisdictionMap* getJurisdiction() { return _jurisdiction; }
|
||||
|
||||
void lockTree() { pthread_mutex_lock(&_treeLock); }
|
||||
void unlockTree() { pthread_mutex_unlock(&_treeLock); }
|
||||
VoxelTree* getTree() { return &_serverTree; }
|
||||
|
||||
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
|
||||
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
|
||||
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
|
||||
|
@ -59,6 +55,10 @@ public:
|
|||
|
||||
static VoxelServer* GetInstance() { return _theInstance; }
|
||||
|
||||
bool isInitialLoadComplete() const { return (_voxelPersistThread) ? _voxelPersistThread->isInitialLoadComplete() : true; }
|
||||
time_t* getLoadCompleted() { return (_voxelPersistThread) ? _voxelPersistThread->getLoadCompleted() : NULL; }
|
||||
uint64_t getLoadElapsedTime() const { return (_voxelPersistThread) ? _voxelPersistThread->getLoadElapsedTime() : 0; }
|
||||
|
||||
private:
|
||||
int _argc;
|
||||
const char** _argv;
|
||||
|
@ -80,7 +80,6 @@ private:
|
|||
JurisdictionSender* _jurisdictionSender;
|
||||
VoxelServerPacketProcessor* _voxelServerPacketProcessor;
|
||||
VoxelPersistThread* _voxelPersistThread;
|
||||
pthread_mutex_t _treeLock;
|
||||
EnvironmentData _environmentData[3];
|
||||
|
||||
NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
|
||||
|
|
|
@ -85,10 +85,10 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
|||
printf("inserting voxel: %f,%f,%f r=%d,g=%d,b=%d\n", vertices[0], vertices[1], vertices[2], red, green, blue);
|
||||
delete[] vertices;
|
||||
}
|
||||
|
||||
_myServer->lockTree();
|
||||
|
||||
_myServer->getServerTree().lockForWrite();
|
||||
_myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
|
||||
_myServer->unlockTree();
|
||||
_myServer->getServerTree().unlock();
|
||||
|
||||
// skip to next voxel edit record in the packet
|
||||
voxelData += voxelDataSize;
|
||||
|
@ -114,9 +114,9 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
|||
} else if (packetData[0] == PACKET_TYPE_ERASE_VOXEL) {
|
||||
|
||||
// Send these bits off to the VoxelTree class to process them
|
||||
_myServer->lockTree();
|
||||
_myServer->getServerTree().lockForWrite();
|
||||
_myServer->getServerTree().processRemoveVoxelBitstream((unsigned char*)packetData, packetLength);
|
||||
_myServer->unlockTree();
|
||||
_myServer->getServerTree().unlock();
|
||||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
Node* node = NodeList::getInstance()->nodeWithAddress(&senderAddress);
|
||||
|
|
|
@ -109,8 +109,47 @@ JurisdictionMap::JurisdictionMap(unsigned char* rootOctalCode, const std::vector
|
|||
init(rootOctalCode, endNodes);
|
||||
}
|
||||
|
||||
void myDebugoutputBits(unsigned char byte, bool withNewLine) {
|
||||
if (isalnum(byte)) {
|
||||
printf("[ %d (%c): ", byte, byte);
|
||||
} else {
|
||||
printf("[ %d (0x%x): ", byte, byte);
|
||||
}
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
printf("%d", byte >> (7 - i) & 1);
|
||||
}
|
||||
printf(" ] ");
|
||||
|
||||
if (withNewLine) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void myDebugPrintOctalCode(const unsigned char* octalCode, bool withNewLine) {
|
||||
if (!octalCode) {
|
||||
printf("NULL");
|
||||
} else {
|
||||
for (int i = 0; i < bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(octalCode)); i++) {
|
||||
myDebugoutputBits(octalCode[i],false);
|
||||
}
|
||||
}
|
||||
if (withNewLine) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHexCodes) {
|
||||
|
||||
qDebug("JurisdictionMap::JurisdictionMap(const char* rootHexCode=[%p] %s, const char* endNodesHexCodes=[%p] %s)\n",
|
||||
rootHexCode, rootHexCode, endNodesHexCodes, endNodesHexCodes);
|
||||
|
||||
_rootOctalCode = hexStringToOctalCode(QString(rootHexCode));
|
||||
|
||||
qDebug("JurisdictionMap::JurisdictionMap() _rootOctalCode=%p octalCode=", _rootOctalCode);
|
||||
myDebugPrintOctalCode(_rootOctalCode, true);
|
||||
|
||||
QString endNodesHexStrings(endNodesHexCodes);
|
||||
QString delimiterPattern(",");
|
||||
|
@ -120,8 +159,16 @@ JurisdictionMap::JurisdictionMap(const char* rootHexCode, const char* endNodesHe
|
|||
QString endNodeHexString = endNodeList.at(i);
|
||||
|
||||
unsigned char* endNodeOctcode = hexStringToOctalCode(endNodeHexString);
|
||||
|
||||
qDebug("JurisdictionMap::JurisdictionMap() endNodeList(%d)=%s\n",
|
||||
i, endNodeHexString.toLocal8Bit().constData());
|
||||
|
||||
//printOctalCode(endNodeOctcode);
|
||||
_endNodes.push_back(endNodeOctcode);
|
||||
|
||||
qDebug("JurisdictionMap::JurisdictionMap() endNodeOctcode=%p octalCode=", endNodeOctcode);
|
||||
myDebugPrintOctalCode(endNodeOctcode, true);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -42,6 +42,7 @@ VoxelQuery::VoxelQuery(Node* owningNode) :
|
|||
}
|
||||
|
||||
VoxelQuery::~VoxelQuery() {
|
||||
qDebug("VoxelQuery::~VoxelQuery()\n");
|
||||
}
|
||||
|
||||
int VoxelQuery::getBroadcastData(unsigned char* destinationBuffer) {
|
||||
|
|
|
@ -35,7 +35,7 @@ class VoxelQuery : public NodeData {
|
|||
|
||||
public:
|
||||
VoxelQuery(Node* owningNode = NULL);
|
||||
~VoxelQuery();
|
||||
virtual ~VoxelQuery();
|
||||
|
||||
int getBroadcastData(unsigned char* destinationBuffer);
|
||||
int parseData(unsigned char* sourceBuffer, int numBytes);
|
||||
|
|
|
@ -1806,9 +1806,10 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) {
|
|||
while (!nodeBag.isEmpty()) {
|
||||
VoxelNode* subTree = nodeBag.extract();
|
||||
|
||||
lockForRead(); // do tree locking down here so that we have shorter slices and less thread contention
|
||||
EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS);
|
||||
bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params);
|
||||
|
||||
unlock();
|
||||
file.write((const char*)&outputBuffer[0], bytesWritten);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "VoxelEditPacketSender.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QReadWriteLock>
|
||||
|
||||
// Callback function, for recuseTreeWithOperation
|
||||
typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData);
|
||||
|
@ -185,6 +186,13 @@ public:
|
|||
// reads voxels from square image with alpha as a Y-axis
|
||||
bool readFromSquareARGB32Pixels(const char *filename);
|
||||
bool readFromSchematicFile(const char* filename);
|
||||
|
||||
// VoxelTree does not currently handle its own locking, caller must use these to lock/unlock
|
||||
void lockForRead() { lock.lockForRead(); }
|
||||
void tryLockForRead() { lock.tryLockForRead(); }
|
||||
void lockForWrite() { lock.lockForWrite(); }
|
||||
void tryLockForWrite() { lock.tryLockForWrite(); }
|
||||
void unlock() { lock.unlock(); }
|
||||
|
||||
unsigned long getVoxelCount();
|
||||
|
||||
|
@ -266,6 +274,8 @@ private:
|
|||
static bool nudgeCheck(VoxelNode* node, void* extraData);
|
||||
void nudgeLeaf(VoxelNode* node, void* extraData);
|
||||
void chunkifyLeaf(VoxelNode* node);
|
||||
|
||||
QReadWriteLock lock;
|
||||
};
|
||||
|
||||
float boundaryDistanceForRenderLevel(unsigned int renderLevel, float voxelSizeScale);
|
||||
|
|
Loading…
Reference in a new issue