From 5ca805693c0a38b5c100e80862b3f0bad7fb4604 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 11 Oct 2013 17:48:54 -0700 Subject: [PATCH 1/8] reset nodeTypesOfInterest on NodeList reset --- libraries/shared/src/NodeList.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 12a24c535f..328e1f0faa 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -285,6 +285,9 @@ void NodeList::reset() { _checkInPacket = NULL; _numBytesCheckInPacket = 0; + + delete _nodeTypesOfInterest; + _nodeTypesOfInterest = NULL; } void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) { From 7bc2cf6fa9fceb9b589b6316dff0ba76e32d8b71 Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Mon, 14 Oct 2013 09:01:50 -0700 Subject: [PATCH 2/8] Leap interface and Avatar: left-hand IK works for Leap interface. This is in and smooth, and there's a decision to be made: In the case where only one hand is visible, we have to decide if it's the left or right hand. Currently it's simple, based on which side it's detected on. So far this seems to work best, in the (very) common case where hands go in/out of the sensor's field frequently. We could also use a history-based heuristic to hold one hand as left/right, but that means that when it guesses wrong the error lingers. Detecting handedness based on where the thumbs are would be better, but is unreliable on the Leap. I went for the simple/clear version, but we can do whatever we want. --- interface/src/avatar/Avatar.cpp | 31 +++++++++++--------- interface/src/avatar/Avatar.h | 2 +- interface/src/avatar/MyAvatar.cpp | 47 +++++++++++++++++++++++-------- 3 files changed, 55 insertions(+), 25 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 112855343d..e155e43670 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -463,7 +463,8 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem //constrain right arm length and re-adjust elbow position as it bends // NOTE - the following must be called on all avatars - not just _isMine if (enableHandMovement) { - updateArmIKAndConstraints(deltaTime); + updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_RIGHT_FINGERTIPS); + updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_LEFT_FINGERTIPS); } } @@ -640,11 +641,15 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[BODY_BALL_HEAD_TOP].rotation * _skeleton.joint[BODY_BALL_HEAD_TOP].bindPosePosition; } -void Avatar::updateArmIKAndConstraints(float deltaTime) { +void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJointID) { + Skeleton::AvatarJoint& fingerJoint = _skeleton.joint[fingerTipJointID]; + Skeleton::AvatarJoint& wristJoint = _skeleton.joint[fingerJoint.parent]; + Skeleton::AvatarJoint& elbowJoint = _skeleton.joint[wristJoint.parent]; + Skeleton::AvatarJoint& shoulderJoint = _skeleton.joint[elbowJoint.parent]; // determine the arm vector - glm::vec3 armVector = _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position; - armVector -= _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; + glm::vec3 armVector = fingerJoint.position; + armVector -= shoulderJoint.position; // test to see if right hand is being dragged beyond maximum arm length float distance = glm::length(armVector); @@ -652,28 +657,28 @@ void Avatar::updateArmIKAndConstraints(float deltaTime) { // don't let right hand get dragged beyond maximum arm length... if (distance > _maxArmLength) { // reset right hand to be constrained to maximum arm length - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; + fingerJoint.position = shoulderJoint.position; glm::vec3 armNormal = armVector / distance; armVector = armNormal * _maxArmLength; distance = _maxArmLength; - glm::vec3 constrainedPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position; + glm::vec3 constrainedPosition = shoulderJoint.position; constrainedPosition += armVector; - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = constrainedPosition; + fingerJoint.position = constrainedPosition; } // set elbow position - glm::vec3 newElbowPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position + armVector * ONE_HALF; + glm::vec3 newElbowPosition = shoulderJoint.position + armVector * ONE_HALF; glm::vec3 perpendicular = glm::cross(getBodyRightDirection(), armVector); newElbowPosition += perpendicular * (1.0f - (_maxArmLength / distance)) * ONE_HALF; - _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position = newElbowPosition; + elbowJoint.position = newElbowPosition; // set wrist position - glm::vec3 vv(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); - vv -= _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position; - glm::vec3 newWristPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position + vv * 0.7f; - _skeleton.joint[ AVATAR_JOINT_RIGHT_WRIST ].position = newWristPosition; + glm::vec3 vv(fingerJoint.position); + vv -= elbowJoint.position; + glm::vec3 newWristPosition = elbowJoint.position + vv * 0.7f; + wristJoint.position = newWristPosition; } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 1451abd180..7e11a0b9df 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -231,7 +231,7 @@ protected: glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const; void updateBodyBalls(float deltaTime); - void updateArmIKAndConstraints(float deltaTime); + void updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJointID); void setScale(const float scale); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 181c320b69..509935b3cf 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -912,24 +912,49 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov _avatarTouch.setHasInteractingOther(false); } - // If there's a leap-interaction hand visible, use that as the endpoint - glm::vec3 rightMostHand; - bool anyHandsFound = false; - for (size_t i = 0; i < getHand().getPalms().size(); ++i) { - PalmData& palm = getHand().getPalms()[i]; - if (palm.isActive()) { - if (!anyHandsFound || palm.getRawPosition().x > rightMostHand.x) { - _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); - rightMostHand = palm.getRawPosition(); + // If there are leap-interaction hands visible, see if we can use them as the endpoints for IK + if (getHand().getPalms().size() > 0) { + PalmData const* leftLeapHand = NULL; + PalmData const* rightLeapHand = NULL; + // Look through all of the palms available (there may be more than two), and pick + // the leftmost and rightmost. If there's only one, we'll use a heuristic below + // to decode whether it's the left or right. + for (size_t i = 0; i < getHand().getPalms().size(); ++i) { + PalmData& palm = getHand().getPalms()[i]; + if (palm.isActive()) { + if (!rightLeapHand || !leftLeapHand) { + rightLeapHand = leftLeapHand = &palm; + } + else if (palm.getRawPosition().x > rightLeapHand->getRawPosition().x) { + rightLeapHand = &palm; + } + else if (palm.getRawPosition().x < leftLeapHand->getRawPosition().x) { + leftLeapHand = &palm; + } } - anyHandsFound = true; + } + // If there's only one palm visible. Decide if it's the left or right + if (leftLeapHand == rightLeapHand && leftLeapHand) { + if (leftLeapHand->getRawPosition().x > 0) { + leftLeapHand = NULL; + } + else { + rightLeapHand = NULL; + } + } + if (leftLeapHand) { + _skeleton.joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].position = leftLeapHand->getPosition(); + } + if (rightLeapHand) { + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = rightLeapHand->getPosition(); } } //constrain right arm length and re-adjust elbow position as it bends // NOTE - the following must be called on all avatars - not just _isMine if (enableHandMovement) { - updateArmIKAndConstraints(deltaTime); + updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_RIGHT_FINGERTIPS); + updateArmIKAndConstraints(deltaTime, AVATAR_JOINT_LEFT_FINGERTIPS); } //Set right hand position and state to be transmitted, and also tell AvatarTouch about it From d5885acd759f56d25f4407c9830075ad51d77406 Mon Sep 17 00:00:00 2001 From: Eric Johnston Date: Mon, 14 Oct 2013 10:09:08 -0700 Subject: [PATCH 3/8] Cleanup and simplification per feedback --- interface/src/avatar/Avatar.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index e155e43670..7fcca723f6 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -675,10 +675,8 @@ void Avatar::updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJ elbowJoint.position = newElbowPosition; // set wrist position - glm::vec3 vv(fingerJoint.position); - vv -= elbowJoint.position; - glm::vec3 newWristPosition = elbowJoint.position + vv * 0.7f; - wristJoint.position = newWristPosition; + const float wristPosRatio = 0.7f; + wristJoint.position = elbowJoint.position + (fingerJoint.position - elbowJoint.position) * wristPosRatio; } glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { From 6f9fdfba2fc001a175cf271adee235a50fc78da4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Oct 2013 11:39:48 -0700 Subject: [PATCH 4/8] make mouse cursor hiding more aware of focused window and bounds --- interface/src/Application.cpp | 24 ++++++++++++++++++------ interface/src/Application.h | 1 + 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9afb269f1b..81e40cc109 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -107,6 +107,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _mouseY(0), _lastMouseMove(usecTimestampNow()), _mouseHidden(false), + _seenMouseMove(false), _touchAvgX(0.0f), _touchAvgY(0.0f), _isTouchPressed(false), @@ -988,6 +989,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) { if (_mouseHidden) { getGLWidget()->setCursor(Qt::ArrowCursor); _mouseHidden = false; + _seenMouseMove = true; } if (activeWindow() == _window) { @@ -2133,12 +2135,22 @@ void Application::update(float deltaTime) { #endif // watch mouse position, if it hasn't moved, hide the cursor - uint64_t now = usecTimestampNow(); - int elapsed = now - _lastMouseMove; - const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second - if (elapsed > HIDE_CURSOR_TIMEOUT) { - getGLWidget()->setCursor(Qt::BlankCursor); - _mouseHidden = true; + bool underMouse = _glWidget->underMouse(); + if (!_mouseHidden) { + uint64_t now = usecTimestampNow(); + int elapsed = now - _lastMouseMove; + const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second + if (elapsed > HIDE_CURSOR_TIMEOUT && (underMouse || !_seenMouseMove)) { + getGLWidget()->setCursor(Qt::BlankCursor); + _mouseHidden = true; + } + } else { + // if the mouse is hidden, but we're not inside our window, then consider ourselves to be moving + if (!underMouse && _seenMouseMove) { + _lastMouseMove = usecTimestampNow(); + getGLWidget()->setCursor(Qt::ArrowCursor); + _mouseHidden = false; + } } } diff --git a/interface/src/Application.h b/interface/src/Application.h index cb3a3ca73d..595f337bf5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -307,6 +307,7 @@ private: int _mouseDragStartedY; uint64_t _lastMouseMove; bool _mouseHidden; + bool _seenMouseMove; float _touchAvgX; float _touchAvgY; From 342568511948ddabd4ce0ca58efc510b6c02904b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Oct 2013 12:09:44 -0700 Subject: [PATCH 5/8] first cut at added voxel node memory usage debugging to client and server --- interface/src/Application.cpp | 5 +- libraries/voxel-server-library/CMakeLists.txt | 5 ++ .../voxel-server-library/src/VoxelServer.cpp | 46 +++++++++++++++++++ .../voxel-server-library/src/VoxelServer.h | 7 +++ libraries/voxels/src/VoxelNode.cpp | 8 ++++ libraries/voxels/src/VoxelNode.h | 3 ++ 6 files changed, 72 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 81e40cc109..070062f164 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2993,14 +2993,15 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); - voxelStats << "Voxels Memory RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " << + voxelStats << "Voxels Memory Nodes: " << VoxelNode::getVoxelMemoryUsage() / 1000000.f << "MB " + "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " << "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB "; if (_voxels.hasVoxelMemoryUsageGPU()) { voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB "; } drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); - + voxelStats.str(""); char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS); voxelStats << "Voxels Sent from Server: " << voxelDetails; diff --git a/libraries/voxel-server-library/CMakeLists.txt b/libraries/voxel-server-library/CMakeLists.txt index 9eabb95508..1298ef1bae 100644 --- a/libraries/voxel-server-library/CMakeLists.txt +++ b/libraries/voxel-server-library/CMakeLists.txt @@ -18,6 +18,11 @@ qt5_use_modules(${TARGET_NAME} Widgets) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) +# setup a library for civetweb and link it to the voxel-server-library +# this assumes that the domain-server cmake has already correctly set up the civetweb library +include_directories(../../domain-server/external/civetweb/include) +target_link_libraries(${TARGET_NAME} civetweb) + include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index aeda7cf277..07a0b65c57 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -70,6 +70,7 @@ VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location locat _parsedArgV = NULL; } + VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes), _serverTree(true) { _argc = 0; @@ -101,6 +102,43 @@ VoxelServer::~VoxelServer() { } } +void VoxelServer::initMongoose(int port) { + // setup the mongoose web server + struct mg_callbacks callbacks = {}; + + QString documentRoot = QString("%1/resources/web").arg(QCoreApplication::applicationDirPath()); + QString listenPort = QString("%1").arg(port); + + + // list of options. Last element must be NULL. + const char* options[] = { + "listening_ports", listenPort.toLocal8Bit().constData(), + "document_root", documentRoot.toLocal8Bit().constData(), + NULL }; + + callbacks.begin_request = civetwebRequestHandler; + + // Start the web server. + mg_start(&callbacks, NULL, options); +} + +int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { + const struct mg_request_info* ri = mg_get_request_info(connection); + + if (strcmp(ri->uri, "/") == 0 && strcmp(ri->request_method, "GET") == 0) { + // return a 200 + mg_printf(connection, "%s", "HTTP/1.0 200 OK\r\n\r\n"); + mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); + mg_printf(connection, "%s", "Current Statistics\r\n"); + mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); + return 1; + } else { + // have mongoose process this request from the document_root + return 0; + } +} + + void VoxelServer::setArguments(int argc, char** argv) { _argc = argc; _argv = const_cast(argv); @@ -157,6 +195,14 @@ void VoxelServer::run() { qInstallMessageHandler(Logging::verboseMessageHandler); + const char* STATUS_PORT = "--statusPort"; + const char* statusPort = getCmdOption(_argc, _argv, STATUS_PORT); + if (statusPort) { + int statusPortNumber = atoi(statusPort); + initMongoose(statusPortNumber); + } + + const char* JURISDICTION_FILE = "--jurisdictionFile"; const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE); if (jurisdictionFile) { diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index 464938706e..c05a2037c1 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -10,7 +10,10 @@ #ifndef __voxel_server__VoxelServer__ #define __voxel_server__VoxelServer__ +#include "../../domain-server/external/civetweb/include/civetweb.h" + #include +#include #include #include @@ -82,6 +85,10 @@ private: NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed void parsePayload(); + + void initMongoose(int port); + + static int civetwebRequestHandler(struct mg_connection *connection); }; #endif // __voxel_server__VoxelServer__ diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index a7675f4609..154d573836 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -21,6 +21,8 @@ #include "VoxelNode.h" #include "VoxelTree.h" +uint64_t VoxelNode::_voxelMemoryUsage = 0; + VoxelNode::VoxelNode() { unsigned char* rootCode = new unsigned char[1]; *rootCode = 0; @@ -56,11 +58,17 @@ void VoxelNode::init(unsigned char * octalCode) { _sourceID = UNKNOWN_NODE_ID; calculateAABox(); markWithChangedTime(); + + _voxelMemoryUsage += sizeof(VoxelNode); + _voxelMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); } VoxelNode::~VoxelNode() { notifyDeleteHooks(); + _voxelMemoryUsage -= sizeof(VoxelNode); + _voxelMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); + delete[] _octalCode; // delete all of this node's children diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 9664b33a29..6a92ab1e42 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -127,6 +127,8 @@ public: unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; } unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; } + static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; } + private: void calculateAABox(); void init(unsigned char * octalCode); @@ -154,6 +156,7 @@ private: static std::vector _deleteHooks; static std::vector _updateHooks; + static uint64_t _voxelMemoryUsage; }; #endif /* defined(__hifi__VoxelNode__) */ From 1513003ecd2ab6a72cf876051c219843e3565e88 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Oct 2013 12:20:50 -0700 Subject: [PATCH 6/8] added more stats to voxel server status --- .../voxel-server-library/src/VoxelServer.cpp | 17 +++++++++++++++++ .../voxel-server-library/src/VoxelServer.h | 5 +++++ 2 files changed, 22 insertions(+) diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 07a0b65c57..8aa88420d2 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -47,6 +47,8 @@ void attachVoxelNodeDataToNode(Node* newNode) { } } +VoxelServer* VoxelServer::_theInstance = NULL; + VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) : Assignment(command, Assignment::VoxelServerType, location), _serverTree(true) { @@ -68,6 +70,8 @@ VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location locat _voxelServerPacketProcessor = NULL; _voxelPersistThread = NULL; _parsedArgV = NULL; + + _theInstance = this; } @@ -91,6 +95,8 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assign _voxelServerPacketProcessor = NULL; _voxelPersistThread = NULL; _parsedArgV = NULL; + + _theInstance = this; } VoxelServer::~VoxelServer() { @@ -131,6 +137,17 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); mg_printf(connection, "%s", "Current Statistics\r\n"); mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); + + VoxelTree* theTree = VoxelServer::GetInstance()->getTree(); + unsigned long nodeCount = theTree->rootNode->getSubTreeNodeCount(); + unsigned long internalNodeCount = theTree->rootNode->getSubTreeInternalNodeCount(); + unsigned long leafNodeCount = theTree->rootNode->getSubTreeLeafNodeCount(); + + mg_printf(connection, "%s", "Current Nodes in scene\r\n"); + mg_printf(connection, " Total Nodes: %lu nodes\r\n", nodeCount); + mg_printf(connection, " Internal Nodes: %lu nodes\r\n", internalNodeCount); + mg_printf(connection, " Leaf Nodes: %lu leaves\r\n", leafNodeCount); + return 1; } else { // have mongoose process this request from the document_root diff --git a/libraries/voxel-server-library/src/VoxelServer.h b/libraries/voxel-server-library/src/VoxelServer.h index c05a2037c1..a52abaec07 100644 --- a/libraries/voxel-server-library/src/VoxelServer.h +++ b/libraries/voxel-server-library/src/VoxelServer.h @@ -52,12 +52,15 @@ public: 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]; } int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); } + static VoxelServer* GetInstance() { return _theInstance; } + private: int _argc; const char** _argv; @@ -89,6 +92,8 @@ private: void initMongoose(int port); static int civetwebRequestHandler(struct mg_connection *connection); + static VoxelServer* _theInstance; + }; #endif // __voxel_server__VoxelServer__ From f0fc973db12030aee369b2c985047b7e7b08224d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Oct 2013 12:42:15 -0700 Subject: [PATCH 7/8] move loading of voxel file to the persist thread so that assignment client will load voxel server faster --- .../src/VoxelPersistThread.cpp | 31 +++++++++++++++++-- .../src/VoxelPersistThread.h | 1 + .../voxel-server-library/src/VoxelServer.cpp | 24 +++----------- 3 files changed, 33 insertions(+), 23 deletions(-) diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.cpp b/libraries/voxel-server-library/src/VoxelPersistThread.cpp index ca40316d28..8ad2bfaa4d 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.cpp +++ b/libraries/voxel-server-library/src/VoxelPersistThread.cpp @@ -8,7 +8,9 @@ // Threaded or non-threaded voxel persistence // +#include #include +#include #include #include "VoxelPersistThread.h" @@ -17,20 +19,43 @@ VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval) : _tree(tree), _filename(filename), - _persistInterval(persistInterval) { + _persistInterval(persistInterval), + _initialLoad(false) { } bool VoxelPersistThread::process() { + + if (!_initialLoad) { + _initialLoad = true; + qDebug("loading voxels from file: %s...\n", _filename); + + bool persistantFileRead = _tree->readFromSVOFile(_filename); + if (persistantFileRead) { + PerformanceWarning warn(true, "reaverageVoxelColors()", true); + + // after done inserting all these voxels, then reaverage colors + _tree->reaverageVoxelColors(_tree->rootNode); + qDebug("Voxels reAveraged\n"); + } + + _tree->clearDirtyBit(); // the tree is clean since we just loaded it + qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); + unsigned long nodeCount = _tree->rootNode->getSubTreeNodeCount(); + unsigned long internalNodeCount = _tree->rootNode->getSubTreeInternalNodeCount(); + unsigned long leafNodeCount = _tree->rootNode->getSubTreeLeafNodeCount(); + qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); + } + uint64_t MSECS_TO_USECS = 1000; usleep(_persistInterval * MSECS_TO_USECS); // check the dirty bit and persist here... if (_tree->isDirty()) { - printf("saving voxels to file %s...\n",_filename); + qDebug("saving voxels to file %s...\n",_filename); _tree->writeToSVOFile(_filename); _tree->clearDirtyBit(); // tree is clean after saving - printf("DONE saving voxels to file...\n"); + qDebug("DONE saving voxels to file...\n"); } return isStillRunning(); // keep running till they terminate us diff --git a/libraries/voxel-server-library/src/VoxelPersistThread.h b/libraries/voxel-server-library/src/VoxelPersistThread.h index 68487da182..3219633702 100644 --- a/libraries/voxel-server-library/src/VoxelPersistThread.h +++ b/libraries/voxel-server-library/src/VoxelPersistThread.h @@ -28,6 +28,7 @@ private: VoxelTree* _tree; const char* _filename; int _persistInterval; + bool _initialLoad; }; #endif // __voxel_server__VoxelPersistThread__ diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index 8aa88420d2..e4517672a0 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -300,8 +300,7 @@ void VoxelServer::run() { } qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist)); - // if we want Voxel Persistence, load the local file now... - bool persistantFileRead = false; + // if we want Voxel Persistence, set up the local file and persist thread if (_wantVoxelPersist) { // Check to see if the user passed in a command line option for setting packet send rate @@ -314,25 +313,8 @@ void VoxelServer::run() { strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE); } - qDebug("loading voxels from file: %s...\n", _voxelPersistFilename); + qDebug("voxelPersistFilename=%s\n", _voxelPersistFilename); - persistantFileRead = _serverTree.readFromSVOFile(_voxelPersistFilename); - if (persistantFileRead) { - PerformanceWarning warn(_shouldShowAnimationDebug, - "persistVoxelsWhenDirty() - reaverageVoxelColors()", _shouldShowAnimationDebug); - - // after done inserting all these voxels, then reaverage colors - _serverTree.reaverageVoxelColors(_serverTree.rootNode); - qDebug("Voxels reAveraged\n"); - } - - _serverTree.clearDirtyBit(); // the tree is clean since we just loaded it - qDebug("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); - unsigned long nodeCount = _serverTree.rootNode->getSubTreeNodeCount(); - unsigned long internalNodeCount = _serverTree.rootNode->getSubTreeInternalNodeCount(); - unsigned long leafNodeCount = _serverTree.rootNode->getSubTreeLeafNodeCount(); - qDebug("Nodes after loading scene %lu nodes %lu internal %lu leaves\n", nodeCount, internalNodeCount, leafNodeCount); - // now set up VoxelPersistThread _voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename); if (_voxelPersistThread) { @@ -377,6 +359,8 @@ void VoxelServer::run() { if (_voxelServerPacketProcessor) { _voxelServerPacketProcessor->initialize(true); } + + qDebug("Now running...\n"); // loop to send to nodes requesting data while (true) { From 924053f2ecee0654f9aecca6c3315b9264cbf267 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 14 Oct 2013 15:10:56 -0700 Subject: [PATCH 8/8] added additional debugging of VoxelNode memory usage, shrunk size of VoxelNode by better alignment --- interface/src/Application.cpp | 10 ++++- .../voxel-server-library/src/VoxelServer.cpp | 1 + libraries/voxels/src/VoxelNode.cpp | 5 ++- libraries/voxels/src/VoxelNode.h | 42 +++++++++++-------- 4 files changed, 37 insertions(+), 21 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 070062f164..6a6a9789a3 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2993,13 +2993,19 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); - voxelStats << "Voxels Memory Nodes: " << VoxelNode::getVoxelMemoryUsage() / 1000000.f << "MB " + voxelStats << + "Voxels Memory Nodes: " << VoxelNode::getVoxelMemoryUsage() / 1000000.f << "MB " + "Octcodes: " << VoxelNode::getOctcodeMemoryUsage() / 1000000.f << "MB " "Geometry RAM: " << _voxels.getVoxelMemoryUsageRAM() / 1000000.f << "MB " << "VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB "; if (_voxels.hasVoxelMemoryUsageGPU()) { voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB "; } - + + // Some debugging for memory usage of VoxelNodes + //voxelStats << "VoxelNode size: " << sizeof(VoxelNode) << " bytes "; + //voxelStats << "AABox size: " << sizeof(AABox) << " bytes "; + drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str()); voxelStats.str(""); diff --git a/libraries/voxel-server-library/src/VoxelServer.cpp b/libraries/voxel-server-library/src/VoxelServer.cpp index e4517672a0..f02069af2e 100644 --- a/libraries/voxel-server-library/src/VoxelServer.cpp +++ b/libraries/voxel-server-library/src/VoxelServer.cpp @@ -137,6 +137,7 @@ int VoxelServer::civetwebRequestHandler(struct mg_connection* connection) { mg_printf(connection, "%s", "Your Voxel Server is running.\r\n"); mg_printf(connection, "%s", "Current Statistics\r\n"); mg_printf(connection, "Voxel Node Memory Usage: %f MB\r\n", VoxelNode::getVoxelMemoryUsage() / 1000000.f); + mg_printf(connection, "Octcode Memory Usage: %f MB\r\n", VoxelNode::getOctcodeMemoryUsage() / 1000000.f); VoxelTree* theTree = VoxelServer::GetInstance()->getTree(); unsigned long nodeCount = theTree->rootNode->getSubTreeNodeCount(); diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 154d573836..ad83b5a9cf 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -22,6 +22,7 @@ #include "VoxelTree.h" uint64_t VoxelNode::_voxelMemoryUsage = 0; +uint64_t VoxelNode::_octcodeMemoryUsage = 0; VoxelNode::VoxelNode() { unsigned char* rootCode = new unsigned char[1]; @@ -60,14 +61,14 @@ void VoxelNode::init(unsigned char * octalCode) { markWithChangedTime(); _voxelMemoryUsage += sizeof(VoxelNode); - _voxelMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); + _octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); } VoxelNode::~VoxelNode() { notifyDeleteHooks(); _voxelMemoryUsage -= sizeof(VoxelNode); - _voxelMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); + _octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode)); delete[] _octalCode; diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 6a92ab1e42..41196c81b5 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -128,6 +128,7 @@ public: unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; } static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; } + static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; } private: void calculateAABox(); @@ -135,28 +136,35 @@ private: void notifyDeleteHooks(); void notifyUpdateHooks(); - nodeColor _trueColor; + VoxelNode* _children[8]; /// Client and server, pointers to child nodes, 64 bytes + AABox _box; /// Client and server, axis aligned box for bounds of this voxel, 48 bytes + unsigned char* _octalCode; /// Client and server, pointer to octal code for this node, 8 bytes + + uint64_t _lastChanged; /// Client and server, timestamp this node was last changed, 8 bytes + unsigned long _subtreeNodeCount; /// Client and server, nodes below this node, 8 bytes + unsigned long _subtreeLeafNodeCount; /// Client and server, leaves below this node, 8 bytes + + glBufferIndex _glBufferIndex; /// Client only, vbo index for this voxel if being rendered, 8 bytes + VoxelSystem* _voxelSystem; /// Client only, pointer to VoxelSystem rendering this voxel, 8 bytes + + float _density; /// Client and server, If leaf: density = 1, if internal node: 0-1 density of voxels inside, 4 bytes + int _childCount; /// Client and server, current child nodes set to non-null in _children, 4 bytes + + nodeColor _trueColor; /// Client and server, true color of this voxel, 4 bytes #ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color - nodeColor _currentColor; - bool _falseColored; + nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes + bool _falseColored; /// Client only, is this voxel false colored, 1 bytes #endif - glBufferIndex _glBufferIndex; - VoxelSystem* _voxelSystem; - bool _isDirty; - uint64_t _lastChanged; - bool _shouldRender; - AABox _box; - unsigned char* _octalCode; - VoxelNode* _children[8]; - int _childCount; - unsigned long _subtreeNodeCount; - unsigned long _subtreeLeafNodeCount; - float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside - uint16_t _sourceID; + + bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte + bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte + uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes + static std::vector _deleteHooks; static std::vector _updateHooks; static uint64_t _voxelMemoryUsage; + static uint64_t _octcodeMemoryUsage; }; -#endif /* defined(__hifi__VoxelNode__) */ +#endif /* defined(__hifi__VoxelNode__) */ \ No newline at end of file