mirror of
https://github.com/overte-org/overte.git
synced 2025-08-09 07:19:05 +02:00
Merge branch 'master' of https://github.com/worklist/hifi into i-can-always-move
This commit is contained in:
commit
19f20aa456
13 changed files with 236 additions and 74 deletions
|
@ -107,6 +107,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
||||||
_mouseY(0),
|
_mouseY(0),
|
||||||
_lastMouseMove(usecTimestampNow()),
|
_lastMouseMove(usecTimestampNow()),
|
||||||
_mouseHidden(false),
|
_mouseHidden(false),
|
||||||
|
_seenMouseMove(false),
|
||||||
_touchAvgX(0.0f),
|
_touchAvgX(0.0f),
|
||||||
_touchAvgY(0.0f),
|
_touchAvgY(0.0f),
|
||||||
_isTouchPressed(false),
|
_isTouchPressed(false),
|
||||||
|
@ -988,6 +989,7 @@ void Application::mouseMoveEvent(QMouseEvent* event) {
|
||||||
if (_mouseHidden) {
|
if (_mouseHidden) {
|
||||||
getGLWidget()->setCursor(Qt::ArrowCursor);
|
getGLWidget()->setCursor(Qt::ArrowCursor);
|
||||||
_mouseHidden = false;
|
_mouseHidden = false;
|
||||||
|
_seenMouseMove = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (activeWindow() == _window) {
|
if (activeWindow() == _window) {
|
||||||
|
@ -2133,12 +2135,22 @@ void Application::update(float deltaTime) {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// watch mouse position, if it hasn't moved, hide the cursor
|
// watch mouse position, if it hasn't moved, hide the cursor
|
||||||
uint64_t now = usecTimestampNow();
|
bool underMouse = _glWidget->underMouse();
|
||||||
int elapsed = now - _lastMouseMove;
|
if (!_mouseHidden) {
|
||||||
const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second
|
uint64_t now = usecTimestampNow();
|
||||||
if (elapsed > HIDE_CURSOR_TIMEOUT) {
|
int elapsed = now - _lastMouseMove;
|
||||||
getGLWidget()->setCursor(Qt::BlankCursor);
|
const int HIDE_CURSOR_TIMEOUT = 1 * 1000 * 1000; // 1 second
|
||||||
_mouseHidden = true;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2981,14 +2993,21 @@ void Application::displayStats() {
|
||||||
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
||||||
|
|
||||||
voxelStats.str("");
|
voxelStats.str("");
|
||||||
voxelStats << "Voxels Memory RAM: " << _voxels.getVoxelMemoryUsageRAM() / 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 ";
|
"VBO: " << _voxels.getVoxelMemoryUsageVBO() / 1000000.f << "MB ";
|
||||||
if (_voxels.hasVoxelMemoryUsageGPU()) {
|
if (_voxels.hasVoxelMemoryUsageGPU()) {
|
||||||
voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB ";
|
voxelStats << "GPU: " << _voxels.getVoxelMemoryUsageGPU() / 1000000.f << "MB ";
|
||||||
}
|
}
|
||||||
|
|
||||||
drawtext(10, statsVerticalOffset + 250, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
|
// 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("");
|
voxelStats.str("");
|
||||||
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
char* voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_VOXELS);
|
||||||
voxelStats << "Voxels Sent from Server: " << voxelDetails;
|
voxelStats << "Voxels Sent from Server: " << voxelDetails;
|
||||||
|
|
|
@ -307,6 +307,7 @@ private:
|
||||||
int _mouseDragStartedY;
|
int _mouseDragStartedY;
|
||||||
uint64_t _lastMouseMove;
|
uint64_t _lastMouseMove;
|
||||||
bool _mouseHidden;
|
bool _mouseHidden;
|
||||||
|
bool _seenMouseMove;
|
||||||
|
|
||||||
float _touchAvgX;
|
float _touchAvgX;
|
||||||
float _touchAvgY;
|
float _touchAvgY;
|
||||||
|
|
|
@ -463,7 +463,8 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem
|
||||||
//constrain right arm length and re-adjust elbow position as it bends
|
//constrain right arm length and re-adjust elbow position as it bends
|
||||||
// NOTE - the following must be called on all avatars - not just _isMine
|
// NOTE - the following must be called on all avatars - not just _isMine
|
||||||
if (enableHandMovement) {
|
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;
|
_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
|
// determine the arm vector
|
||||||
glm::vec3 armVector = _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position;
|
glm::vec3 armVector = fingerJoint.position;
|
||||||
armVector -= _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position;
|
armVector -= shoulderJoint.position;
|
||||||
|
|
||||||
// test to see if right hand is being dragged beyond maximum arm length
|
// test to see if right hand is being dragged beyond maximum arm length
|
||||||
float distance = glm::length(armVector);
|
float distance = glm::length(armVector);
|
||||||
|
@ -652,28 +657,26 @@ void Avatar::updateArmIKAndConstraints(float deltaTime) {
|
||||||
// don't let right hand get dragged beyond maximum arm length...
|
// don't let right hand get dragged beyond maximum arm length...
|
||||||
if (distance > _maxArmLength) {
|
if (distance > _maxArmLength) {
|
||||||
// reset right hand to be constrained to maximum arm length
|
// 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;
|
glm::vec3 armNormal = armVector / distance;
|
||||||
armVector = armNormal * _maxArmLength;
|
armVector = armNormal * _maxArmLength;
|
||||||
distance = _maxArmLength;
|
distance = _maxArmLength;
|
||||||
glm::vec3 constrainedPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_SHOULDER ].position;
|
glm::vec3 constrainedPosition = shoulderJoint.position;
|
||||||
constrainedPosition += armVector;
|
constrainedPosition += armVector;
|
||||||
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = constrainedPosition;
|
fingerJoint.position = constrainedPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set elbow position
|
// 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);
|
glm::vec3 perpendicular = glm::cross(getBodyRightDirection(), armVector);
|
||||||
|
|
||||||
newElbowPosition += perpendicular * (1.0f - (_maxArmLength / distance)) * ONE_HALF;
|
newElbowPosition += perpendicular * (1.0f - (_maxArmLength / distance)) * ONE_HALF;
|
||||||
_skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position = newElbowPosition;
|
elbowJoint.position = newElbowPosition;
|
||||||
|
|
||||||
// set wrist position
|
// set wrist position
|
||||||
glm::vec3 vv(_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position);
|
const float wristPosRatio = 0.7f;
|
||||||
vv -= _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position;
|
wristJoint.position = elbowJoint.position + (fingerJoint.position - elbowJoint.position) * wristPosRatio;
|
||||||
glm::vec3 newWristPosition = _skeleton.joint[ AVATAR_JOINT_RIGHT_ELBOW ].position + vv * 0.7f;
|
|
||||||
_skeleton.joint[ AVATAR_JOINT_RIGHT_WRIST ].position = newWristPosition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const {
|
||||||
|
|
|
@ -231,7 +231,7 @@ protected:
|
||||||
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
glm::vec3 getBodyFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||||
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
|
||||||
void updateBodyBalls(float deltaTime);
|
void updateBodyBalls(float deltaTime);
|
||||||
void updateArmIKAndConstraints(float deltaTime);
|
void updateArmIKAndConstraints(float deltaTime, AvatarJointID fingerTipJointID);
|
||||||
void setScale(const float scale);
|
void setScale(const float scale);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -912,24 +912,49 @@ void MyAvatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMov
|
||||||
_avatarTouch.setHasInteractingOther(false);
|
_avatarTouch.setHasInteractingOther(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there's a leap-interaction hand visible, use that as the endpoint
|
// If there are leap-interaction hands visible, see if we can use them as the endpoints for IK
|
||||||
glm::vec3 rightMostHand;
|
if (getHand().getPalms().size() > 0) {
|
||||||
bool anyHandsFound = false;
|
PalmData const* leftLeapHand = NULL;
|
||||||
for (size_t i = 0; i < getHand().getPalms().size(); ++i) {
|
PalmData const* rightLeapHand = NULL;
|
||||||
PalmData& palm = getHand().getPalms()[i];
|
// Look through all of the palms available (there may be more than two), and pick
|
||||||
if (palm.isActive()) {
|
// the leftmost and rightmost. If there's only one, we'll use a heuristic below
|
||||||
if (!anyHandsFound || palm.getRawPosition().x > rightMostHand.x) {
|
// to decode whether it's the left or right.
|
||||||
_skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition();
|
for (size_t i = 0; i < getHand().getPalms().size(); ++i) {
|
||||||
rightMostHand = palm.getRawPosition();
|
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
|
//constrain right arm length and re-adjust elbow position as it bends
|
||||||
// NOTE - the following must be called on all avatars - not just _isMine
|
// NOTE - the following must be called on all avatars - not just _isMine
|
||||||
if (enableHandMovement) {
|
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
|
//Set right hand position and state to be transmitted, and also tell AvatarTouch about it
|
||||||
|
|
|
@ -285,6 +285,9 @@ void NodeList::reset() {
|
||||||
_checkInPacket = NULL;
|
_checkInPacket = NULL;
|
||||||
|
|
||||||
_numBytesCheckInPacket = 0;
|
_numBytesCheckInPacket = 0;
|
||||||
|
|
||||||
|
delete _nodeTypesOfInterest;
|
||||||
|
_nodeTypesOfInterest = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
void NodeList::setNodeTypesOfInterest(const char* nodeTypesOfInterest, int numNodeTypesOfInterest) {
|
||||||
|
|
|
@ -18,6 +18,11 @@ qt5_use_modules(${TARGET_NAME} Widgets)
|
||||||
include(${MACRO_DIR}/IncludeGLM.cmake)
|
include(${MACRO_DIR}/IncludeGLM.cmake)
|
||||||
include_glm(${TARGET_NAME} ${ROOT_DIR})
|
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)
|
include(${MACRO_DIR}/LinkHifiLibrary.cmake)
|
||||||
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR})
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,9 @@
|
||||||
// Threaded or non-threaded voxel persistence
|
// Threaded or non-threaded voxel persistence
|
||||||
//
|
//
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
#include <NodeList.h>
|
#include <NodeList.h>
|
||||||
|
#include <PerfStat.h>
|
||||||
#include <SharedUtil.h>
|
#include <SharedUtil.h>
|
||||||
|
|
||||||
#include "VoxelPersistThread.h"
|
#include "VoxelPersistThread.h"
|
||||||
|
@ -17,20 +19,43 @@
|
||||||
VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval) :
|
VoxelPersistThread::VoxelPersistThread(VoxelTree* tree, const char* filename, int persistInterval) :
|
||||||
_tree(tree),
|
_tree(tree),
|
||||||
_filename(filename),
|
_filename(filename),
|
||||||
_persistInterval(persistInterval) {
|
_persistInterval(persistInterval),
|
||||||
|
_initialLoad(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VoxelPersistThread::process() {
|
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;
|
uint64_t MSECS_TO_USECS = 1000;
|
||||||
usleep(_persistInterval * MSECS_TO_USECS);
|
usleep(_persistInterval * MSECS_TO_USECS);
|
||||||
|
|
||||||
|
|
||||||
// check the dirty bit and persist here...
|
// check the dirty bit and persist here...
|
||||||
if (_tree->isDirty()) {
|
if (_tree->isDirty()) {
|
||||||
printf("saving voxels to file %s...\n",_filename);
|
qDebug("saving voxels to file %s...\n",_filename);
|
||||||
_tree->writeToSVOFile(_filename);
|
_tree->writeToSVOFile(_filename);
|
||||||
_tree->clearDirtyBit(); // tree is clean after saving
|
_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
|
return isStillRunning(); // keep running till they terminate us
|
||||||
|
|
|
@ -28,6 +28,7 @@ private:
|
||||||
VoxelTree* _tree;
|
VoxelTree* _tree;
|
||||||
const char* _filename;
|
const char* _filename;
|
||||||
int _persistInterval;
|
int _persistInterval;
|
||||||
|
bool _initialLoad;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __voxel_server__VoxelPersistThread__
|
#endif // __voxel_server__VoxelPersistThread__
|
||||||
|
|
|
@ -47,6 +47,8 @@ void attachVoxelNodeDataToNode(Node* newNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VoxelServer* VoxelServer::_theInstance = NULL;
|
||||||
|
|
||||||
VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) :
|
VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location location) :
|
||||||
Assignment(command, Assignment::VoxelServerType, location),
|
Assignment(command, Assignment::VoxelServerType, location),
|
||||||
_serverTree(true) {
|
_serverTree(true) {
|
||||||
|
@ -68,8 +70,11 @@ VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location locat
|
||||||
_voxelServerPacketProcessor = NULL;
|
_voxelServerPacketProcessor = NULL;
|
||||||
_voxelPersistThread = NULL;
|
_voxelPersistThread = NULL;
|
||||||
_parsedArgV = NULL;
|
_parsedArgV = NULL;
|
||||||
|
|
||||||
|
_theInstance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes),
|
VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes),
|
||||||
_serverTree(true) {
|
_serverTree(true) {
|
||||||
_argc = 0;
|
_argc = 0;
|
||||||
|
@ -90,6 +95,8 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assign
|
||||||
_voxelServerPacketProcessor = NULL;
|
_voxelServerPacketProcessor = NULL;
|
||||||
_voxelPersistThread = NULL;
|
_voxelPersistThread = NULL;
|
||||||
_parsedArgV = NULL;
|
_parsedArgV = NULL;
|
||||||
|
|
||||||
|
_theInstance = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelServer::~VoxelServer() {
|
VoxelServer::~VoxelServer() {
|
||||||
|
@ -101,6 +108,55 @@ 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);
|
||||||
|
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();
|
||||||
|
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
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void VoxelServer::setArguments(int argc, char** argv) {
|
void VoxelServer::setArguments(int argc, char** argv) {
|
||||||
_argc = argc;
|
_argc = argc;
|
||||||
_argv = const_cast<const char**>(argv);
|
_argv = const_cast<const char**>(argv);
|
||||||
|
@ -157,6 +213,14 @@ void VoxelServer::run() {
|
||||||
|
|
||||||
qInstallMessageHandler(Logging::verboseMessageHandler);
|
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* JURISDICTION_FILE = "--jurisdictionFile";
|
||||||
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
|
const char* jurisdictionFile = getCmdOption(_argc, _argv, JURISDICTION_FILE);
|
||||||
if (jurisdictionFile) {
|
if (jurisdictionFile) {
|
||||||
|
@ -237,8 +301,7 @@ void VoxelServer::run() {
|
||||||
}
|
}
|
||||||
qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist));
|
qDebug("wantVoxelPersist=%s\n", debug::valueOf(_wantVoxelPersist));
|
||||||
|
|
||||||
// if we want Voxel Persistence, load the local file now...
|
// if we want Voxel Persistence, set up the local file and persist thread
|
||||||
bool persistantFileRead = false;
|
|
||||||
if (_wantVoxelPersist) {
|
if (_wantVoxelPersist) {
|
||||||
|
|
||||||
// Check to see if the user passed in a command line option for setting packet send rate
|
// Check to see if the user passed in a command line option for setting packet send rate
|
||||||
|
@ -251,25 +314,8 @@ void VoxelServer::run() {
|
||||||
strcpy(_voxelPersistFilename, LOCAL_VOXELS_PERSIST_FILE);
|
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
|
// now set up VoxelPersistThread
|
||||||
_voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename);
|
_voxelPersistThread = new VoxelPersistThread(&_serverTree, _voxelPersistFilename);
|
||||||
if (_voxelPersistThread) {
|
if (_voxelPersistThread) {
|
||||||
|
@ -314,6 +360,8 @@ void VoxelServer::run() {
|
||||||
if (_voxelServerPacketProcessor) {
|
if (_voxelServerPacketProcessor) {
|
||||||
_voxelServerPacketProcessor->initialize(true);
|
_voxelServerPacketProcessor->initialize(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
qDebug("Now running...\n");
|
||||||
|
|
||||||
// loop to send to nodes requesting data
|
// loop to send to nodes requesting data
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
#ifndef __voxel_server__VoxelServer__
|
#ifndef __voxel_server__VoxelServer__
|
||||||
#define __voxel_server__VoxelServer__
|
#define __voxel_server__VoxelServer__
|
||||||
|
|
||||||
|
#include "../../domain-server/external/civetweb/include/civetweb.h"
|
||||||
|
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QtCore/QCoreApplication>
|
||||||
|
|
||||||
#include <Assignment.h>
|
#include <Assignment.h>
|
||||||
#include <EnvironmentData.h>
|
#include <EnvironmentData.h>
|
||||||
|
@ -49,12 +52,15 @@ public:
|
||||||
|
|
||||||
void lockTree() { pthread_mutex_lock(&_treeLock); }
|
void lockTree() { pthread_mutex_lock(&_treeLock); }
|
||||||
void unlockTree() { pthread_mutex_unlock(&_treeLock); }
|
void unlockTree() { pthread_mutex_unlock(&_treeLock); }
|
||||||
|
VoxelTree* getTree() { return &_serverTree; }
|
||||||
|
|
||||||
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
|
int getPacketsPerClientPerInterval() const { return _packetsPerClientPerInterval; }
|
||||||
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
|
bool getSendMinimalEnvironment() const { return _sendMinimalEnvironment; }
|
||||||
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
|
EnvironmentData* getEnvironmentData(int i) { return &_environmentData[i]; }
|
||||||
int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
|
int getEnvironmentDataCount() const { return sizeof(_environmentData)/sizeof(EnvironmentData); }
|
||||||
|
|
||||||
|
static VoxelServer* GetInstance() { return _theInstance; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int _argc;
|
int _argc;
|
||||||
const char** _argv;
|
const char** _argv;
|
||||||
|
@ -82,6 +88,12 @@ private:
|
||||||
NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
|
NodeWatcher _nodeWatcher; // used to cleanup AGENT data when agents are killed
|
||||||
|
|
||||||
void parsePayload();
|
void parsePayload();
|
||||||
|
|
||||||
|
void initMongoose(int port);
|
||||||
|
|
||||||
|
static int civetwebRequestHandler(struct mg_connection *connection);
|
||||||
|
static VoxelServer* _theInstance;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __voxel_server__VoxelServer__
|
#endif // __voxel_server__VoxelServer__
|
||||||
|
|
|
@ -21,6 +21,9 @@
|
||||||
#include "VoxelNode.h"
|
#include "VoxelNode.h"
|
||||||
#include "VoxelTree.h"
|
#include "VoxelTree.h"
|
||||||
|
|
||||||
|
uint64_t VoxelNode::_voxelMemoryUsage = 0;
|
||||||
|
uint64_t VoxelNode::_octcodeMemoryUsage = 0;
|
||||||
|
|
||||||
VoxelNode::VoxelNode() {
|
VoxelNode::VoxelNode() {
|
||||||
unsigned char* rootCode = new unsigned char[1];
|
unsigned char* rootCode = new unsigned char[1];
|
||||||
*rootCode = 0;
|
*rootCode = 0;
|
||||||
|
@ -56,11 +59,17 @@ void VoxelNode::init(unsigned char * octalCode) {
|
||||||
_sourceID = UNKNOWN_NODE_ID;
|
_sourceID = UNKNOWN_NODE_ID;
|
||||||
calculateAABox();
|
calculateAABox();
|
||||||
markWithChangedTime();
|
markWithChangedTime();
|
||||||
|
|
||||||
|
_voxelMemoryUsage += sizeof(VoxelNode);
|
||||||
|
_octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode));
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelNode::~VoxelNode() {
|
VoxelNode::~VoxelNode() {
|
||||||
notifyDeleteHooks();
|
notifyDeleteHooks();
|
||||||
|
|
||||||
|
_voxelMemoryUsage -= sizeof(VoxelNode);
|
||||||
|
_octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode));
|
||||||
|
|
||||||
delete[] _octalCode;
|
delete[] _octalCode;
|
||||||
|
|
||||||
// delete all of this node's children
|
// delete all of this node's children
|
||||||
|
|
|
@ -127,33 +127,44 @@ public:
|
||||||
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; }
|
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; }
|
||||||
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; }
|
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; }
|
||||||
|
|
||||||
|
static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; }
|
||||||
|
static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void calculateAABox();
|
void calculateAABox();
|
||||||
void init(unsigned char * octalCode);
|
void init(unsigned char * octalCode);
|
||||||
void notifyDeleteHooks();
|
void notifyDeleteHooks();
|
||||||
void notifyUpdateHooks();
|
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
|
#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color
|
||||||
nodeColor _currentColor;
|
nodeColor _currentColor; /// Client only, false color of this voxel, 4 bytes
|
||||||
bool _falseColored;
|
bool _falseColored; /// Client only, is this voxel false colored, 1 bytes
|
||||||
#endif
|
#endif
|
||||||
glBufferIndex _glBufferIndex;
|
|
||||||
VoxelSystem* _voxelSystem;
|
bool _isDirty; /// Client only, has this voxel changed since being rendered, 1 byte
|
||||||
bool _isDirty;
|
bool _shouldRender; /// Client only, should this voxel render at this time, 1 byte
|
||||||
uint64_t _lastChanged;
|
uint16_t _sourceID; /// Client only, stores node id of voxel server that sent his voxel, 2 bytes
|
||||||
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;
|
|
||||||
|
|
||||||
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
|
static std::vector<VoxelNodeDeleteHook*> _deleteHooks;
|
||||||
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
|
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
|
||||||
|
static uint64_t _voxelMemoryUsage;
|
||||||
|
static uint64_t _octcodeMemoryUsage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__hifi__VoxelNode__) */
|
#endif /* defined(__hifi__VoxelNode__) */
|
Loading…
Reference in a new issue