Merge pull request #1095 from ZappoMan/keep_local_voxels

Keep local voxels
This commit is contained in:
Philip Rosedale 2013-10-21 17:22:24 -07:00
commit c354b4a063
11 changed files with 525 additions and 138 deletions

View file

@ -356,8 +356,9 @@ void Application::initializeGL() {
void Application::paintGL() {
PerformanceWarning::setSuppressShortTimings(Menu::getInstance()->isOptionChecked(MenuOption::SuppressShortTimings));
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::paintGL()");
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::paintGL()");
glEnable(GL_LINE_SMOOTH);
if (_myCamera.getMode() == CAMERA_MODE_MIRROR) {
@ -545,6 +546,7 @@ void Application::keyPressEvent(QKeyEvent* event) {
}
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
switch (event->key()) {
case Qt::Key_Shift:
if (Menu::getInstance()->isOptionChecked(MenuOption::VoxelSelectMode)) {
@ -619,8 +621,10 @@ void Application::keyPressEvent(QKeyEvent* event) {
break;
case Qt::Key_S:
if (isShifted) {
if (isShifted && !isMeta) {
_voxels.collectStatsForTreesAndVBOs();
} else if (isShifted && isMeta) {
Menu::getInstance()->triggerOption(MenuOption::SuppressShortTimings);
} else if (_nudgeStarted) {
if (_lookingAlongX) {
if (_lookingAwayFromOrigin) {
@ -1238,6 +1242,8 @@ static glm::vec3 getFaceVector(BoxFace face) {
}
void Application::idle() {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::idle()");
timeval check;
gettimeofday(&check, NULL);
@ -1252,7 +1258,7 @@ void Application::idle() {
_glWidget->updateGL();
_lastTimeUpdated = check;
_idleLoopStdev.addValue(timeSinceLastUpdate);
// Record standard deviation and reset counter if needed
const int STDEV_SAMPLES = 500;
if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) {
@ -1783,7 +1789,28 @@ void Application::renderFollowIndicator() {
}
}
void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateAvatars()");
NodeList* nodeList = NodeList::getInstance();
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL) {
Avatar *avatar = (Avatar *)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
avatar->simulate(deltaTime, NULL);
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
}
node->unlock();
}
}
void Application::update(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::update()");
// Use Transmitter Hand to move hand if connected, else use mouse
if (_myTransmitter.isConnected()) {
@ -1884,6 +1911,8 @@ void Application::update(float deltaTime) {
(fabs(_myAvatar.getVelocity().x) +
fabs(_myAvatar.getVelocity().y) +
fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) {
PerformanceWarning warn(showWarnings, "Application::update()... findRayIntersection()");
if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) {
if (distance < MAX_VOXEL_EDIT_DISTANCE) {
// find the nearest voxel with the desired scale
@ -1991,22 +2020,11 @@ void Application::update(float deltaTime) {
_voxelProcessor.threadRoutine();
_voxelEditSender.threadRoutine();
}
//loop through all the other avatars and simulate them...
NodeList* nodeList = NodeList::getInstance();
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL) {
Avatar *avatar = (Avatar *)node->getLinkedData();
if (!avatar->isInitialized()) {
avatar->init();
}
avatar->simulate(deltaTime, NULL);
avatar->setMouseRay(mouseRayOrigin, mouseRayDirection);
}
node->unlock();
}
updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection);
// Simulate myself
if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) {
_myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition()));
@ -2041,6 +2059,7 @@ void Application::update(float deltaTime) {
if (_voxels.findRayIntersection(_transmitterPickStart, direction, detail, distance, face)) {
minDistance = min(minDistance, distance);
}
NodeList* nodeList = NodeList::getInstance();
for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); node++) {
node->lock();
if (node->getLinkedData() != NULL) {
@ -2134,6 +2153,8 @@ void Application::update(float deltaTime) {
}
void Application::updateAvatar(float deltaTime) {
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "Application::updateAvatar()");
// rotate body yaw for yaw received from multitouch
_myAvatar.setOrientation(_myAvatar.getOrientation()
@ -2990,51 +3011,54 @@ void Application::displayStats() {
std::stringstream voxelStats;
voxelStats.precision(4);
voxelStats << "Voxels Rendered: " << _voxels.getVoxelsRendered() / 1000.f << "K " <<
"Written: " << _voxels.getVoxelsWritten()/1000.f << "K " <<
"Updated: " << _voxels.getVoxelsUpdated()/1000.f << "K " <<
"Max: " << _voxels.getMaxVoxels()/1000.f << "K ";
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
voxelStats.str("");
voxelStats <<
"Voxels Memory Nodes: " << VoxelNode::getVoxelMemoryUsage() / 1000000.f << "MB "
"Octcodes: " << VoxelNode::getOctcodeMemoryUsage() / 1000000.f << "MB "
"Voxels Memory Nodes: " << VoxelNode::getTotalMemoryUsage() / 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 ";
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str());
voxelStats.str("");
voxelStats <<
"Local Voxels Total: " << VoxelNode::getNodeCount() << ", " <<
"Internal: " << VoxelNode::getInternalNodeCount() << " , " <<
"Leaves: " << VoxelNode::getLeafNodeCount() << "";
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;
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
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;
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
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;
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
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;
statsVerticalOffset += PELS_PER_LINE;
drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char *)voxelStats.str().c_str());
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];
@ -3049,7 +3073,7 @@ void Application::displayStats() {
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());
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
@ -3235,7 +3259,6 @@ void Application::renderCoverageMapsRecursively(CoverageMap* map) {
/////////////////////////////////////////////////////////////////////////////////////
// renderViewFrustum()
//
// Description: this will render the view frustum bounds for EITHER the head
@ -3317,7 +3340,7 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) {
|| Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_PLANES
|| Menu::getInstance()->getFrustumDrawMode() == FRUSTUM_DRAW_MODE_FAR_PLANE) {
// viewFrustum.getFar plane - bottom edge
glColor3f(0,1,0); // GREEN!!!
glColor3f(0,1,0);
glVertex3f(viewFrustum.getFarBottomLeft().x, viewFrustum.getFarBottomLeft().y, viewFrustum.getFarBottomLeft().z);
glVertex3f(viewFrustum.getFarBottomRight().x, viewFrustum.getFarBottomRight().y, viewFrustum.getFarBottomRight().z);
@ -3685,6 +3708,9 @@ int Application::parseVoxelStats(unsigned char* messageData, ssize_t messageLeng
// Receive packets from other nodes/servers and decide what to do with them!
void* Application::networkReceive(void* args) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::networkReceive()");
sockaddr senderAddress;
ssize_t bytesReceived;
@ -3712,6 +3738,9 @@ void* Application::networkReceive(void* args) {
case PACKET_TYPE_ERASE_VOXEL:
case PACKET_TYPE_VOXEL_STATS:
case PACKET_TYPE_ENVIRONMENT_DATA: {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"Application::networkReceive()... _voxelProcessor.queueReceivedPacket()");
// add this packet to our list of voxel packets and process them on the voxel processing
app->_voxelProcessor.queueReceivedPacket(senderAddress, app->_incomingPacket, bytesReceived);
break;

View file

@ -216,6 +216,7 @@ private:
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
void renderFollowIndicator();
void updateAvatar(float deltaTime);
void updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm::vec3 mouseRayDirection);
void loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum);
void displayOculus(Camera& whichCamera);

View file

@ -275,16 +275,25 @@ Menu::Menu() :
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelsAsPoints, 0,
false, appInstance->getVoxels(), SLOT(setVoxelsAsPoints(bool)));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::FastVoxelPipeline, 0,
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::DontRemoveOutOfView);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::HideOutOfView);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::ConstantCulling);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AutomaticallyAuditTree);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::VoxelTextures);
addCheckableActionToQMenuAndActionHash(voxelOptionsMenu, MenuOption::AmbientOcclusion);
QMenu* cullingOptionsMenu = voxelOptionsMenu->addMenu("Culling Options");
addDisabledActionAndSeparator(cullingOptionsMenu, "Standard Settings");
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::OldVoxelCullingMode, 0,
false, this, SLOT(setOldVoxelCullingMode(bool)));
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::NewVoxelCullingMode, 0,
false, this, SLOT(setNewVoxelCullingMode(bool)));
addDisabledActionAndSeparator(cullingOptionsMenu, "Individual Option Settings");
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::FastVoxelPipeline, 0,
false, appInstance->getVoxels(), SLOT(setUseFastVoxelPipeline(bool)));
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::DontRemoveOutOfView);
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::HideOutOfView);
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::UseDeltaFrustumInHide);
addCheckableActionToQMenuAndActionHash(cullingOptionsMenu, MenuOption::ConstantCulling);
QMenu* avatarOptionsMenu = developerMenu->addMenu("Avatar Options");
@ -377,8 +386,17 @@ Menu::Menu() :
QMenu* renderDebugMenu = developerMenu->addMenu("Render Debugging Tools");
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings);
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings);
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::PipelineWarnings, Qt::CTRL | Qt::SHIFT | Qt::Key_P);
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::SuppressShortTimings, Qt::CTRL | Qt::SHIFT | Qt::Key_S);
addCheckableActionToQMenuAndActionHash(renderDebugMenu, MenuOption::AutomaticallyAuditTree);
addActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::ShowAllLocalVoxels,
Qt::CTRL | Qt::Key_A,
appInstance->getVoxels(),
SLOT(showAllLocalVoxels()));
addActionToQMenuAndActionHash(renderDebugMenu,
MenuOption::KillLocalVoxels,
@ -1085,4 +1103,30 @@ void Menu::updateFrustumRenderModeAction() {
}
}
void Menu::setOldVoxelCullingMode(bool oldMode) {
setVoxelCullingMode(oldMode);
}
void Menu::setNewVoxelCullingMode(bool newMode) {
setVoxelCullingMode(!newMode);
}
/// This will switch on or off several different individual settings options all at once based on choosing with Old or New
/// voxel culling mode.
void Menu::setVoxelCullingMode(bool oldMode) {
const QString menus[] = { MenuOption::FastVoxelPipeline, MenuOption::DontRemoveOutOfView, MenuOption::HideOutOfView,
MenuOption::UseDeltaFrustumInHide, MenuOption::ConstantCulling};
bool oldModeValue[] = { false, false, false, false, false };
bool newModeValue[] = { true, true, true, true, true };
for (int i = 0; i < sizeof(menus) / sizeof(menus[0]); i++) {
bool desiredValue = oldMode ? oldModeValue[i] : newModeValue[i];
if (isOptionChecked(menus[i]) != desiredValue) {
triggerOption(menus[i]);
}
}
// set the checkmarks accordingly...
_actionHash.value(MenuOption::OldVoxelCullingMode)->setChecked(oldMode);
_actionHash.value(MenuOption::NewVoxelCullingMode)->setChecked(!oldMode);
}

View file

@ -81,6 +81,8 @@ private slots:
void chooseVoxelPaintColor();
void runTests();
void resetSwatchColors();
void setOldVoxelCullingMode(bool oldMode);
void setNewVoxelCullingMode(bool newMode);
private:
static Menu* _instance;
@ -108,6 +110,7 @@ private:
const char* member = NULL);
void updateFrustumRenderModeAction();
void setVoxelCullingMode(bool oldMode);
QHash<QString, QAction*> _actionHash;
int _audioJitterBufferSamples; /// number of extra samples to wait before starting audio playback
@ -182,9 +185,11 @@ namespace MenuOption {
const QString LookAtVectors = "Look-at Vectors";
const QString LowRes = "Lower Resolution While Moving";
const QString Mirror = "Mirror";
const QString NewVoxelCullingMode = "New Voxel Culling Mode";
const QString NudgeVoxels = "Nudge";
const QString OcclusionCulling = "Occlusion Culling";
const QString OffAxisProjection = "Off-Axis Projection";
const QString OldVoxelCullingMode = "Old Voxel Culling Mode";
const QString TurnWithHead = "Turn using Head";
const QString Oscilloscope = "Audio Oscilloscope";
const QString Pair = "Pair";
@ -198,6 +203,7 @@ namespace MenuOption {
const QString SendVoxelColors = "Colored Voxels";
const QString SettingsImport = "Import Settings";
const QString SettingsExport = "Export Settings";
const QString ShowAllLocalVoxels = "Show All Local Voxels";
const QString ShowTrueColors = "Show TRUE Colors";
const QString SimulateLeapHand = "Simulate Leap Hand";
const QString SkeletonTracking = "Skeleton Tracking";
@ -210,6 +216,7 @@ namespace MenuOption {
const QString TreeStats = "Calculate Tree Stats";
const QString TransmitterDrive = "Transmitter Drive";
const QString Quit = "Quit";
const QString UseDeltaFrustumInHide = "Use Delta View Frustums when Culling";
const QString UseVoxelShader = "Use Voxel Shader";
const QString VoxelsAsPoints = "Draw Voxels as Points";
const QString Voxels = "Voxels";

View file

@ -17,6 +17,11 @@
void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"VoxelPacketProcessor::processPacket()");
const int WAY_BEHIND = 300;
if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) {
qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount());
}
ssize_t messageLength = packetLength;
Application* app = Application::getInstance();

View file

@ -73,6 +73,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_writeRenderFullVBO = true;
_readRenderFullVBO = true;
_tree = new VoxelTree();
_tree->rootNode->setVoxelSystem(this);
pthread_mutex_init(&_bufferWriteLock, NULL);
pthread_mutex_init(&_treeLock, NULL);
@ -106,6 +107,8 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels)
_inSetupNewVoxelsForDrawing = false;
_useFastVoxelPipeline = false;
_culledOnce = false;
}
void VoxelSystem::voxelDeleted(VoxelNode* node) {
@ -133,7 +136,7 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) {
}
if (node->getVoxelSystem() == this) {
bool shouldRender = false; // assume we don't need to render it
bool shouldRender = false; // assume we don't need to render it
// if it's colored, we might need to render it!
shouldRender = node->calculateShouldRender(_viewFrustum);
@ -228,16 +231,21 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) {
// This will run through the list of _freeIndexes and reset their VBO array values to be "invisible".
void VoxelSystem::clearFreeBufferIndexes() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()");
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "clearFreeBufferIndexes()");
_voxelsInWriteArrays = 0; // reset our VBO
_abandonedVBOSlots = 0;
// clear out freeIndexes
pthread_mutex_lock(&_freeIndexLock);
_freeIndexes.clear();
{
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : pthread_mutex_lock(&_freeIndexLock)");
pthread_mutex_lock(&_freeIndexLock);
}
{
PerformanceWarning warn(showWarnings,"clearFreeBufferIndexes() : _freeIndexes.clear()");
_freeIndexes.clear();
}
pthread_mutex_unlock(&_freeIndexLock);
clearAllNodesBufferIndex();
}
VoxelSystem::~VoxelSystem() {
@ -744,7 +752,6 @@ void VoxelSystem::checkForCulling() {
&& !isViewChanging()
)
) {
_lastViewCulling = start;
// When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove
@ -949,6 +956,12 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelNode* node) {
int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw) {
// If we've run out of room, then just bail...
if (_voxelsInWriteArrays >= _maxVoxels) {
// We need to think about what else we can do in this case. This basically means that all of our available
// VBO slots are used up, but we're trying to render more voxels. At this point, if this happens we'll just
// not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality
// possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this
// state actually occurs.
qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n");
return 0;
}
@ -1061,10 +1074,24 @@ void VoxelSystem::changeTree(VoxelTree* newTree) {
}
void VoxelSystem::updateFullVBOs() {
updateVBOSegment(0, _voxelsInReadArrays);
bool outputWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(outputWarning, "updateFullVBOs()");
{
static char buffer[128] = { 0 };
if (outputWarning) {
sprintf(buffer, "updateFullVBOs() : updateVBOSegment(0, _voxelsInReadArrays=%lu);", _voxelsInReadArrays);
};
PerformanceWarning warn(outputWarning,buffer);
updateVBOSegment(0, _voxelsInReadArrays);
}
// consider the _readVoxelDirtyArray[] clean!
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
{
PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)");
// consider the _readVoxelDirtyArray[] clean!
memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool));
}
}
void VoxelSystem::updatePartialVBOs() {
@ -1116,6 +1143,9 @@ void VoxelSystem::updateVBOs() {
}
void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) {
bool showWarning = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarning, "updateVBOSegment()");
if (_useVoxelShader) {
int segmentLength = (segmentEnd - segmentStart) + 1;
GLintptr segmentStartAt = segmentStart * sizeof(VoxelShaderVBOData);
@ -1130,18 +1160,36 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg
GLintptr segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLfloat);
GLsizeiptr segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLfloat);
GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * vertexPointsPerVoxel);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
{
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);");
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
}
{
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboVerticesID);");
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom);
}
segmentStartAt = segmentStart * vertexPointsPerVoxel * sizeof(GLubyte);
segmentSizeBytes = segmentLength * vertexPointsPerVoxel * sizeof(GLubyte);
GLubyte* readColorsFrom = _readColorsArray + (segmentStart * vertexPointsPerVoxel);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
{
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);");
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
}
{
PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);");
glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom);
}
}
}
void VoxelSystem::render(bool texture) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render()");
bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showWarnings, "render()");
// If we got here and we're not initialized then bail!
if (!_initialized) {
@ -1153,8 +1201,7 @@ void VoxelSystem::render(bool texture) {
bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels);
// if not don't... then do...
if (_useVoxelShader) {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
"render().. _useVoxelShader openGL..");
PerformanceWarning warn(showWarnings,"render().. _useVoxelShader openGL..");
//Define this somewhere in your header file
@ -1200,68 +1247,78 @@ void VoxelSystem::render(bool texture) {
glDisableVertexAttribArray(attributeLocation);
}
} else {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "render().. openGL...");
PerformanceWarning warn(showWarnings, "render().. TRIANGLES...");
// tell OpenGL where to find vertex and color information
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
{
PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()...");
// tell OpenGL where to find vertex and color information
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID);
glVertexPointer(3, GL_FLOAT, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);
glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0);
applyScaleAndBindProgram(texture);
applyScaleAndBindProgram(texture);
// for performance, enable backface culling
glEnable(GL_CULL_FACE);
// for performance, enable backface culling
glEnable(GL_CULL_FACE);
}
// draw voxels in 6 passes
if (!dontCallOpenGLDraw) {
PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()...");
glNormal3f(0,1.0f,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glNormal3f(0,-1.0f,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBottom);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glNormal3f(-1.0f,0,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesLeft);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glNormal3f(1.0f,0,0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesRight);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glNormal3f(0,0,-1.0f);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesFront);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
glNormal3f(0,0,1.0f);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesBack);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, INDICES_PER_FACE * _voxelsInReadArrays - 1,
glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1,
INDICES_PER_FACE * _voxelsInReadArrays, GL_UNSIGNED_INT, 0);
}
glDisable(GL_CULL_FACE);
{
PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()...");
glDisable(GL_CULL_FACE);
removeScaleAndReleaseProgram(texture);
removeScaleAndReleaseProgram(texture);
// deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// deactivate vertex and color arrays after drawing
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
// bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
// bind with 0 to switch back to normal operation
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
}
}
@ -1526,11 +1583,11 @@ public:
VoxelSystem* thisVoxelSystem;
ViewFrustum thisViewFrustum;
VoxelNodeBag dontRecurseBag;
unsigned long nodesScanned;
unsigned long nodesRemoved;
unsigned long nodesInside;
unsigned long nodesIntersect;
unsigned long nodesOutside;
unsigned long nodesScanned;
unsigned long nodesRemoved;
unsigned long nodesInside;
unsigned long nodesIntersect;
unsigned long nodesOutside;
VoxelNode* insideRoot;
VoxelNode* outsideRoot;
@ -1611,10 +1668,10 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) {
bool VoxelSystem::isViewChanging() {
bool result = false; // assume the best
// If our viewFrustum has changed since our _lastKnowViewFrustum
if (!_lastKnowViewFrustum.matches(_viewFrustum)) {
// If our viewFrustum has changed since our _lastKnownViewFrustum
if (!_lastKnownViewFrustum.matches(_viewFrustum)) {
result = true;
_lastKnowViewFrustum = *_viewFrustum; // save last known
_lastKnownViewFrustum = *_viewFrustum; // save last known
}
return result;
}
@ -1627,7 +1684,7 @@ bool VoxelSystem::hasViewChanged() {
return false;
}
// If our viewFrustum has changed since our _lastKnowViewFrustum
// If our viewFrustum has changed since our _lastKnownViewFrustum
if (!_lastStableViewFrustum.matches(_viewFrustum)) {
result = true;
_lastStableViewFrustum = *_viewFrustum; // save last stable
@ -1652,27 +1709,92 @@ void VoxelSystem::removeOutOfView() {
}
}
// combines the removeOutOfView args into a single class
class showAllLocalVoxelsArgs {
public:
VoxelSystem* thisVoxelSystem;
ViewFrustum thisViewFrustum;
unsigned long nodesScanned;
showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) :
thisVoxelSystem(voxelSystem),
thisViewFrustum(*voxelSystem->getViewFrustum()),
nodesScanned(0)
{
}
};
void VoxelSystem::showAllLocalVoxels() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "showAllLocalVoxels()");
showAllLocalVoxelsArgs args(this);
_tree->recurseTreeWithOperation(showAllLocalVoxelsOperation,(void*)&args);
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
if (showRemoveDebugDetails) {
qDebug("showAllLocalVoxels() scanned=%ld \n",args.nodesScanned );
}
}
bool VoxelSystem::showAllLocalVoxelsOperation(VoxelNode* node, void* extraData) {
showAllLocalVoxelsArgs* args = (showAllLocalVoxelsArgs*)extraData;
args->nodesScanned++;
bool shouldRender = true; // node->calculateShouldRender(&args->thisViewFrustum);
node->setShouldRender(shouldRender);
if (shouldRender) {
bool falseColorize = false;
if (falseColorize) {
node->setFalseColor(0,0,255); // false colorize
}
// These are both needed to force redraw...
node->setDirtyBit();
node->markWithChangedTime();
}
return true; // keep recursing!
}
// combines the removeOutOfView args into a single class
class hideOutOfViewArgs {
public:
VoxelSystem* thisVoxelSystem;
VoxelTree* tree;
ViewFrustum thisViewFrustum;
unsigned long nodesScanned;
unsigned long nodesRemoved;
unsigned long nodesInside;
unsigned long nodesIntersect;
unsigned long nodesOutside;
VoxelSystem* thisVoxelSystem;
VoxelTree* tree;
ViewFrustum thisViewFrustum;
ViewFrustum lastViewFrustum;
bool culledOnce;
bool wantDeltaFrustums;
unsigned long nodesScanned;
unsigned long nodesRemoved;
unsigned long nodesInside;
unsigned long nodesIntersect;
unsigned long nodesOutside;
unsigned long nodesInsideInside;
unsigned long nodesIntersectInside;
unsigned long nodesOutsideInside;
unsigned long nodesInsideOutside;
unsigned long nodesOutsideOutside;
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, bool widenViewFrustum = true) :
hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree,
bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) :
thisVoxelSystem(voxelSystem),
tree(tree),
thisViewFrustum(*voxelSystem->getViewFrustum()),
lastViewFrustum(*voxelSystem->getLastCulledViewFrustum()),
culledOnce(culledOnce),
wantDeltaFrustums(wantDeltaFrustums),
nodesScanned(0),
nodesRemoved(0),
nodesInside(0),
nodesIntersect(0),
nodesOutside(0)
nodesOutside(0),
nodesInsideInside(0),
nodesIntersectInside(0),
nodesOutsideInside(0),
nodesInsideOutside(0),
nodesOutsideOutside(0)
{
// Widen the FOV for trimming
if (widenViewFrustum) {
@ -1685,34 +1807,88 @@ public:
};
void VoxelSystem::hideOutOfView() {
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "hideOutOfView()");
hideOutOfViewArgs args(this, this->_tree, true); // widen to match server!
bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails);
bool widenFrustum = true;
bool wantDeltaFrustums = false; // Menu::getInstance()->isOptionChecked(MenuOption::UseDeltaFrustumInHide);
hideOutOfViewArgs args(this, this->_tree, _culledOnce, widenFrustum, wantDeltaFrustums);
const bool wantViewFrustumDebugging = false; // change to true for additional debugging
if (wantViewFrustumDebugging) {
args.thisViewFrustum.printDebugDetails();
if (_culledOnce) {
args.lastViewFrustum.printDebugDetails();
}
}
if (_culledOnce && args.lastViewFrustum.matches(args.thisViewFrustum)) {
//printf("view frustum hasn't changed BAIL!!!\n");
return;
}
// Changed hideOutOfView() to support "delta" view frustums and only hide/show items that are in the difference
// between the two view frustums. There are some potential problems with this idea...
//
// 1) This might work well for rotating, but what about moving forward?
// in the move forward case, you'll get new voxel details, but those
// new voxels will be in the last view... does that work? This works
// ok for now because voxel server resends them and so they get redisplayed,
// but this will not work if we update the voxel server to send less data.
//
// 2) what about voxels coming in from the network that are OUTSIDE of the view
// frustum... they don't get hidden... and so we can't assume they are correctly
// hidden... we could solve this with checking in view on voxelUpdated...
//
_tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args);
_lastCulledViewFrustum = args.thisViewFrustum; // save last stable
_culledOnce = true;
if (args.nodesRemoved) {
_tree->setDirtyBit();
setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY);
}
bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings);
if (showRemoveDebugDetails) {
if (showDebugDetails) {
qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n",
args.nodesScanned, args.nodesRemoved, args.nodesInside,
args.nodesIntersect, args.nodesOutside
);
qDebug(" inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n",
args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside
);
}
}
bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
// consider that case.
ViewFrustum::location inLastCulledFrustum;
if (args->culledOnce && args->wantDeltaFrustums) {
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
// if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further
if (inLastCulledFrustum == ViewFrustum::OUTSIDE) {
args->nodesOutsideOutside++;
return false;
}
}
args->nodesOutside++;
if (node->isKnownBufferIndex()) {
args->nodesRemoved++;
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
bool falseColorize = false;
if (falseColorize) {
node->setFalseColor(255,0,0); // false colorize
} else {
VoxelSystem* thisVoxelSystem = args->thisVoxelSystem;
thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(node);
thisVoxelSystem->setupNewVoxelsForDrawingSingleNode();
}
}
return true;
@ -1721,17 +1897,39 @@ bool VoxelSystem::hideAllSubTreeOperation(VoxelNode* node, void* extraData) {
bool VoxelSystem::showAllSubTreeOperation(VoxelNode* node, void* extraData) {
hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData;
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
// consider that case.
ViewFrustum::location inLastCulledFrustum;
if (args->culledOnce && args->wantDeltaFrustums) {
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
// if this node is fully inside our last culled view frustum, then we don't need to recurse further
if (inLastCulledFrustum == ViewFrustum::INSIDE) {
args->nodesInsideInside++;
return false;
}
}
args->nodesInside++;
if (node->getShouldRender() && !node->isKnownBufferIndex()) {
node->setDirtyBit(); // will this make it draw!
bool shouldRender = node->calculateShouldRender(&args->thisViewFrustum);
node->setShouldRender(shouldRender);
if (shouldRender && !node->isKnownBufferIndex()) {
bool falseColorize = false;
if (falseColorize) {
node->setFalseColor(0,0,255); // false colorize
}
// These are both needed to force redraw...
node->setDirtyBit();
node->markWithChangedTime();
}
return true; // keep recursing!
}
// "hide" voxels in the VBOs that are still in the tree that but not in view.
// We don't remove them from the tree, we don't delete them, we do remove them
// from the VBOs and mark them as such in the tree.
@ -1741,26 +1939,66 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) {
// If we're still recursing the tree using this operator, then we don't know if we're inside or outside...
// so before we move forward we need to determine our frustum location
ViewFrustum::location inFrustum = node->inFrustum(args->thisViewFrustum);
// If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine
// how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not
// consider that case.
ViewFrustum::location inLastCulledFrustum;
if (args->culledOnce && args->wantDeltaFrustums) {
inLastCulledFrustum = node->inFrustum(args->lastViewFrustum);
}
// ok, now do some processing for this node...
switch (inFrustum) {
case ViewFrustum::OUTSIDE: {
// if this node is fully OUTSIDE the view, then we know that ALL of it's children are also fully OUTSIDE
// so we can recurse the children and simply mark them as hidden
// If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE,
// if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume
// that all of it's children are outside both of our views, in which case we can just stop recursing...
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::OUTSIDE) {
args->nodesScanned++;
args->nodesOutsideOutside++;
return false; // stop recursing this branch!
}
// if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then
// we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse
// the children and simply mark them as hidden
args->tree->recurseNodeWithOperation(node, hideAllSubTreeOperation, args );
return false;
} break;
case ViewFrustum::INSIDE: {
// if this node is fully INSIDE the view, then we know that ALL of it's children are also fully INSIDE
// so we can recurse the children and simply mark them as visible (as appropriate based on LOD)
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args );
// If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE,
// if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume
// that all of it's children are INSIDE both of our views, in which case we can just stop recursing...
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
args->nodesScanned++;
args->nodesInsideInside++;
return false; // stop recursing this branch!
}
// if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then
// we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse
// the children and simply mark them as visible (as appropriate based on LOD)
args->tree->recurseNodeWithOperation(node, showAllSubTreeOperation, args);
return false;
} break;
case ViewFrustum::INTERSECT: {
args->nodesScanned++;
// If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE
// the last known view, in which case it will already be visible, and we know that all it's children are also
// previously INSIDE and visible. So in this case stop recursing
if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) {
args->nodesIntersectInside++;
return false; // stop recursing this branch!
}
args->nodesIntersect++;
// if the child node INTERSECTs the view, then we want to check to see if it thinks it should render
@ -1886,6 +2124,7 @@ public:
};
bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData) {
collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData;
args->totalNodes++;

View file

@ -59,6 +59,9 @@ public:
void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }
unsigned long getVoxelsUpdated() const { return _voxelsUpdated; }
unsigned long getVoxelsRendered() const { return _voxelsInReadArrays; }
unsigned long getVoxelsWritten() const { return _voxelsInWriteArrays; }
ViewFrustum* getLastCulledViewFrustum() { return &_lastCulledViewFrustum; }
void loadVoxelsFile(const char* fileName,bool wantColorRandomizer);
void writeToSVOFile(const char* filename, VoxelNode* node) const;
@ -123,6 +126,7 @@ public slots:
void collectStatsForTreesAndVBOs();
// Methods that recurse tree
void showAllLocalVoxels();
void randomizeVoxelColors();
void falseColorizeRandom();
void trueColorize();
@ -192,6 +196,7 @@ private:
static bool hideOutOfViewUnrollOperation(VoxelNode* node, void* extraData);
static bool hideAllSubTreeOperation(VoxelNode* node, void* extraData);
static bool showAllSubTreeOperation(VoxelNode* node, void* extraData);
static bool showAllLocalVoxelsOperation(VoxelNode* node, void* extraData);
int updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw);
int forceRemoveNodeFromArrays(VoxelNode* node);
@ -252,10 +257,13 @@ private:
pthread_mutex_t _bufferWriteLock;
pthread_mutex_t _treeLock;
ViewFrustum _lastKnowViewFrustum;
ViewFrustum _lastKnownViewFrustum;
ViewFrustum _lastStableViewFrustum;
ViewFrustum* _viewFrustum;
ViewFrustum _lastCulledViewFrustum; // used for hide/show visible passes
bool _culledOnce;
void setupFaceIndices(GLuint& faceVBOID, GLubyte faceIdentityIndices[]);
int newTreeToArrays(VoxelNode *currentNode);

View file

@ -94,7 +94,8 @@ private:
static bool _suppressShortTimings;
public:
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false, uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
PerformanceWarning(bool renderWarnings, const char* message, bool alwaysDisplay = false,
uint64_t* runningTotal = NULL, uint64_t* totalCalls = NULL) :
_start(usecTimestampNow()),
_message(message),
_renderWarningsOn(renderWarnings),

View file

@ -79,6 +79,7 @@ void VoxelNode::init(unsigned char * octalCode) {
_unknownBufferIndex = true;
setBufferIndex(GLBUFFER_INDEX_UNKNOWN);
setVoxelSystem(NULL);
_isDirty = true;
_shouldRender = false;
@ -104,18 +105,8 @@ VoxelNode::~VoxelNode() {
delete[] _octalCode.pointer;
}
// delete all of this node's children
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
VoxelNode* childAt = getChildAtIndex(i);
if (childAt) {
delete childAt;
setChildAtIndex(i, NULL);
}
}
// at this point, we should have no children, but we need to drop ourselves from population counts
_singleChildrenCount--;
_childrenCount[0]--;
// delete all of this node's children, this also takes care of all population tracking data
deleteAllChildren();
}
void VoxelNode::markWithChangedTime() {
@ -146,7 +137,9 @@ std::map<uint8_t, VoxelSystem*> VoxelNode::_mapIndexToVoxelSystemPointers;
VoxelSystem* VoxelNode::getVoxelSystem() const {
if (_voxelSystemIndex > INDEX_FOR_NULL) {
if (_mapIndexToVoxelSystemPointers.end() != _mapIndexToVoxelSystemPointers.find(_voxelSystemIndex)) {
return _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
VoxelSystem* voxelSystem = _mapIndexToVoxelSystemPointers[_voxelSystemIndex];
return voxelSystem;
}
}
return NULL;
@ -287,7 +280,8 @@ void VoxelNode::auditChildren(const char* label) const {
}
}
if (auditFailed) {
const bool alwaysReport = false; // set this to true to get additional debugging
if (alwaysReport || auditFailed) {
qDebug("%s... auditChildren() %s <<<< \n", label, (auditFailed ? "FAILED" : "PASSED"));
qDebug(" _childrenExternal=%s\n", debug::valueOf(_childrenExternal));
qDebug(" childCount=%d\n", getChildCount());
@ -605,6 +599,60 @@ void VoxelNode::checkStoreFourChildren(VoxelNode* childOne, VoxelNode* childTwo,
}
}
void VoxelNode::deleteAllChildren() {
// first delete all the VoxelNode objects...
for (int i = 0; i < NUMBER_OF_CHILDREN; i++) {
VoxelNode* childAt = getChildAtIndex(i);
if (childAt) {
delete childAt;
}
}
// now, reset our internal state and ANY and all population data
int childCount = getChildCount();
switch (childCount) {
case 0: {
_singleChildrenCount--;
_childrenCount[0]--;
} break;
case 1: {
_singleChildrenCount--;
_childrenCount[1]--;
} break;
case 2: {
if (_childrenExternal) {
_twoChildrenExternalCount--;
} else {
_twoChildrenOffsetCount--;
}
_childrenCount[2]--;
} break;
case 3: {
if (_childrenExternal) {
_threeChildrenExternalCount--;
} else {
_threeChildrenOffsetCount--;
}
_childrenCount[3]--;
} break;
default: {
_externalChildrenCount--;
_childrenCount[childCount]--;
} break;
}
// If we had externally stored children, clean them too.
if (_childrenExternal && _children.external) {
delete[] _children.external;
}
_children.single = NULL;
}
void VoxelNode::setChildAtIndex(int childIndex, VoxelNode* child) {
PerformanceWarning warn(false,"setChildAtIndex",false,&_setChildAtIndexTime,&_setChildAtIndexCalls);

View file

@ -9,6 +9,8 @@
#ifndef __hifi__VoxelNode__
#define __hifi__VoxelNode__
//#define HAS_AUDIT_CHILDREN
#include <SharedUtil.h>
#include "AABox.h"
#include "ViewFrustum.h"
@ -144,6 +146,7 @@ public:
#endif // def HAS_AUDIT_CHILDREN
private:
void deleteAllChildren();
void setChildAtIndex(int childIndex, VoxelNode* child);
void storeTwoChildren(VoxelNode* childOne, VoxelNode* childTwo);
void retrieveTwoChildren(VoxelNode*& childOne, VoxelNode*& childTwo);

View file

@ -476,7 +476,9 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat
void VoxelTree::eraseAllVoxels() {
// XXXBHG Hack attack - is there a better way to erase the voxel tree?
delete rootNode; // this will recurse and delete all children
VoxelSystem* voxelSystem = rootNode->getVoxelSystem();
rootNode = new VoxelNode();
rootNode->setVoxelSystem(voxelSystem);
_isDirty = true;
}