Merge branch 'master' of https://github.com/worklist/hifi into skinny

This commit is contained in:
Andrzej Kapolka 2013-10-15 14:01:53 -07:00
commit 0a5ba79bbe
9 changed files with 227 additions and 83 deletions

View file

@ -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;
}
}
}
@ -2779,9 +2791,11 @@ void Application::displayOverlay() {
}
#ifndef _WIN32
_audio.render(_glWidget->width(), _glWidget->height());
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
_audioScope.render(45, _glWidget->height() - 200);
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
_audio.render(_glWidget->width(), _glWidget->height());
if (Menu::getInstance()->isOptionChecked(MenuOption::Oscilloscope)) {
_audioScope.render(45, _glWidget->height() - 200);
}
}
#endif
@ -2821,7 +2835,24 @@ void Application::displayOverlay() {
glPointSize(1.0f);
if (Menu::getInstance()->isOptionChecked(MenuOption::Stats)) {
// Onscreen text about position, servers, etc
displayStats();
// Bandwidth meter
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
_bandwidthMeter.render(_glWidget->width(), _glWidget->height());
}
// Stats at upper right of screen about who domain server is telling us about
glPointSize(1.0f);
char nodes[100];
NodeList* nodeList = NodeList::getInstance();
int totalAvatars = 0, totalServers = 0;
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++;
}
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0);
}
// testing rendering coverage map
@ -2833,9 +2864,6 @@ void Application::displayOverlay() {
renderCoverageMap();
}
if (Menu::getInstance()->isOptionChecked(MenuOption::Bandwidth)) {
_bandwidthMeter.render(_glWidget->width(), _glWidget->height());
}
if (Menu::getInstance()->isOptionChecked(MenuOption::Log)) {
LogDisplay::instance.render(_glWidget->width(), _glWidget->height());
@ -2855,19 +2883,6 @@ void Application::displayOverlay() {
drawtext(_glWidget->width() - 102, _glWidget->height() - 22, 0.30, 0, 1.0, 0, frameTimer, 1, 1, 1);
}
// Stats at upper right of screen about who domain server is telling us about
glPointSize(1.0f);
char nodes[100];
NodeList* nodeList = NodeList::getInstance();
int totalAvatars = 0, totalServers = 0;
for (NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->getType() == NODE_TYPE_AGENT ? totalAvatars++ : totalServers++;
}
sprintf(nodes, "Servers: %d, Avatars: %d\n", totalServers, totalAvatars);
drawtext(_glWidget->width() - 150, 20, 0.10, 0, 1.0, 0, nodes, 1, 0, 0);
// render the webcam input frame
_webcam.renderPreview(_glWidget->width(), _glWidget->height());
@ -2929,11 +2944,12 @@ void Application::displayOverlay() {
void Application::displayStats() {
int statsVerticalOffset = 8;
const int PELS_PER_LINE = 15;
char stats[200];
statsVerticalOffset += PELS_PER_LINE;
sprintf(stats, "%3.0f FPS, %d Pkts/sec, %3.2f Mbps ",
_fps, _packetsPerSecond, (float)_bytesPerSecond * 8.f / 1000000.f);
drawtext(10, statsVerticalOffset + 15, 0.10f, 0, 1.0, 0, stats);
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, stats);
if (Menu::getInstance()->isOptionChecked(MenuOption::TestPing)) {
int pingAudio = 0, pingAvatar = 0, pingVoxel = 0, pingVoxelMax = 0;
@ -2963,14 +2979,16 @@ void Application::displayStats() {
}
char pingStats[200];
statsVerticalOffset += PELS_PER_LINE;
sprintf(pingStats, "Ping audio/avatar/voxel: %d / %d / %d avg %d max ", pingAudio, pingAvatar, pingVoxel, pingVoxelMax);
drawtext(10, statsVerticalOffset + 35, 0.10f, 0, 1.0, 0, pingStats);
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, pingStats);
}
char avatarStats[200];
statsVerticalOffset += PELS_PER_LINE;
glm::vec3 avatarPos = _myAvatar.getPosition();
sprintf(avatarStats, "Avatar: pos %.3f, %.3f, %.3f, vel %.1f, yaw = %.2f", avatarPos.x, avatarPos.y, avatarPos.z, glm::length(_myAvatar.getVelocity()), _myAvatar.getBodyYaw());
drawtext(10, statsVerticalOffset + 55, 0.10f, 0, 1.0, 0, avatarStats);
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats);
std::stringstream voxelStats;
@ -2978,36 +2996,49 @@ void Application::displayStats() {
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " <<
"Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " <<
"Max: " << _voxels.getMaxVoxels()/1000.f << "K ";
drawtext(10, statsVerticalOffset + 230, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 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 "
"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 ";
}
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 ";
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 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;
drawtext(10, statsVerticalOffset + 270, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ELAPSED);
voxelStats << "Scene Send Time from Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 290, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_ENCODE);
voxelStats << "Encode Time on Server: " << voxelDetails;
drawtext(10, statsVerticalOffset + 310, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
voxelStats.str("");
voxelDetails = _voxelSceneStats.getItemValue(VoxelSceneStats::ITEM_MODE);
voxelStats << "Sending Mode: " << voxelDetails;
drawtext(10, statsVerticalOffset + 330, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER);
char avatarMixerStats[200];
@ -3019,20 +3050,21 @@ void Application::displayStats() {
} else {
sprintf(avatarMixerStats, "No Avatar Mixer");
}
drawtext(10, statsVerticalOffset + 350, 0.10f, 0, 1.0, 0, avatarMixerStats);
drawtext(10, statsVerticalOffset + 450, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarMixerStats);
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)LeapManager::statusString().c_str());
if (_perfStatsOn) {
// Get the PerfStats group details. We need to allocate and array of char* long enough to hold 1+groups
char** perfStatLinesArray = new char*[PerfStat::getGroupCount()+1];
int lines = PerfStat::DumpStats(perfStatLinesArray);
int atZ = 150; // arbitrary place on screen that looks good
for (int line=0; line < lines; line++) {
drawtext(10, statsVerticalOffset + atZ, 0.10f, 0, 1.0, 0, perfStatLinesArray[line]);
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, perfStatLinesArray[line]);
delete perfStatLinesArray[line]; // we're responsible for cleanup
perfStatLinesArray[line]=NULL;
atZ+=20; // height of a line
}
delete []perfStatLinesArray; // we're responsible for cleanup
}

View file

@ -307,6 +307,7 @@ private:
int _mouseDragStartedY;
uint64_t _lastMouseMove;
bool _mouseHidden;
bool _seenMouseMove;
float _touchAvgX;
float _touchAvgY;

View file

@ -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})

View file

@ -8,7 +8,9 @@
// Threaded or non-threaded voxel persistence
//
#include <QDebug>
#include <NodeList.h>
#include <PerfStat.h>
#include <SharedUtil.h>
#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

View file

@ -28,6 +28,7 @@ private:
VoxelTree* _tree;
const char* _filename;
int _persistInterval;
bool _initialLoad;
};
#endif // __voxel_server__VoxelPersistThread__

View file

@ -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,8 +70,11 @@ VoxelServer::VoxelServer(Assignment::Command command, Assignment::Location locat
_voxelServerPacketProcessor = NULL;
_voxelPersistThread = NULL;
_parsedArgV = NULL;
_theInstance = this;
}
VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assignment(dataBuffer, numBytes),
_serverTree(true) {
_argc = 0;
@ -90,6 +95,8 @@ VoxelServer::VoxelServer(const unsigned char* dataBuffer, int numBytes) : Assign
_voxelServerPacketProcessor = NULL;
_voxelPersistThread = NULL;
_parsedArgV = NULL;
_theInstance = this;
}
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) {
_argc = argc;
_argv = const_cast<const char**>(argv);
@ -157,6 +213,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) {
@ -237,8 +301,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
@ -251,25 +314,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) {
@ -314,6 +360,8 @@ void VoxelServer::run() {
if (_voxelServerPacketProcessor) {
_voxelServerPacketProcessor->initialize(true);
}
qDebug("Now running...\n");
// loop to send to nodes requesting data
while (true) {

View file

@ -10,7 +10,10 @@
#ifndef __voxel_server__VoxelServer__
#define __voxel_server__VoxelServer__
#include "../../domain-server/external/civetweb/include/civetweb.h"
#include <QStringList>
#include <QtCore/QCoreApplication>
#include <Assignment.h>
#include <EnvironmentData.h>
@ -49,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;
@ -82,6 +88,12 @@ 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);
static VoxelServer* _theInstance;
};
#endif // __voxel_server__VoxelServer__

View file

@ -21,6 +21,9 @@
#include "VoxelNode.h"
#include "VoxelTree.h"
uint64_t VoxelNode::_voxelMemoryUsage = 0;
uint64_t VoxelNode::_octcodeMemoryUsage = 0;
VoxelNode::VoxelNode() {
unsigned char* rootCode = new unsigned char[1];
*rootCode = 0;
@ -56,11 +59,17 @@ void VoxelNode::init(unsigned char * octalCode) {
_sourceID = UNKNOWN_NODE_ID;
calculateAABox();
markWithChangedTime();
_voxelMemoryUsage += sizeof(VoxelNode);
_octcodeMemoryUsage += bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode));
}
VoxelNode::~VoxelNode() {
notifyDeleteHooks();
_voxelMemoryUsage -= sizeof(VoxelNode);
_octcodeMemoryUsage -= bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(_octalCode));
delete[] _octalCode;
// delete all of this node's children

View file

@ -127,33 +127,44 @@ public:
unsigned long getSubTreeInternalNodeCount() const { return _subtreeNodeCount - _subtreeLeafNodeCount; }
unsigned long getSubTreeLeafNodeCount() const { return _subtreeLeafNodeCount; }
static uint64_t getVoxelMemoryUsage() { return _voxelMemoryUsage; }
static uint64_t getOctcodeMemoryUsage() { return _octcodeMemoryUsage; }
private:
void calculateAABox();
void init(unsigned char * octalCode);
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<VoxelNodeDeleteHook*> _deleteHooks;
static std::vector<VoxelNodeUpdateHook*> _updateHooks;
static uint64_t _voxelMemoryUsage;
static uint64_t _octcodeMemoryUsage;
};
#endif /* defined(__hifi__VoxelNode__) */
#endif /* defined(__hifi__VoxelNode__) */