mirror of
https://github.com/overte-org/overte.git
synced 2025-04-22 03:04:33 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into new_voxel_scene_stats
Conflicts: interface/src/Application.cpp
This commit is contained in:
commit
19515c80fd
43 changed files with 631 additions and 374 deletions
|
@ -71,6 +71,9 @@ We have successfully built on OS X 10.8, Ubuntu and a few other modern Linux
|
|||
distributions. A Windows build is planned for the future, but not currently in
|
||||
development.
|
||||
|
||||
On a fresh Ubuntu 13.10 install, these are all the packages you need to grab and build the hifi project:
|
||||
<pre>sudo apt-get install build-essential cmake git libcurl4-openssl-dev libqt5scripttools5 libqt5svg5-dev libqt5webkit5-dev libqt5location5 qtlocation5-dev qtdeclarative5-dev qtscript5-dev qtsensors5-dev qtmultimedia5-dev qtquick1-5-dev libasound2 libxmu-dev libxi-dev freeglut3-dev libasound2-dev libjack-dev</pre>
|
||||
|
||||
Running Interface
|
||||
-----
|
||||
|
||||
|
@ -147,4 +150,4 @@ To access your local domain in Interface, open your Preferences -- on OS X this
|
|||
If everything worked you should see "Servers: 3" in the upper right. Nice work!
|
||||
|
||||
In the voxel-server/src directory you will find a README that explains in
|
||||
further detail how to setup and administer a voxel-server.
|
||||
further detail how to setup and administer a voxel-server.
|
||||
|
|
|
@ -29,7 +29,11 @@ link_hifi_library(voxel-server-library ${TARGET_NAME} ${ROOT_DIR})
|
|||
|
||||
include_directories(${ROOT_DIR}/externals/civetweb/include)
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS})
|
||||
endif (UNIX)
|
||||
|
||||
# link curl for synchronous script downloads
|
||||
find_package(CURL REQUIRED)
|
||||
include_directories(${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY})
|
||||
target_link_libraries(${TARGET_NAME} ${CURL_LIBRARY})
|
||||
|
|
|
@ -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,33 +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 && audioMixer->getActiveSocket() && 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 (audioMixer && !audioMixer->getActiveSocket()) {
|
||||
// don't have an active socket for the audio-mixer, ping it now
|
||||
NodeList::getInstance()->pingPublicAndLocalSocketsForInactiveNode(audioMixer);
|
||||
}
|
||||
|
||||
if (voxelScripter.getVoxelPacketSender()->voxelServersExist()) {
|
||||
timeval thisSend = {};
|
||||
gettimeofday(&thisSend, NULL);
|
||||
// allow the scripter's call back to setup visual data
|
||||
emit willSendVisualDataCallback();
|
||||
|
||||
|
@ -193,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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -124,6 +124,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_isHoverVoxel(false),
|
||||
_isHoverVoxelSounding(false),
|
||||
_mouseVoxelScale(1.0f / 1024.0f),
|
||||
_mouseVoxelScaleInitialized(false),
|
||||
_justEditedVoxel(false),
|
||||
_nudgeStarted(false),
|
||||
_lookingAlongX(false),
|
||||
|
@ -1782,7 +1783,7 @@ void Application::shrinkMirrorView() {
|
|||
}
|
||||
|
||||
const float MAX_AVATAR_EDIT_VELOCITY = 1.0f;
|
||||
const float MAX_VOXEL_EDIT_DISTANCE = 20.0f;
|
||||
const float MAX_VOXEL_EDIT_DISTANCE = 50.0f;
|
||||
const float HEAD_SPHERE_RADIUS = 0.07;
|
||||
|
||||
static QUuid DEFAULT_NODE_ID_REF;
|
||||
|
@ -1987,8 +1988,8 @@ void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3&
|
|||
// deflect using Faceshift gaze data
|
||||
glm::vec3 origin = _myAvatar.getHead().calculateAverageEyePosition();
|
||||
float pitchSign = (_myCamera.getMode() == CAMERA_MODE_MIRROR) ? -1.0f : 1.0f;
|
||||
const float PITCH_SCALE = 0.5f;
|
||||
const float YAW_SCALE = 0.5f;
|
||||
const float PITCH_SCALE = 0.25f;
|
||||
const float YAW_SCALE = 0.25f;
|
||||
lookAtSpot = origin + _myCamera.getRotation() * glm::quat(glm::radians(glm::vec3(
|
||||
_faceshift.getEstimatedEyePitch() * pitchSign * PITCH_SCALE, _faceshift.getEstimatedEyeYaw() * YAW_SCALE, 0.0f))) *
|
||||
glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin);
|
||||
|
@ -2051,6 +2052,8 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()");
|
||||
|
||||
_mouseVoxel.s = 0.0f;
|
||||
bool wasInitialized = _mouseVoxelScaleInitialized;
|
||||
_mouseVoxelScaleInitialized = false;
|
||||
if (Menu::getInstance()->isVoxelModeActionChecked() &&
|
||||
(fabs(_myAvatar.getVelocity().x) +
|
||||
fabs(_myAvatar.getVelocity().y) +
|
||||
|
@ -2058,6 +2061,12 @@ void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin,
|
|||
|
||||
if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) {
|
||||
if (distance < MAX_VOXEL_EDIT_DISTANCE) {
|
||||
// set the voxel scale to that of the first moused-over voxel
|
||||
if (!wasInitialized) {
|
||||
_mouseVoxelScale = _mouseVoxel.s;
|
||||
}
|
||||
_mouseVoxelScaleInitialized = true;
|
||||
|
||||
// find the nearest voxel with the desired scale
|
||||
if (_mouseVoxelScale > _mouseVoxel.s) {
|
||||
// choose the larger voxel that encompasses the one selected
|
||||
|
@ -2990,6 +2999,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
glDisable(GL_LIGHTING);
|
||||
glPushMatrix();
|
||||
glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE);
|
||||
const float CUBE_EXPANSION = 1.01f;
|
||||
if (_nudgeStarted) {
|
||||
renderNudgeGuide(_nudgeGuidePosition.x, _nudgeGuidePosition.y, _nudgeGuidePosition.z, _nudgeVoxel.s);
|
||||
renderNudgeGrid(_nudgeVoxel.x, _nudgeVoxel.y, _nudgeVoxel.z, _nudgeVoxel.s, _mouseVoxel.s);
|
||||
|
@ -2999,7 +3009,7 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
_nudgeVoxel.z + _nudgeVoxel.s * 0.5f);
|
||||
glColor3ub(255, 255, 255);
|
||||
glLineWidth(4.0f);
|
||||
glutWireCube(_nudgeVoxel.s);
|
||||
glutWireCube(_nudgeVoxel.s * CUBE_EXPANSION);
|
||||
glPopMatrix();
|
||||
} else {
|
||||
renderMouseVoxelGrid(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s);
|
||||
|
@ -3018,13 +3028,13 @@ void Application::displaySide(Camera& whichCamera, bool selfAvatarOnly) {
|
|||
_nudgeGuidePosition.y + _nudgeVoxel.s*0.5f,
|
||||
_nudgeGuidePosition.z + _nudgeVoxel.s*0.5f);
|
||||
glLineWidth(4.0f);
|
||||
glutWireCube(_nudgeVoxel.s);
|
||||
glutWireCube(_nudgeVoxel.s * CUBE_EXPANSION);
|
||||
} else {
|
||||
glTranslatef(_mouseVoxel.x + _mouseVoxel.s*0.5f,
|
||||
_mouseVoxel.y + _mouseVoxel.s*0.5f,
|
||||
_mouseVoxel.z + _mouseVoxel.s*0.5f);
|
||||
glLineWidth(4.0f);
|
||||
glutWireCube(_mouseVoxel.s);
|
||||
glutWireCube(_mouseVoxel.s * CUBE_EXPANSION);
|
||||
}
|
||||
glLineWidth(1.0f);
|
||||
glPopMatrix();
|
||||
|
@ -4105,11 +4115,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);
|
||||
}
|
||||
|
||||
// we should remove it...
|
||||
_voxelServerJurisdictions.erase(nodeUUID);
|
||||
|
@ -4165,11 +4177,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
|
||||
|
|
|
@ -378,6 +378,7 @@ private:
|
|||
|
||||
VoxelDetail _mouseVoxel; // details of the voxel to be edited
|
||||
float _mouseVoxelScale; // the scale for adding/removing voxels
|
||||
bool _mouseVoxelScaleInitialized;
|
||||
glm::vec3 _lastMouseVoxelPos; // the position of the last mouse voxel edit
|
||||
bool _justEditedVoxel; // set when we've just added/deleted/colored a voxel
|
||||
|
||||
|
|
|
@ -8,18 +8,21 @@
|
|||
|
||||
#include <cstdlib>
|
||||
|
||||
#include <QMenuBar>
|
||||
|
||||
#include <QBoxLayout>
|
||||
#include <QColorDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFileDialog>
|
||||
#include <QFormLayout>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QMainWindow>
|
||||
#include <QMenuBar>
|
||||
#include <QSlider>
|
||||
#include <QStandardPaths>
|
||||
#include <QUuid>
|
||||
#include <QWindow>
|
||||
|
||||
#include <UUID.h>
|
||||
|
||||
|
@ -280,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");
|
||||
|
@ -324,6 +328,7 @@ Menu::Menu() :
|
|||
false,
|
||||
appInstance->getFaceshift(),
|
||||
SLOT(setTCPEnabled(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(avatarOptionsMenu, MenuOption::ChatCircling, 0, true);
|
||||
|
||||
QMenu* webcamOptionsMenu = developerMenu->addMenu("Webcam Options");
|
||||
|
||||
|
@ -715,73 +720,43 @@ 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;
|
||||
|
||||
|
||||
QLineEdit* lineEditForDomainHostname() {
|
||||
QString currentDomainHostname = NodeList::getInstance()->getDomainHostname();
|
||||
|
||||
if (NodeList::getInstance()->getDomainPort() != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
// add the port to the currentDomainHostname string if it is custom
|
||||
currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainPort()));
|
||||
}
|
||||
|
||||
QLineEdit* domainServerLineEdit = new QLineEdit(currentDomainHostname);
|
||||
domainServerLineEdit->setPlaceholderText(DEFAULT_DOMAIN_HOSTNAME);
|
||||
domainServerLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
|
||||
return domainServerLineEdit;
|
||||
}
|
||||
|
||||
const float DIALOG_RATIO_OF_WINDOW = 0.30;
|
||||
|
||||
void Menu::login() {
|
||||
Application* applicationInstance = Application::getInstance();
|
||||
QDialog dialog;
|
||||
dialog.setWindowTitle("Login");
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
QInputDialog loginDialog(Application::getInstance()->getWindow());
|
||||
loginDialog.setWindowTitle("Login");
|
||||
loginDialog.setLabelText("Username:");
|
||||
QString username = Application::getInstance()->getProfile()->getUsername();
|
||||
loginDialog.setTextValue(username);
|
||||
loginDialog.setWindowFlags(Qt::Sheet);
|
||||
loginDialog.resize(loginDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, loginDialog.size().height());
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
int dialogReturn = loginDialog.exec();
|
||||
|
||||
QString username = applicationInstance->getProfile()->getUsername();
|
||||
QLineEdit* usernameLineEdit = new QLineEdit(username);
|
||||
usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Username:", usernameLineEdit);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
layout->addWidget(buttons);
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (usernameLineEdit->text() != username) {
|
||||
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
|
||||
applicationInstance->resetProfile(usernameLineEdit->text());
|
||||
Application::getInstance()->resetProfile(loginDialog.textValue());
|
||||
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::editPreferences() {
|
||||
Application* applicationInstance = Application::getInstance();
|
||||
|
||||
QDialog dialog;
|
||||
QDialog dialog(applicationInstance->getWindow());
|
||||
dialog.setWindowTitle("Interface Preferences");
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
|
@ -839,119 +814,107 @@ 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() {
|
||||
QDialog dialog;
|
||||
dialog.setWindowTitle("Go To Domain");
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
QString currentDomainHostname = NodeList::getInstance()->getDomainHostname();
|
||||
|
||||
QLineEdit* domainServerLineEdit = lineEditForDomainHostname();
|
||||
form->addRow("Domain server:", domainServerLineEdit);
|
||||
if (NodeList::getInstance()->getDomainPort() != DEFAULT_DOMAIN_SERVER_PORT) {
|
||||
// add the port to the currentDomainHostname string if it is custom
|
||||
currentDomainHostname.append(QString(":%1").arg(NodeList::getInstance()->getDomainPort()));
|
||||
}
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
layout->addWidget(buttons);
|
||||
QInputDialog domainDialog(Application::getInstance()->getWindow());
|
||||
domainDialog.setWindowTitle("Go to Domain");
|
||||
domainDialog.setLabelText("Domain server:");
|
||||
domainDialog.setTextValue(currentDomainHostname);
|
||||
domainDialog.setWindowFlags(Qt::Sheet);
|
||||
domainDialog.resize(domainDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, domainDialog.size().height());
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
int dialogReturn = domainDialog.exec();
|
||||
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());
|
||||
}
|
||||
|
||||
updateDSHostname(domainServerLineEdit->text());
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToLocation() {
|
||||
QDialog dialog;
|
||||
dialog.setWindowTitle("Go To Location");
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
const int QLINE_MINIMUM_WIDTH = 300;
|
||||
|
||||
Application* applicationInstance = Application::getInstance();
|
||||
MyAvatar* myAvatar = applicationInstance->getAvatar();
|
||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||
glm::vec3 avatarPos = myAvatar->getPosition();
|
||||
QString currentLocation = QString("%1, %2, %3").arg(QString::number(avatarPos.x),
|
||||
QString::number(avatarPos.y), QString::number(avatarPos.z));
|
||||
|
||||
QLineEdit* coordinates = new QLineEdit(currentLocation);
|
||||
coordinates->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Coordinates as x,y,z:", coordinates);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
layout->addWidget(buttons);
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
QByteArray newCoordinates;
|
||||
|
||||
if (coordinates->text().size() > 0) {
|
||||
// the user input a new hostname, use that
|
||||
QString currentLocation = QString("%1, %2, %3").arg(QString::number(avatarPos.x),
|
||||
QString::number(avatarPos.y), QString::number(avatarPos.z));
|
||||
|
||||
|
||||
QInputDialog coordinateDialog(Application::getInstance()->getWindow());
|
||||
coordinateDialog.setWindowTitle("Go to Location");
|
||||
coordinateDialog.setLabelText("Coordinate as x,y,z:");
|
||||
coordinateDialog.setTextValue(currentLocation);
|
||||
coordinateDialog.setWindowFlags(Qt::Sheet);
|
||||
coordinateDialog.resize(coordinateDialog.parentWidget()->size().width() * 0.30, coordinateDialog.size().height());
|
||||
|
||||
int dialogReturn = coordinateDialog.exec();
|
||||
if (dialogReturn == QDialog::Accepted && !coordinateDialog.textValue().isEmpty()) {
|
||||
QByteArray newCoordinates;
|
||||
|
||||
QString delimiterPattern(",");
|
||||
QStringList coordinateItems = coordinates->text().split(delimiterPattern);
|
||||
|
||||
QStringList coordinateItems = coordinateDialog.textValue().split(delimiterPattern);
|
||||
|
||||
const int NUMBER_OF_COORDINATE_ITEMS = 3;
|
||||
const int X_ITEM = 0;
|
||||
const int Y_ITEM = 1;
|
||||
|
@ -968,36 +931,27 @@ void Menu::goToLocation() {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToUser() {
|
||||
QDialog dialog;
|
||||
dialog.setWindowTitle("Go To User");
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
QInputDialog userDialog(Application::getInstance()->getWindow());
|
||||
userDialog.setWindowTitle("Go to User");
|
||||
userDialog.setLabelText("Destination user:");
|
||||
QString username = Application::getInstance()->getProfile()->getUsername();
|
||||
userDialog.setTextValue(username);
|
||||
userDialog.setWindowFlags(Qt::Sheet);
|
||||
userDialog.resize(userDialog.parentWidget()->size().width() * DIALOG_RATIO_OF_WINDOW, userDialog.size().height());
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
QLineEdit* usernameLineEdit = new QLineEdit();
|
||||
usernameLineEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("", usernameLineEdit);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
layout->addWidget(buttons);
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!usernameLineEdit->text().isEmpty()) {
|
||||
int dialogReturn = userDialog.exec();
|
||||
if (dialogReturn == QDialog::Accepted && !userDialog.textValue().isEmpty()) {
|
||||
// there's a username entered by the user, make a request to the data-server
|
||||
DataServerClient::getValuesForKeysAndUserString((QStringList() << DataServerKey::Domain << DataServerKey::Position),
|
||||
usernameLineEdit->text());
|
||||
userDialog.textValue());
|
||||
}
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::bandwidthDetails() {
|
||||
|
|
|
@ -146,6 +146,7 @@ namespace MenuOption {
|
|||
const QString AutomaticallyAuditTree = "Automatically Audit Tree Stats";
|
||||
const QString Bandwidth = "Bandwidth Display";
|
||||
const QString BandwidthDetails = "Bandwidth Details";
|
||||
const QString ChatCircling = "Chat Circling";
|
||||
const QString Collisions = "Collisions";
|
||||
const QString CopyVoxels = "Copy";
|
||||
const QString CoverageMap = "Render Coverage Map";
|
||||
|
@ -164,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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -96,8 +96,6 @@ Avatar::Avatar(Node* owningNode) :
|
|||
_leadingAvatar(NULL),
|
||||
_voxels(this),
|
||||
_moving(false),
|
||||
_hoverOnDuration(0.0f),
|
||||
_hoverOffDuration(0.0f),
|
||||
_initialized(false),
|
||||
_handHoldingPosition(0.0f, 0.0f, 0.0f),
|
||||
_maxArmLength(0.0f),
|
||||
|
@ -257,6 +255,11 @@ Avatar::~Avatar() {
|
|||
delete _balls;
|
||||
}
|
||||
|
||||
void Avatar::deleteOrDeleteLater() {
|
||||
this->deleteLater();
|
||||
}
|
||||
|
||||
|
||||
void Avatar::init() {
|
||||
_head.init();
|
||||
_hand.init();
|
||||
|
@ -387,30 +390,6 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) {
|
|||
}
|
||||
}
|
||||
|
||||
// head scale grows when avatar is looked at
|
||||
const float BASE_MAX_SCALE = 3.0f;
|
||||
float maxScale = BASE_MAX_SCALE * glm::distance(_position, Application::getInstance()->getCamera()->getPosition());
|
||||
if (Application::getInstance()->getLookatTargetAvatar() == this) {
|
||||
_hoverOnDuration += deltaTime;
|
||||
_hoverOffDuration = 0.0f;
|
||||
|
||||
const float GROW_DELAY = 1.0f;
|
||||
const float GROW_RATE = 0.25f;
|
||||
if (_hoverOnDuration > GROW_DELAY) {
|
||||
_head.setScale(glm::mix(_head.getScale(), maxScale, GROW_RATE));
|
||||
}
|
||||
|
||||
} else {
|
||||
_hoverOnDuration = 0.0f;
|
||||
_hoverOffDuration += deltaTime;
|
||||
|
||||
const float SHRINK_DELAY = 1.0f;
|
||||
const float SHRINK_RATE = 0.25f;
|
||||
if (_hoverOffDuration > SHRINK_DELAY) {
|
||||
_head.setScale(glm::mix(_head.getScale(), 1.0f, SHRINK_RATE));
|
||||
}
|
||||
}
|
||||
|
||||
_skeletonModel.simulate(deltaTime);
|
||||
_head.setBodyRotation(glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll));
|
||||
glm::vec3 headPosition;
|
||||
|
|
|
@ -134,6 +134,7 @@ public:
|
|||
|
||||
Avatar(Node* owningNode = NULL);
|
||||
~Avatar();
|
||||
void deleteOrDeleteLater();
|
||||
|
||||
void init();
|
||||
void simulate(float deltaTime, Transmitter* transmitter);
|
||||
|
@ -227,8 +228,6 @@ protected:
|
|||
AvatarVoxelSystem _voxels;
|
||||
|
||||
bool _moving; ///< set when position is changing
|
||||
float _hoverOnDuration;
|
||||
float _hoverOffDuration;
|
||||
|
||||
// protected methods...
|
||||
glm::vec3 getBodyRightDirection() const { return getOrientation() * IDENTITY_RIGHT; }
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
#include "Application.h"
|
||||
#include "DataServerClient.h"
|
||||
#include "Menu.h"
|
||||
#include "MyAvatar.h"
|
||||
#include "Physics.h"
|
||||
#include "devices/OculusManager.h"
|
||||
|
@ -830,6 +831,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
|
|||
// reset hand and arm positions according to hand movement
|
||||
glm::vec3 up = orientation * IDENTITY_UP;
|
||||
|
||||
bool pointing = false;
|
||||
if (enableHandMovement && glm::length(_mouseRayDirection) > EPSILON && !Application::getInstance()->isMouseHidden()) {
|
||||
// confine to the approximate shoulder plane
|
||||
glm::vec3 pointDirection = _mouseRayDirection;
|
||||
|
@ -841,6 +843,7 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
|
|||
}
|
||||
const float FAR_AWAY_POINT = TREE_SCALE;
|
||||
_skeleton.joint[AVATAR_JOINT_RIGHT_FINGERTIPS].position = _mouseRayOrigin + pointDirection * FAR_AWAY_POINT;
|
||||
pointing = true;
|
||||
}
|
||||
|
||||
_avatarTouch.setMyBodyPosition(_position);
|
||||
|
@ -932,6 +935,8 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
|
|||
|
||||
if (_mousePressed) {
|
||||
_handState = HAND_STATE_GRASPING;
|
||||
} else if (pointing) {
|
||||
_handState = HAND_STATE_POINTING;
|
||||
} else {
|
||||
_handState = HAND_STATE_NULL;
|
||||
}
|
||||
|
@ -1059,6 +1064,11 @@ void MyAvatar::updateAvatarCollisions(float deltaTime) {
|
|||
// detect collisions with other avatars and respond
|
||||
void MyAvatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) {
|
||||
|
||||
// for now, don't collide if we have a new skeleton
|
||||
if (_skeletonModel.isActive()) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f);
|
||||
|
||||
// loop through the body balls of each avatar to check for every possible collision
|
||||
|
@ -1110,6 +1120,10 @@ bool operator<(const SortedAvatar& s1, const SortedAvatar& s2) {
|
|||
}
|
||||
|
||||
void MyAvatar::updateChatCircle(float deltaTime) {
|
||||
if (!Menu::getInstance()->isOptionChecked(MenuOption::ChatCircling)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// find all members and sort by distance
|
||||
QVector<SortedAvatar> sortedAvatars;
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
|
|
@ -28,7 +28,12 @@ void SkeletonModel::simulate(float deltaTime) {
|
|||
|
||||
Model::simulate(deltaTime);
|
||||
|
||||
setRightHandPosition(_owningAvatar->getHandPosition());
|
||||
if (_owningAvatar->getHandState() == HAND_STATE_NULL) {
|
||||
const float HAND_RESTORATION_RATE = 0.25f;
|
||||
restoreRightHandPosition(HAND_RESTORATION_RATE);
|
||||
} else {
|
||||
setRightHandPosition(_owningAvatar->getHandPosition());
|
||||
}
|
||||
}
|
||||
|
||||
bool SkeletonModel::render(float alpha) {
|
||||
|
|
|
@ -68,7 +68,7 @@ void Faceshift::update() {
|
|||
(_eyeGazeLeftPitch + _eyeGazeRightPitch) / 2.0f, (_eyeGazeLeftYaw + _eyeGazeRightYaw) / 2.0f, 0.0f))));
|
||||
|
||||
// compute and subtract the long term average
|
||||
const float LONG_TERM_AVERAGE_SMOOTHING = 0.9999f;
|
||||
const float LONG_TERM_AVERAGE_SMOOTHING = 0.999f;
|
||||
if (!_longTermAverageInitialized) {
|
||||
_longTermAverageEyePitch = eulers.x;
|
||||
_longTermAverageEyeYaw = eulers.y;
|
||||
|
|
|
@ -477,6 +477,10 @@ bool Model::setLeftHandPosition(const glm::vec3& position) {
|
|||
return isActive() && setJointPosition(_geometry->getFBXGeometry().leftHandJointIndex, position);
|
||||
}
|
||||
|
||||
bool Model::restoreLeftHandPosition(float percent) {
|
||||
return isActive() && restoreJointPosition(_geometry->getFBXGeometry().leftHandJointIndex, percent);
|
||||
}
|
||||
|
||||
bool Model::setLeftHandRotation(const glm::quat& rotation) {
|
||||
return isActive() && setJointRotation(_geometry->getFBXGeometry().leftHandJointIndex, rotation);
|
||||
}
|
||||
|
@ -485,6 +489,10 @@ bool Model::setRightHandPosition(const glm::vec3& position) {
|
|||
return isActive() && setJointPosition(_geometry->getFBXGeometry().rightHandJointIndex, position);
|
||||
}
|
||||
|
||||
bool Model::restoreRightHandPosition(float percent) {
|
||||
return isActive() && restoreJointPosition(_geometry->getFBXGeometry().rightHandJointIndex, percent);
|
||||
}
|
||||
|
||||
bool Model::setRightHandRotation(const glm::quat& rotation) {
|
||||
return isActive() && setJointRotation(_geometry->getFBXGeometry().rightHandJointIndex, rotation);
|
||||
}
|
||||
|
@ -617,6 +625,19 @@ bool Model::setJointRotation(int jointIndex, const glm::quat& rotation) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Model::restoreJointPosition(int jointIndex, float percent) {
|
||||
if (jointIndex == -1 || _jointStates.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const QVector<int>& freeLineage = geometry.joints.at(jointIndex).freeLineage;
|
||||
|
||||
foreach (int index, freeLineage) {
|
||||
_jointStates[index].rotation = safeMix(_jointStates[index].rotation, geometry.joints.at(index).rotation, percent);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Model::deleteGeometry() {
|
||||
foreach (Model* attachment, _attachments) {
|
||||
delete attachment;
|
||||
|
|
|
@ -74,6 +74,11 @@ public:
|
|||
/// \return whether or not the left hand joint was found
|
||||
bool setLeftHandPosition(const glm::vec3& position);
|
||||
|
||||
/// Restores some percentage of the default position of the left hand.
|
||||
/// \param percent the percentage of the default position to restore
|
||||
/// \return whether or not the left hand joint was found
|
||||
bool restoreLeftHandPosition(float percent = 1.0f);
|
||||
|
||||
/// Sets the rotation of the left hand.
|
||||
/// \return whether or not the left hand joint was found
|
||||
bool setLeftHandRotation(const glm::quat& rotation);
|
||||
|
@ -82,6 +87,11 @@ public:
|
|||
/// \return whether or not the right hand joint was found
|
||||
bool setRightHandPosition(const glm::vec3& position);
|
||||
|
||||
/// Restores some percentage of the default position of the right hand.
|
||||
/// \param percent the percentage of the default position to restore
|
||||
/// \return whether or not the right hand joint was found
|
||||
bool restoreRightHandPosition(float percent = 1.0f);
|
||||
|
||||
/// Sets the rotation of the right hand.
|
||||
/// \return whether or not the right hand joint was found
|
||||
bool setRightHandRotation(const glm::quat& rotation);
|
||||
|
@ -130,6 +140,12 @@ protected:
|
|||
bool setJointPosition(int jointIndex, const glm::vec3& position);
|
||||
bool setJointRotation(int jointIndex, const glm::quat& rotation);
|
||||
|
||||
/// Restores the indexed joint to its default position.
|
||||
/// \param percent the percentage of the default position to apply (i.e., 0.25f to slerp one fourth of the way to
|
||||
/// the original position
|
||||
/// \return true if the joint was found
|
||||
bool restoreJointPosition(int jointIndex, float percent = 1.0f);
|
||||
|
||||
private:
|
||||
|
||||
void deleteGeometry();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -687,13 +687,10 @@ unsigned NodeList::broadcastToNodes(unsigned char* broadcastData, size_t dataByt
|
|||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
// only send to the NodeTypes we are asked to send to.
|
||||
if (memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
||||
if (node->getActiveSocket()) {
|
||||
if (getNodeActiveSocketOrPing(&(*node))) {
|
||||
// we know which socket is good for this node, send there
|
||||
_nodeSocket.send(node->getActiveSocket(), broadcastData, dataBytes);
|
||||
++n;
|
||||
} else {
|
||||
// we don't have an active link to this node, ping it to set that up
|
||||
pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -718,6 +715,15 @@ void NodeList::possiblyPingInactiveNodes() {
|
|||
}
|
||||
}
|
||||
|
||||
sockaddr* NodeList::getNodeActiveSocketOrPing(Node* node) {
|
||||
if (node->getActiveSocket()) {
|
||||
return node->getActiveSocket();
|
||||
} else {
|
||||
pingPublicAndLocalSocketsForInactiveNode(node);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void NodeList::activateSocketFromNodeCommunication(sockaddr *nodeAddress) {
|
||||
for(NodeList::iterator node = begin(); node != end(); node++) {
|
||||
if (!node->getActiveSocket()) {
|
||||
|
|
|
@ -141,6 +141,7 @@ public:
|
|||
void removeDomainListener(DomainChangeListener* listener);
|
||||
|
||||
void possiblyPingInactiveNodes();
|
||||
sockaddr* getNodeActiveSocketOrPing(Node* node);
|
||||
private:
|
||||
static NodeList* _sharedInstance;
|
||||
|
||||
|
|
|
@ -16,10 +16,15 @@
|
|||
#include "SharedUtil.h"
|
||||
#include "OctalCode.h"
|
||||
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode) {
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes) {
|
||||
if (maxBytes == OVERFLOWED_OCTCODE_BUFFER) {
|
||||
return OVERFLOWED_OCTCODE_BUFFER;
|
||||
}
|
||||
|
||||
assert(octalCode);
|
||||
if (*octalCode == 255) {
|
||||
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1);
|
||||
int newMaxBytes = (maxBytes == UNKNOWN_OCTCODE_LENGTH) ? UNKNOWN_OCTCODE_LENGTH : maxBytes - 1;
|
||||
return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1, newMaxBytes);
|
||||
} else {
|
||||
return *octalCode;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,15 @@ void printOctalCode(const unsigned char* octalCode);
|
|||
int bytesRequiredForCodeLength(unsigned char threeBitCodes);
|
||||
int branchIndexWithDescendant(const unsigned char* ancestorOctalCode, const unsigned char* descendantOctalCode);
|
||||
unsigned char* childOctalCode(const unsigned char* parentOctalCode, char childNumber);
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode);
|
||||
|
||||
const int OVERFLOWED_OCTCODE_BUFFER = -1;
|
||||
const int UNKNOWN_OCTCODE_LENGTH = -2;
|
||||
|
||||
/// will return -1 if there is an error in the octcode encoding, or it would overflow maxBytes
|
||||
/// \param const unsigned char* octalCode the octalcode to decode
|
||||
/// \param int maxBytes number of bytes that octalCode is expected to be, -1 if unknown
|
||||
int numberOfThreeBitSectionsInCode(const unsigned char* octalCode, int maxBytes = UNKNOWN_OCTCODE_LENGTH);
|
||||
|
||||
unsigned char* chopOctalCode(const unsigned char* originalOctalCode, int chopLevels);
|
||||
unsigned char* rebaseOctalCode(const unsigned char* originalOctalCode, const unsigned char* newParentOctalCode,
|
||||
bool includeColorSpace = false);
|
||||
|
|
|
@ -91,23 +91,23 @@ bool PacketSender::process() {
|
|||
while (keepGoing) {
|
||||
uint64_t SEND_INTERVAL_USECS = (_packetsPerSecond == 0) ? USECS_PER_SECOND : (USECS_PER_SECOND / _packetsPerSecond);
|
||||
|
||||
lock();
|
||||
NetworkPacket& packet = _packets.front();
|
||||
|
||||
NetworkPacket temporary = packet; // make a copy
|
||||
_packets.erase(_packets.begin());
|
||||
packetsLeft = _packets.size();
|
||||
unlock();
|
||||
|
||||
// send the packet through the NodeList...
|
||||
UDPSocket* nodeSocket = NodeList::getInstance()->getNodeSocket();
|
||||
|
||||
nodeSocket->send(&packet.getAddress(), packet.getData(), packet.getLength());
|
||||
nodeSocket->send(&temporary.getAddress(), temporary.getData(), temporary.getLength());
|
||||
packetsThisCall++;
|
||||
|
||||
if (_notify) {
|
||||
_notify->packetSentNotification(packet.getLength());
|
||||
_notify->packetSentNotification(temporary.getLength());
|
||||
}
|
||||
|
||||
lock();
|
||||
_packets.erase(_packets.begin());
|
||||
unlock();
|
||||
|
||||
packetsLeft = _packets.size();
|
||||
|
||||
// in threaded mode, we go till we're empty
|
||||
if (isThreaded()) {
|
||||
|
|
|
@ -31,12 +31,13 @@ bool ReceivedPacketProcessor::process() {
|
|||
usleep(RECEIVED_THREAD_SLEEP_INTERVAL);
|
||||
}
|
||||
while (_packets.size() > 0) {
|
||||
NetworkPacket& packet = _packets.front();
|
||||
processPacket(packet.getAddress(), packet.getData(), packet.getLength());
|
||||
|
||||
lock();
|
||||
_packets.erase(_packets.begin());
|
||||
unlock();
|
||||
lock(); // lock to make sure nothing changes on us
|
||||
NetworkPacket& packet = _packets.front(); // get the oldest packet
|
||||
NetworkPacket temporary = packet; // make a copy of the packet in case the vector is resized on us
|
||||
_packets.erase(_packets.begin()); // remove the oldest packet
|
||||
unlock(); // let others add to the packets
|
||||
processPacket(temporary.getAddress(), temporary.getData(), temporary.getLength()); // process our temporary copy
|
||||
}
|
||||
return isStillRunning(); // keep running till they terminate us
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
@ -112,12 +118,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
|
||||
}
|
||||
|
||||
|
@ -113,8 +125,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;
|
||||
|
@ -285,10 +295,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);
|
||||
|
@ -356,8 +369,6 @@ int VoxelSendThread::deepestLevelVoxelDistributor(Node* node, VoxelNodeData* nod
|
|||
|
||||
} // end if bag wasn't empty, and so we sent stuff...
|
||||
|
||||
_myServer->unlockTree();
|
||||
|
||||
return truePacketsSent;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <time.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QString>
|
||||
|
@ -45,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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -71,7 +76,10 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assign
|
|||
_voxelServerPacketProcessor = NULL;
|
||||
_voxelPersistThread = NULL;
|
||||
_parsedArgV = NULL;
|
||||
|
||||
|
||||
_started = time(0);
|
||||
_startedUSecs = usecTimestampNow();
|
||||
|
||||
_theInstance = this;
|
||||
}
|
||||
|
||||
|
@ -106,6 +114,19 @@ void VoxelServer::initMongoose(int port) {
|
|||
|
||||
int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
|
||||
const struct mg_request_info* ri = mg_get_request_info(connection);
|
||||
|
||||
#ifdef FORCE_CRASH
|
||||
if (strcmp(ri->uri, "/force_crash") == 0 && strcmp(ri->request_method, "GET") == 0) {
|
||||
qDebug() << "About to force a crash!\n";
|
||||
int foo;
|
||||
int* forceCrash = &foo;
|
||||
mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n");
|
||||
mg_printf(connection, "%s", "forcing a crash....\r\n");
|
||||
delete[] forceCrash;
|
||||
mg_printf(connection, "%s", "did it crash....\r\n");
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) {
|
||||
uint64_t checkSum;
|
||||
|
@ -114,6 +135,86 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) {
|
|||
mg_printf(connection, "%s", "Your Voxel Server is running.\r\n");
|
||||
|
||||
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
tm* localtm = localtime(&GetInstance()->_started);
|
||||
const int MAX_TIME_LENGTH = 128;
|
||||
char buffer[MAX_TIME_LENGTH];
|
||||
strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm);
|
||||
mg_printf(connection, "Running since: %s", buffer);
|
||||
|
||||
// Convert now to tm struct for UTC
|
||||
tm* gmtm = gmtime(&GetInstance()->_started);
|
||||
if (gmtm != NULL) {
|
||||
strftime(buffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", gmtm);
|
||||
mg_printf(connection, " [%s UTM] ", buffer);
|
||||
}
|
||||
mg_printf(connection, "%s", "\r\n");
|
||||
|
||||
uint64_t now = usecTimestampNow();
|
||||
const int USECS_PER_MSEC = 1000;
|
||||
uint64_t msecsElapsed = (now - GetInstance()->_startedUSecs) / USECS_PER_MSEC;
|
||||
const int MSECS_PER_SEC = 1000;
|
||||
const int SECS_PER_MIN = 60;
|
||||
const int MIN_PER_HOUR = 60;
|
||||
const int MSECS_PER_MIN = MSECS_PER_SEC * SECS_PER_MIN;
|
||||
|
||||
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", "Uptime: ");
|
||||
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");
|
||||
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 ");
|
||||
|
@ -283,8 +384,6 @@ void VoxelServer::run() {
|
|||
parsePayload();
|
||||
}
|
||||
|
||||
pthread_mutex_init(&_treeLock, NULL);
|
||||
|
||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
||||
|
||||
const char* STATUS_PORT = "--statusPort";
|
||||
|
@ -438,12 +537,24 @@ void VoxelServer::run() {
|
|||
_voxelServerPacketProcessor->initialize(true);
|
||||
}
|
||||
|
||||
qDebug("Now running...\n");
|
||||
// Convert now to tm struct for local timezone
|
||||
tm* localtm = localtime(&_started);
|
||||
const int MAX_TIME_LENGTH = 128;
|
||||
char localBuffer[MAX_TIME_LENGTH] = { 0 };
|
||||
char utcBuffer[MAX_TIME_LENGTH] = { 0 };
|
||||
strftime(localBuffer, MAX_TIME_LENGTH, "%m/%d/%Y %X", localtm);
|
||||
// Convert now to tm struct for UTC
|
||||
tm* gmtm = gmtime(&_started);
|
||||
if (gmtm != NULL) {
|
||||
strftime(utcBuffer, MAX_TIME_LENGTH, " [%m/%d/%Y %X UTC]", gmtm);
|
||||
}
|
||||
qDebug() << "Now running... started at: " << localBuffer << utcBuffer << "\n";
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
@ -499,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";
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define __voxel_server__VoxelServer__
|
||||
|
||||
#include <QStringList>
|
||||
#include <QDateTime>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <Assignment.h>
|
||||
|
@ -47,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]; }
|
||||
|
@ -58,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;
|
||||
|
@ -79,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
|
||||
|
@ -91,6 +91,8 @@ private:
|
|||
static int civetwebRequestHandler(struct mg_connection *connection);
|
||||
static VoxelServer* _theInstance;
|
||||
|
||||
time_t _started;
|
||||
uint64_t _startedUSecs;
|
||||
};
|
||||
|
||||
#endif // __voxel_server__VoxelServer__
|
||||
|
|
|
@ -24,6 +24,12 @@ VoxelServerPacketProcessor::VoxelServerPacketProcessor(VoxelServer* myServer) :
|
|||
|
||||
void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
|
||||
|
||||
bool debugProcessPacket = _myServer->wantsDebugVoxelReceiving();
|
||||
|
||||
if (debugProcessPacket) {
|
||||
printf("VoxelServerPacketProcessor::processPacket(() packetData=%p packetLength=%ld\n", packetData, packetLength);
|
||||
}
|
||||
|
||||
int numBytesPacketHeader = numBytesForPacketHeader(packetData);
|
||||
|
||||
if (packetData[0] == PACKET_TYPE_SET_VOXEL || packetData[0] == PACKET_TYPE_SET_VOXEL_DESTRUCTIVE) {
|
||||
|
@ -49,25 +55,54 @@ void VoxelServerPacketProcessor::processPacket(sockaddr& senderAddress, unsigned
|
|||
int atByte = numBytesPacketHeader + sizeof(itemNumber);
|
||||
unsigned char* voxelData = (unsigned char*)&packetData[atByte];
|
||||
while (atByte < packetLength) {
|
||||
unsigned char octets = (unsigned char)*voxelData;
|
||||
int maxSize = packetLength - atByte;
|
||||
|
||||
if (debugProcessPacket) {
|
||||
printf("VoxelServerPacketProcessor::processPacket(() %s packetData=%p packetLength=%ld voxelData=%p atByte=%d maxSize=%d\n",
|
||||
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
||||
packetData, packetLength, voxelData, atByte, maxSize);
|
||||
}
|
||||
|
||||
int octets = numberOfThreeBitSectionsInCode(voxelData, maxSize);
|
||||
|
||||
if (octets == OVERFLOWED_OCTCODE_BUFFER) {
|
||||
printf("WARNING! Got voxel edit record that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
|
||||
printf("bailing processing of packet!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
const int COLOR_SIZE_IN_BYTES = 3;
|
||||
int voxelDataSize = bytesRequiredForCodeLength(octets) + COLOR_SIZE_IN_BYTES;
|
||||
int voxelCodeSize = bytesRequiredForCodeLength(octets);
|
||||
|
||||
if (_myServer->wantShowAnimationDebug()) {
|
||||
int red = voxelData[voxelCodeSize + 0];
|
||||
int green = voxelData[voxelCodeSize + 1];
|
||||
int blue = voxelData[voxelCodeSize + 2];
|
||||
if (atByte + voxelDataSize <= packetLength) {
|
||||
if (_myServer->wantShowAnimationDebug()) {
|
||||
int red = voxelData[voxelCodeSize + RED_INDEX];
|
||||
int green = voxelData[voxelCodeSize + GREEN_INDEX];
|
||||
int blue = voxelData[voxelCodeSize + BLUE_INDEX];
|
||||
|
||||
float* vertices = firstVertexForCode(voxelData);
|
||||
printf("inserting voxel: %f,%f,%f r=%d,g=%d,b=%d\n", vertices[0], vertices[1], vertices[2], red, green, blue);
|
||||
delete[] vertices;
|
||||
float* vertices = firstVertexForCode(voxelData);
|
||||
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->getServerTree().lockForWrite();
|
||||
_myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
|
||||
_myServer->getServerTree().unlock();
|
||||
|
||||
// skip to next voxel edit record in the packet
|
||||
voxelData += voxelDataSize;
|
||||
atByte += voxelDataSize;
|
||||
} else {
|
||||
printf("WARNING! Got voxel edit record that would overflow buffer, bailing processing of packet!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
_myServer->getServerTree().readCodeColorBufferToTree(voxelData, destructive);
|
||||
// skip to next
|
||||
voxelData += voxelDataSize;
|
||||
atByte += voxelDataSize;
|
||||
}
|
||||
|
||||
if (debugProcessPacket) {
|
||||
printf("VoxelServerPacketProcessor::processPacket(() DONE LOOPING FOR %s packetData=%p packetLength=%ld voxelData=%p atByte=%d\n",
|
||||
destructive ? "PACKET_TYPE_SET_VOXEL_DESTRUCTIVE" : "PACKET_TYPE_SET_VOXEL",
|
||||
packetData, packetLength, voxelData, atByte);
|
||||
}
|
||||
|
||||
// Make sure our Node and NodeList knows we've heard from this node.
|
||||
|
@ -79,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);
|
||||
|
|
|
@ -46,11 +46,7 @@ bool JurisdictionListener::queueJurisdictionRequest() {
|
|||
|
||||
NodeList* nodeList = NodeList::getInstance();
|
||||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
|
||||
// only send to the NodeTypes that are interested in our jurisdiction details
|
||||
const int numNodeTypes = 1;
|
||||
const NODE_TYPE nodeTypes[numNodeTypes] = { NODE_TYPE_VOXEL_SERVER };
|
||||
if (node->getActiveSocket() != NULL && memchr(nodeTypes, node->getType(), numNodeTypes)) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(&(*node)) && node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
sockaddr* nodeAddress = node->getActiveSocket();
|
||||
PacketSender::queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
|
||||
nodeCount++;
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ void JurisdictionSender::processPacket(sockaddr& senderAddress, unsigned char*
|
|||
if (node) {
|
||||
QUuid nodeUUID = node->getUUID();
|
||||
lockRequestingNodes();
|
||||
_nodesRequestingJurisdictions.insert(nodeUUID);
|
||||
_nodesRequestingJurisdictions.push(nodeUUID);
|
||||
unlockRequestingNodes();
|
||||
}
|
||||
}
|
||||
|
@ -59,18 +59,16 @@ bool JurisdictionSender::process() {
|
|||
int nodeCount = 0;
|
||||
|
||||
lockRequestingNodes();
|
||||
for (std::set<QUuid>::iterator nodeIterator = _nodesRequestingJurisdictions.begin();
|
||||
nodeIterator != _nodesRequestingJurisdictions.end(); nodeIterator++) {
|
||||
while (!_nodesRequestingJurisdictions.empty()) {
|
||||
|
||||
QUuid nodeUUID = *nodeIterator;
|
||||
QUuid nodeUUID = _nodesRequestingJurisdictions.front();
|
||||
_nodesRequestingJurisdictions.pop();
|
||||
Node* node = NodeList::getInstance()->nodeWithUUID(nodeUUID);
|
||||
|
||||
if (node->getActiveSocket() != NULL) {
|
||||
sockaddr* nodeAddress = node->getActiveSocket();
|
||||
queuePacketForSending(*nodeAddress, bufferOut, sizeOut);
|
||||
nodeCount++;
|
||||
// remove it from the set
|
||||
_nodesRequestingJurisdictions.erase(nodeIterator);
|
||||
}
|
||||
}
|
||||
unlockRequestingNodes();
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#ifndef __shared__JurisdictionSender__
|
||||
#define __shared__JurisdictionSender__
|
||||
|
||||
#include <set>
|
||||
#include <queue>
|
||||
|
||||
#include <PacketSender.h>
|
||||
#include <ReceivedPacketProcessor.h>
|
||||
|
@ -44,6 +44,6 @@ protected:
|
|||
private:
|
||||
pthread_mutex_t _requestingNodeMutex;
|
||||
JurisdictionMap* _jurisdictionMap;
|
||||
std::set<QUuid> _nodesRequestingJurisdictions;
|
||||
std::queue<QUuid> _nodesRequestingJurisdictions;
|
||||
};
|
||||
#endif // __shared__JurisdictionSender__
|
||||
|
|
|
@ -90,11 +90,8 @@ bool VoxelEditPacketSender::voxelServersExist() const {
|
|||
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
|
||||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER) {
|
||||
if (node->getActiveSocket()) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
|
||||
return true;
|
||||
} else {
|
||||
// we don't have an active socket for this node, ping it
|
||||
nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -109,12 +106,9 @@ void VoxelEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned ch
|
|||
// only send to the NodeTypes that are NODE_TYPE_VOXEL_SERVER
|
||||
if (node->getType() == NODE_TYPE_VOXEL_SERVER &&
|
||||
((node->getUUID() == nodeUUID) || (nodeUUID.isNull()))) {
|
||||
if (node->getActiveSocket()) {
|
||||
if (nodeList->getNodeActiveSocketOrPing(&(*node))) {
|
||||
sockaddr* nodeAddress = node->getActiveSocket();
|
||||
queuePacketForSending(*nodeAddress, buffer, length);
|
||||
} else {
|
||||
// we don't have an active socket for this node, ping it
|
||||
nodeList->pingPublicAndLocalSocketsForInactiveNode(&(*node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -581,13 +581,24 @@ void VoxelTree::processRemoveVoxelBitstream(unsigned char * bitstream, int buffe
|
|||
int atByte = sizeof(short int) + numBytesForPacketHeader(bitstream);
|
||||
unsigned char* voxelCode = (unsigned char*)&bitstream[atByte];
|
||||
while (atByte < bufferSizeBytes) {
|
||||
int codeLength = numberOfThreeBitSectionsInCode(voxelCode);
|
||||
int maxSize = bufferSizeBytes - atByte;
|
||||
int codeLength = numberOfThreeBitSectionsInCode(voxelCode, maxSize);
|
||||
|
||||
if (codeLength == OVERFLOWED_OCTCODE_BUFFER) {
|
||||
printf("WARNING! Got remove voxel bitstream that would overflow buffer in numberOfThreeBitSectionsInCode(), ");
|
||||
printf("bailing processing of packet!\n");
|
||||
break;
|
||||
}
|
||||
int voxelDataSize = bytesRequiredForCodeLength(codeLength) + SIZE_OF_COLOR_DATA;
|
||||
|
||||
deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE);
|
||||
|
||||
voxelCode+=voxelDataSize;
|
||||
atByte+=voxelDataSize;
|
||||
|
||||
if (atByte + voxelDataSize <= bufferSizeBytes) {
|
||||
deleteVoxelCodeFromTree(voxelCode, COLLAPSE_EMPTY_TREE);
|
||||
voxelCode += voxelDataSize;
|
||||
atByte += voxelDataSize;
|
||||
} else {
|
||||
printf("WARNING! Got remove voxel bitstream that would overflow buffer, bailing processing!\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1795,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