Showing the changes to interface/src/VoxelSystem.cpp (1 of 202 files). Show all
Unified · Split
| @@ -103,9 +103,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) · 102 unmodified lines | |||
| 103 | 103 | ||
| 104 | _culledOnce = false; | 104 | _culledOnce = false; |
| 105 | _inhideOutOfView = false; | 105 | _inhideOutOfView = false; |
| 106 | _treeIsBusy = false; | ||
| 107 | |||
| 108 | |||
| 109 | } | 106 | } |
| 110 | 107 | ||
| 111 | void VoxelSystem::elementDeleted(OctreeElement* element) { | 108 | void VoxelSystem::elementDeleted(OctreeElement* element) { |
| @@ -570,30 +567,30 @@ int VoxelSystem::parseData(const QByteArray& packet) { · 458 unmodified lines | |||
| 570 | 567 | ||
| 571 | const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader; | 568 | const unsigned char* dataAt = reinterpret_cast<const unsigned char*>(packet.data()) + numBytesPacketHeader; |
| 572 | 569 | ||
| 573 | VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); | 570 | OCTREE_PACKET_FLAGS flags = (*(OCTREE_PACKET_FLAGS*)(dataAt)); |
| 574 | dataAt += sizeof(VOXEL_PACKET_FLAGS); | 571 | dataAt += sizeof(OCTREE_PACKET_FLAGS); |
| 575 | VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); | 572 | OCTREE_PACKET_SEQUENCE sequence = (*(OCTREE_PACKET_SEQUENCE*)dataAt); |
| 576 | dataAt += sizeof(VOXEL_PACKET_SEQUENCE); | 573 | dataAt += sizeof(OCTREE_PACKET_SEQUENCE); |
| 577 | 574 | ||
| 578 | VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); | 575 | OCTREE_PACKET_SENT_TIME sentAt = (*(OCTREE_PACKET_SENT_TIME*)dataAt); |
| 579 | dataAt += sizeof(VOXEL_PACKET_SENT_TIME); | 576 | dataAt += sizeof(OCTREE_PACKET_SENT_TIME); |
| 580 | 577 | ||
| 581 | bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); | 578 | bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); |
| 582 | bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); | 579 | bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); |
| 583 | 580 | ||
| 584 | VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); | 581 | OCTREE_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); |
| 585 | int flightTime = arrivedAt - sentAt; | 582 | int flightTime = arrivedAt - sentAt; |
| 586 | 583 | ||
| 587 | VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; | 584 | OCTREE_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; |
| 588 | int dataBytes = packet.size() - VOXEL_PACKET_HEADER_SIZE; | 585 | int dataBytes = packet.size() - (numBytesPacketHeader + OCTREE_PACKET_EXTRA_HEADERS_SIZE); |
| 589 | 586 | ||
| 590 | int subsection = 1; | 587 | int subsection = 1; |
| 591 | while (dataBytes > 0) { | 588 | while (dataBytes > 0) { |
| 592 | if (packetIsCompressed) { | 589 | if (packetIsCompressed) { |
| 593 | if (dataBytes > sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE)) { | 590 | if (dataBytes > sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE)) { |
| 594 | sectionLength = (*(VOXEL_PACKET_INTERNAL_SECTION_SIZE*)dataAt); | 591 | sectionLength = (*(OCTREE_PACKET_INTERNAL_SECTION_SIZE*)dataAt); |
| 595 | dataAt += sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); | 592 | dataAt += sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); |
| 596 | dataBytes -= sizeof(VOXEL_PACKET_INTERNAL_SECTION_SIZE); | 593 | dataBytes -= sizeof(OCTREE_PACKET_INTERNAL_SECTION_SIZE); |
| 597 | } else { | 594 | } else { |
| 598 | sectionLength = 0; | 595 | sectionLength = 0; |
| 599 | dataBytes = 0; // stop looping something is wrong | 596 | dataBytes = 0; // stop looping something is wrong |
| @@ -603,9 +600,10 @@ int VoxelSystem::parseData(const QByteArray& packet) { · 3 unmodified lines | |||
| 603 | } | 600 | } |
| 604 | 601 | ||
| 605 | if (sectionLength) { | 602 | if (sectionLength) { |
| 603 | PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() section"); | ||
| 606 | // ask the VoxelTree to read the bitstream into the tree | 604 | // ask the VoxelTree to read the bitstream into the tree |
| 607 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); | 605 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); |
| 608 | lockTree(); | 606 | _tree->lockForWrite(); |
| 609 | VoxelPacketData packetData(packetIsCompressed); | 607 | VoxelPacketData packetData(packetIsCompressed); |
| 610 | packetData.loadFinalizedContent(dataAt, sectionLength); | 608 | packetData.loadFinalizedContent(dataAt, sectionLength); |
| 611 | if (Application::getInstance()->getLogger()->extraDebugging()) { | 609 | if (Application::getInstance()->getLogger()->extraDebugging()) { |
| @@ -617,7 +615,7 @@ int VoxelSystem::parseData(const QByteArray& packet) { · 5 unmodified lines | |||
| 617 | packetData.getUncompressedSize()); | 615 | packetData.getUncompressedSize()); |
| 618 | } | 616 | } |
| 619 | _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); | 617 | _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); |
| 620 | unlockTree(); | 618 | _tree->unlock(); |
| 621 | 619 | ||
| 622 | dataBytes -= sectionLength; | 620 | dataBytes -= sectionLength; |
| 623 | dataAt += sectionLength; | 621 | dataAt += sectionLength; |
| @@ -1467,9 +1465,11 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { · 843 unmodified lines | |||
| 1467 | int VoxelSystem::_nodeCount = 0; | 1465 | int VoxelSystem::_nodeCount = 0; |
| 1468 | 1466 | ||
| 1469 | void VoxelSystem::killLocalVoxels() { | 1467 | void VoxelSystem::killLocalVoxels() { |
| 1470 | lockTree(); | 1468 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 1469 | "VoxelSystem::killLocalVoxels()"); | ||
| 1470 | _tree->lockForWrite(); | ||
| 1471 | _tree->eraseAllOctreeElements(); | 1471 | _tree->eraseAllOctreeElements(); |
| 1472 | unlockTree(); | 1472 | _tree->unlock(); |
| 1473 | clearFreeBufferIndexes(); | 1473 | clearFreeBufferIndexes(); |
| 1474 | _renderer->release(); | 1474 | _renderer->release(); |
| 1475 | _voxelsInReadArrays = 0; // do we need to do this? | 1475 | _voxelsInReadArrays = 0; // do we need to do this? |
| @@ -1490,10 +1490,12 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void · 14 unmodified lines | |||
| 1490 | } | 1490 | } |
| 1491 | 1491 | ||
| 1492 | void VoxelSystem::clearAllNodesBufferIndex() { | 1492 | void VoxelSystem::clearAllNodesBufferIndex() { |
| 1493 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 1494 | "VoxelSystem::clearAllNodesBufferIndex()"); | ||
| 1493 | _nodeCount = 0; | 1495 | _nodeCount = 0; |
| 1494 | lockTree(); | 1496 | _tree->lockForRead(); // we won't change the tree so it's ok to treat this as a read |
| 1495 | _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); | 1497 | _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); |
| 1496 | unlockTree(); | 1498 | _tree->unlock(); |
| 1497 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { | 1499 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { |
| 1498 | qDebug("clearing buffer index of %d nodes", _nodeCount); | 1500 | qDebug("clearing buffer index of %d nodes", _nodeCount); |
| 1499 | } | 1501 | } |
| @@ -1681,9 +1683,9 @@ void VoxelSystem::cullSharedFaces() { · 181 unmodified lines | |||
| 1681 | _usePrimitiveRenderer = false; | 1683 | _usePrimitiveRenderer = false; |
| 1682 | _renderer->release(); | 1684 | _renderer->release(); |
| 1683 | clearAllNodesBufferIndex(); | 1685 | clearAllNodesBufferIndex(); |
| 1684 | lockTree(); | 1686 | _tree->lockForRead(); |
| 1685 | _tree->recurseTreeWithOperation(clearOcclusionsOperation); | 1687 | _tree->recurseTreeWithOperation(clearOcclusionsOperation); |
| 1686 | unlockTree(); | 1688 | _tree->unlock(); |
| 1687 | 1689 | ||
| 1688 | 1690 | ||
| 1689 | qDebug("unculling shared faces in %d nodes", _nodeCount); | 1691 | qDebug("unculling shared faces in %d nodes", _nodeCount); |
| @@ -1720,10 +1722,10 @@ void VoxelSystem::inspectForOcclusions() { · 30 unmodified lines | |||
| 1720 | bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 1722 | bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1721 | PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); | 1723 | PerformanceWarning warn(showDebugDetails, "inspectForOcclusions()"); |
| 1722 | 1724 | ||
| 1723 | lockTree(); | 1725 | _tree->lockForRead(); |
| 1724 | _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); | 1726 | _tree->recurseTreeWithPostOperation(inspectForExteriorOcclusionsOperation); |
| 1725 | _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); | 1727 | _tree->recurseTreeWithOperation(inspectForInteriorOcclusionsOperation); |
| 1726 | unlockTree(); | 1728 | _tree->unlock(); |
| 1727 | 1729 | ||
| 1728 | _inInspectForOcclusions = false; | 1730 | _inInspectForOcclusions = false; |
| 1729 | } | 1731 | } |
| @@ -1784,7 +1786,8 @@ bool VoxelSystem::trueColorizeOperation(OctreeElement* element, void* extraData) · 54 unmodified lines | |||
| 1784 | } | 1786 | } |
| 1785 | 1787 | ||
| 1786 | void VoxelSystem::trueColorize() { | 1788 | void VoxelSystem::trueColorize() { |
| 1787 | PerformanceWarning warn(true, "trueColorize()",true); | 1789 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 1790 | "trueColorize()",true); | ||
| 1788 | _nodeCount = 0; | 1791 | _nodeCount = 0; |
| 1789 | _tree->recurseTreeWithOperation(trueColorizeOperation); | 1792 | _tree->recurseTreeWithOperation(trueColorizeOperation); |
| 1790 | qDebug("setting true color for %d nodes", _nodeCount); | 1793 | qDebug("setting true color for %d nodes", _nodeCount); |
| @@ -2254,9 +2257,13 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { · 463 unmodified lines | |||
| 2254 | return; | 2257 | return; |
| 2255 | } | 2258 | } |
| 2256 | 2259 | ||
| 2257 | lockTree(); | 2260 | { |
| 2258 | _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); | 2261 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2259 | unlockTree(); | 2262 | "VoxelSystem::... recurseTreeWithOperation(hideOutOfViewOperation)"); |
| 2263 | _tree->lockForRead(); | ||
| 2264 | _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); | ||
| 2265 | _tree->unlock(); | ||
| 2266 | } | ||
| 2260 | _lastCulledViewFrustum = args.thisViewFrustum; // save last stable | 2267 | _lastCulledViewFrustum = args.thisViewFrustum; // save last stable |
| 2261 | _culledOnce = true; | 2268 | _culledOnce = true; |
| 2262 | 2269 | ||
| @@ -2459,35 +2466,47 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 196 unmodified lines | |||
| 2459 | 2466 | ||
| 2460 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 2467 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 2461 | VoxelDetail& detail, float& distance, BoxFace& face) { | 2468 | VoxelDetail& detail, float& distance, BoxFace& face) { |
| 2462 | lockTree(); | 2469 | |
| 2463 | OctreeElement* element; | 2470 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2464 | if (!_tree->findRayIntersection(origin, direction, element, distance, face)) { | 2471 | "VoxelSystem::findRayIntersection()"); |
| 2465 | unlockTree(); | 2472 | bool result = false; // assume no intersection |
| 2466 | return false; | 2473 | if (_tree->tryLockForRead()) { |
| 2474 | OctreeElement* element; | ||
| 2475 | result = _tree->findRayIntersection(origin, direction, element, distance, face); | ||
| 2476 | if (result) { | ||
| 2477 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2478 | detail.x = voxel->getCorner().x; | ||
| 2479 | detail.y = voxel->getCorner().y; | ||
| 2480 | detail.z = voxel->getCorner().z; | ||
| 2481 | detail.s = voxel->getScale(); | ||
| 2482 | detail.red = voxel->getColor()[0]; | ||
| 2483 | detail.green = voxel->getColor()[1]; | ||
| 2484 | detail.blue = voxel->getColor()[2]; | ||
| 2485 | } | ||
| 2486 | _tree->unlock(); | ||
| 2467 | } | 2487 | } |
| 2468 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | 2488 | return result; |
| 2469 | detail.x = voxel->getCorner().x; | ||
| 2470 | detail.y = voxel->getCorner().y; | ||
| 2471 | detail.z = voxel->getCorner().z; | ||
| 2472 | detail.s = voxel->getScale(); | ||
| 2473 | detail.red = voxel->getColor()[0]; | ||
| 2474 | detail.green = voxel->getColor()[1]; | ||
| 2475 | detail.blue = voxel->getColor()[2]; | ||
| 2476 | unlockTree(); | ||
| 2477 | return true; | ||
| 2478 | } | 2489 | } |
| 2479 | 2490 | ||
| 2480 | bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { | 2491 | bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { |
| 2481 | lockTree(); | 2492 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2482 | bool result = _tree->findSpherePenetration(center, radius, penetration); | 2493 | "VoxelSystem::findSpherePenetration()"); |
| 2483 | unlockTree(); | 2494 | bool result = false; // assume no penetration |
| 2495 | if (_tree->tryLockForRead()) { | ||
| 2496 | result = _tree->findSpherePenetration(center, radius, penetration); | ||
| 2497 | _tree->unlock(); | ||
| 2498 | } | ||
| 2484 | return result; | 2499 | return result; |
| 2485 | } | 2500 | } |
| 2486 | 2501 | ||
| 2487 | bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { | 2502 | bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { |
| 2488 | lockTree(); | 2503 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2489 | bool result = _tree->findCapsulePenetration(start, end, radius, penetration); | 2504 | "VoxelSystem::findCapsulePenetration()"); |
| 2490 | unlockTree(); | 2505 | bool result = false; // assume no penetration |
| 2506 | if (_tree->tryLockForRead()) { | ||
| 2507 | result = _tree->findCapsulePenetration(start, end, radius, penetration); | ||
| 2508 | _tree->unlock(); | ||
| 2509 | } | ||
| 2491 | return result; | 2510 | return result; |
| 2492 | } | 2511 | } |
| 2493 | 2512 | ||
| @@ -2695,13 +2714,14 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 201 unmodified lines | |||
| 2695 | 2714 | ||
| 2696 | 2715 | ||
| 2697 | void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { | 2716 | void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { |
| 2698 | lockTree(); | 2717 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2718 | "VoxelSystem::deleteVoxelAt()"); | ||
| 2719 | _tree->lockForWrite(); | ||
| 2699 | _tree->deleteVoxelAt(x, y, z, s); | 2720 | _tree->deleteVoxelAt(x, y, z, s); |
| 2700 | unlockTree(); | 2721 | _tree->unlock(); |
| 2701 | 2722 | ||
| 2702 | // redraw! | 2723 | // redraw! |
| 2703 | setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? | 2724 | setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? |
| 2704 | |||
| 2705 | }; | 2725 | }; |
| 2706 | 2726 | ||
| 2707 | VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { | 2727 | VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { |
| @@ -2711,10 +2731,12 @@ VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) co · 3 unmodified lines | |||
| 2711 | void VoxelSystem::createVoxel(float x, float y, float z, float s, | 2731 | void VoxelSystem::createVoxel(float x, float y, float z, float s, |
| 2712 | unsigned char red, unsigned char green, unsigned char blue, bool destructive) { | 2732 | unsigned char red, unsigned char green, unsigned char blue, bool destructive) { |
| 2713 | 2733 | ||
| 2714 | //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); | 2734 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 2715 | lockTree(); | 2735 | "VoxelSystem::createVoxel()"); |
| 2736 | |||
| 2737 | _tree->lockForWrite(); | ||
| 2716 | _tree->createVoxel(x, y, z, s, red, green, blue, destructive); | 2738 | _tree->createVoxel(x, y, z, s, red, green, blue, destructive); |
| 2717 | unlockTree(); | 2739 | _tree->unlock(); |
| 2718 | 2740 | ||
| 2719 | setupNewVoxelsForDrawing(); | 2741 | setupNewVoxelsForDrawing(); |
| 2720 | }; | 2742 | }; |
| @@ -3085,38 +3107,6 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() { · 364 unmodified lines | |||
| 3085 | return (_initialMemoryUsageGPU - currentFreeMemory); | 3107 | return (_initialMemoryUsageGPU - currentFreeMemory); |
| 3086 | } | 3108 | } |
| 3087 | 3109 | ||
| 3088 | void VoxelSystem::lockTree() { | ||
| 3089 | _treeLock.lock(); | ||
| 3090 | _treeIsBusy = true; | ||
| 3091 | } | ||
| 3092 | |||
| 3093 | void VoxelSystem::unlockTree() { | ||
| 3094 | _treeIsBusy = false; | ||
| 3095 | _treeLock.unlock(); | ||
| 3096 | } | ||
| 3097 | |||
| 3098 | |||
| 3099 | void VoxelSystem::localVoxelCacheLoaded() { | ||
| 3100 | qDebug() << "localVoxelCacheLoaded()"; | ||
| 3101 | |||
| 3102 | // Make sure that the application has properly set up the view frustum for our loaded state | ||
| 3103 | Application::getInstance()->initAvatarAndViewFrustum(); | ||
| 3104 | |||
| 3105 | _tree->setDirtyBit(); // make sure the tree thinks it's dirty | ||
| 3106 | _setupNewVoxelsForDrawingLastFinished = 0; // don't allow the setupNewVoxelsForDrawing() shortcuts | ||
| 3107 | _writeRenderFullVBO = true; // this will disable individual node updates, was reset by killLocalVoxels() | ||
| 3108 | setupNewVoxelsForDrawing(); | ||
| 3109 | _inhideOutOfView = false; // reenable hideOutOfView behavior | ||
| 3110 | } | ||
| 3111 | |||
| 3112 | void VoxelSystem::beginLoadingLocalVoxelCache() { | ||
| 3113 | qDebug() << "beginLoadingLocalVoxelCache()"; | ||
| 3114 | _writeRenderFullVBO = true; // this will disable individual node updates | ||
| 3115 | _inhideOutOfView = true; // this will disable hidOutOfView which we want to do until local cache is loaded | ||
| 3116 | killLocalVoxels(); | ||
| 3117 | qDebug() << "DONE beginLoadingLocalVoxelCache()"; | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | // Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index | 3110 | // Octant bitmask array indexed by octant. The mask value indicates the octant's halfspace partitioning. The index |
| 3121 | // value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* | 3111 | // value corresponds to the voxel's octal code derived in "pointToVoxel" in SharedUtil.cpp, which, BTW, does *not* |
| 3122 | // correspond to the "ChildIndex" enum value in OctreeElement.h | 3112 | // correspond to the "ChildIndex" enum value in OctreeElement.h |