Showing the changes to interface/src/VoxelSystem.cpp (1 of 140 files). Show all
Unified · Split
| @@ -18,8 +18,6 @@ · 17 unmodified lines | |||
| 18 | #include <NodeList.h> | 18 | #include <NodeList.h> |
| 19 | 19 | ||
| 20 | #include "Application.h" | 20 | #include "Application.h" |
| 21 | #include "CoverageMap.h" | ||
| 22 | #include "CoverageMapV2.h" | ||
| 23 | #include "InterfaceConfig.h" | 21 | #include "InterfaceConfig.h" |
| 24 | #include "Menu.h" | 22 | #include "Menu.h" |
| 25 | #include "renderer/ProgramObject.h" | 23 | #include "renderer/ProgramObject.h" |
| @@ -84,9 +82,6 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels, VoxelTree* tree) · 58 unmodified lines | |||
| 84 | 82 | ||
| 85 | _viewFrustum = Application::getInstance()->getViewFrustum(); | 83 | _viewFrustum = Application::getInstance()->getViewFrustum(); |
| 86 | 84 | ||
| 87 | connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); | ||
| 88 | connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); | ||
| 89 | |||
| 90 | _useVoxelShader = false; | 85 | _useVoxelShader = false; |
| 91 | _voxelsAsPoints = false; | 86 | _voxelsAsPoints = false; |
| 92 | _voxelShaderModeWhenVoxelsAsPointsEnabled = false; | 87 | _voxelShaderModeWhenVoxelsAsPointsEnabled = false; |
| @@ -206,31 +201,16 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { · 113 unmodified lines | |||
| 206 | qDebug() << "freeBufferIndex() called when _voxelsInWriteArrays == 0!"; | 201 | qDebug() << "freeBufferIndex() called when _voxelsInWriteArrays == 0!"; |
| 207 | } | 202 | } |
| 208 | 203 | ||
| 209 | // if the "freed" index was our max index, then just drop the _voxelsInWriteArrays down one... | 204 | // make the index available for next node that needs to be drawn |
| 210 | bool inList = false; | 205 | _freeIndexLock.lock(); |
| 211 | 206 | _freeIndexes.push_back(index); | |
| 212 | // make sure the index isn't already in the free list..., this is a debugging measure only done if you've enabled audits | 207 | _freeIndexLock.unlock(); |
| 213 | if (Menu::getInstance()->isOptionChecked(MenuOption::AutomaticallyAuditTree)) { | ||
| 214 | for (unsigned long i = 0; i < _freeIndexes.size(); i++) { | ||
| 215 | if (_freeIndexes[i] == index) { | ||
| 216 | printf("freeBufferIndex(glBufferIndex index)... index=%ld already in free list!", index); | ||
| 217 | inList = true; | ||
| 218 | break; | ||
| 219 | } | ||
| 220 | } | ||
| 221 | } | ||
| 222 | if (!inList) { | ||
| 223 | // make the index available for next node that needs to be drawn | ||
| 224 | _freeIndexLock.lock(); | ||
| 225 | _freeIndexes.push_back(index); | ||
| 226 | _freeIndexLock.unlock(); | ||
| 227 | 208 | ||
| 228 | // make the VBO slot "invisible" in case this slot is not used | 209 | // make the VBO slot "invisible" in case this slot is not used |
| 229 | const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); | 210 | const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); |
| 230 | const float voxelScale = 0; | 211 | const float voxelScale = 0; |
| 231 | const nodeColor BLACK = {0, 0, 0, 0}; | 212 | const nodeColor BLACK = {0, 0, 0, 0}; |
| 232 | updateArraysDetails(index, startVertex, voxelScale, BLACK); | 213 | updateArraysDetails(index, startVertex, voxelScale, BLACK); |
| 233 | } | ||
| 234 | } | 214 | } |
| 235 | 215 | ||
| 236 | // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". | 216 | // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". |
| @@ -541,34 +521,6 @@ void VoxelSystem::initVoxelMemory() { · 304 unmodified lines | |||
| 541 | _readArraysLock.unlock(); | 521 | _readArraysLock.unlock(); |
| 542 | } | 522 | } |
| 543 | 523 | ||
| 544 | void VoxelSystem::writeToSVOFile(const char* filename, VoxelTreeElement* element) const { | ||
| 545 | _tree->writeToSVOFile(filename, element); | ||
| 546 | } | ||
| 547 | |||
| 548 | bool VoxelSystem::readFromSVOFile(const char* filename) { | ||
| 549 | bool result = _tree->readFromSVOFile(filename); | ||
| 550 | if (result) { | ||
| 551 | setupNewVoxelsForDrawing(); | ||
| 552 | } | ||
| 553 | return result; | ||
| 554 | } | ||
| 555 | |||
| 556 | bool VoxelSystem::readFromSquareARGB32Pixels(const char *filename) { | ||
| 557 | bool result = _tree->readFromSquareARGB32Pixels(filename); | ||
| 558 | if (result) { | ||
| 559 | setupNewVoxelsForDrawing(); | ||
| 560 | } | ||
| 561 | return result; | ||
| 562 | } | ||
| 563 | |||
| 564 | bool VoxelSystem::readFromSchematicFile(const char* filename) { | ||
| 565 | bool result = _tree->readFromSchematicFile(filename); | ||
| 566 | if (result) { | ||
| 567 | setupNewVoxelsForDrawing(); | ||
| 568 | } | ||
| 569 | return result; | ||
| 570 | } | ||
| 571 | |||
| 572 | int VoxelSystem::parseData(const QByteArray& packet) { | 524 | int VoxelSystem::parseData(const QByteArray& packet) { |
| 573 | bool showTimingDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 525 | bool showTimingDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 574 | PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData()",showTimingDetails); | 526 | PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData()",showTimingDetails); |
| @@ -618,7 +570,7 @@ int VoxelSystem::parseData(const QByteArray& packet) { · 43 unmodified lines | |||
| 618 | // ask the VoxelTree to read the bitstream into the tree | 570 | // ask the VoxelTree to read the bitstream into the tree |
| 619 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); | 571 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); |
| 620 | _tree->lockForWrite(); | 572 | _tree->lockForWrite(); |
| 621 | VoxelPacketData packetData(packetIsCompressed); | 573 | OctreePacketData packetData(packetIsCompressed); |
| 622 | packetData.loadFinalizedContent(dataAt, sectionLength); | 574 | packetData.loadFinalizedContent(dataAt, sectionLength); |
| 623 | if (Application::getInstance()->getLogger()->extraDebugging()) { | 575 | if (Application::getInstance()->getLogger()->extraDebugging()) { |
| 624 | qDebug("VoxelSystem::parseData() ... Got Packet Section" | 576 | qDebug("VoxelSystem::parseData() ... Got Packet Section" |
| @@ -692,8 +644,6 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 67 unmodified lines | |||
| 692 | _abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier???? | 644 | _abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier???? |
| 693 | } | 645 | } |
| 694 | 646 | ||
| 695 | // since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are | ||
| 696 | // ok again, until/unless we call removeOutOfView() | ||
| 697 | _writeRenderFullVBO = false; | 647 | _writeRenderFullVBO = false; |
| 698 | } else { | 648 | } else { |
| 699 | _voxelsUpdated = 0; | 649 | _voxelsUpdated = 0; |
| @@ -886,15 +836,6 @@ void VoxelSystem::checkForCulling() { · 186 unmodified lines | |||
| 886 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on | 836 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on |
| 887 | // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. | 837 | // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. |
| 888 | cleanupRemovedVoxels(); | 838 | cleanupRemovedVoxels(); |
| 889 | |||
| 890 | quint64 sinceLastAudit = (start - _lastAudit) / 1000; | ||
| 891 | |||
| 892 | if (Menu::getInstance()->isOptionChecked(MenuOption::AutomaticallyAuditTree)) { | ||
| 893 | if (sinceLastAudit >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) { | ||
| 894 | _lastAudit = start; | ||
| 895 | collectStatsForTreesAndVBOs(); | ||
| 896 | } | ||
| 897 | } | ||
| 898 | } | 839 | } |
| 899 | 840 | ||
| 900 | void VoxelSystem::cleanupRemovedVoxels() { | 841 | void VoxelSystem::cleanupRemovedVoxels() { |
| @@ -1241,9 +1182,6 @@ void VoxelSystem::changeTree(VoxelTree* newTree) { · 340 unmodified lines | |||
| 1241 | _tree->setDirtyBit(); | 1182 | _tree->setDirtyBit(); |
| 1242 | _tree->getRoot()->setVoxelSystem(this); | 1183 | _tree->getRoot()->setVoxelSystem(this); |
| 1243 | 1184 | ||
| 1244 | connect(_tree, SIGNAL(importSize(float,float,float)), SIGNAL(importSize(float,float,float))); | ||
| 1245 | connect(_tree, SIGNAL(importProgress(int)), SIGNAL(importProgress(int))); | ||
| 1246 | |||
| 1247 | setupNewVoxelsForDrawing(); | 1185 | setupNewVoxelsForDrawing(); |
| 1248 | } | 1186 | } |
| 1249 | 1187 | ||
| @@ -1830,329 +1768,6 @@ void VoxelSystem::forceRedrawEntireTree() { · 580 unmodified lines | |||
| 1830 | setupNewVoxelsForDrawing(); | 1768 | setupNewVoxelsForDrawing(); |
| 1831 | } | 1769 | } |
| 1832 | 1770 | ||
| 1833 | bool VoxelSystem::randomColorOperation(OctreeElement* element, void* extraData) { | ||
| 1834 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1835 | _nodeCount++; | ||
| 1836 | if (voxel->isColored()) { | ||
| 1837 | nodeColor newColor = { 255, randomColorValue(150), randomColorValue(150), 1 }; | ||
| 1838 | voxel->setColor(newColor); | ||
| 1839 | } | ||
| 1840 | return true; | ||
| 1841 | } | ||
| 1842 | |||
| 1843 | void VoxelSystem::randomizeVoxelColors() { | ||
| 1844 | _nodeCount = 0; | ||
| 1845 | _tree->recurseTreeWithOperation(randomColorOperation); | ||
| 1846 | qDebug("setting randomized true color for %d nodes", _nodeCount); | ||
| 1847 | _tree->setDirtyBit(); | ||
| 1848 | setupNewVoxelsForDrawing(); | ||
| 1849 | } | ||
| 1850 | |||
| 1851 | bool VoxelSystem::falseColorizeRandomOperation(OctreeElement* element, void* extraData) { | ||
| 1852 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1853 | _nodeCount++; | ||
| 1854 | // always false colorize | ||
| 1855 | voxel->setFalseColor(255, randomColorValue(150), randomColorValue(150)); | ||
| 1856 | return true; // keep going! | ||
| 1857 | } | ||
| 1858 | |||
| 1859 | void VoxelSystem::falseColorizeRandom() { | ||
| 1860 | _nodeCount = 0; | ||
| 1861 | _tree->recurseTreeWithOperation(falseColorizeRandomOperation); | ||
| 1862 | qDebug("setting randomized false color for %d nodes", _nodeCount); | ||
| 1863 | _tree->setDirtyBit(); | ||
| 1864 | setupNewVoxelsForDrawing(); | ||
| 1865 | } | ||
| 1866 | |||
| 1867 | bool VoxelSystem::trueColorizeOperation(OctreeElement* element, void* extraData) { | ||
| 1868 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1869 | _nodeCount++; | ||
| 1870 | voxel->setFalseColored(false); | ||
| 1871 | return true; | ||
| 1872 | } | ||
| 1873 | |||
| 1874 | void VoxelSystem::trueColorize() { | ||
| 1875 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 1876 | "trueColorize()",true); | ||
| 1877 | _nodeCount = 0; | ||
| 1878 | _tree->recurseTreeWithOperation(trueColorizeOperation); | ||
| 1879 | qDebug("setting true color for %d nodes", _nodeCount); | ||
| 1880 | _tree->setDirtyBit(); | ||
| 1881 | setupNewVoxelsForDrawing(); | ||
| 1882 | } | ||
| 1883 | |||
| 1884 | // Will false colorize voxels that are not in view | ||
| 1885 | bool VoxelSystem::falseColorizeInViewOperation(OctreeElement* element, void* extraData) { | ||
| 1886 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1887 | const ViewFrustum* viewFrustum = (const ViewFrustum*) extraData; | ||
| 1888 | _nodeCount++; | ||
| 1889 | if (voxel->isColored()) { | ||
| 1890 | if (!voxel->isInView(*viewFrustum)) { | ||
| 1891 | // Out of view voxels are colored RED | ||
| 1892 | voxel->setFalseColor(255, 0, 0); | ||
| 1893 | } | ||
| 1894 | } | ||
| 1895 | return true; // keep going! | ||
| 1896 | } | ||
| 1897 | |||
| 1898 | void VoxelSystem::falseColorizeInView() { | ||
| 1899 | _nodeCount = 0; | ||
| 1900 | _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)_viewFrustum); | ||
| 1901 | qDebug("setting in view false color for %d nodes", _nodeCount); | ||
| 1902 | _tree->setDirtyBit(); | ||
| 1903 | setupNewVoxelsForDrawing(); | ||
| 1904 | } | ||
| 1905 | |||
| 1906 | class VoxelAndPoint { | ||
| 1907 | public: | ||
| 1908 | VoxelTreeElement* voxel; | ||
| 1909 | glm::vec3 point; | ||
| 1910 | }; | ||
| 1911 | |||
| 1912 | // Find the smallest colored voxel enclosing a point (if there is one) | ||
| 1913 | bool VoxelSystem::getVoxelEnclosingOperation(OctreeElement* element, void* extraData) { | ||
| 1914 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1915 | VoxelAndPoint* args = (VoxelAndPoint*) extraData; | ||
| 1916 | AABox voxelBox = voxel->getAABox(); | ||
| 1917 | if (voxelBox.contains(args->point)) { | ||
| 1918 | if (voxel->isColored() && voxel->isLeaf()) { | ||
| 1919 | // we've reached a solid leaf containing the point, return the node. | ||
| 1920 | args->voxel = voxel; | ||
| 1921 | return false; | ||
| 1922 | } | ||
| 1923 | } else { | ||
| 1924 | // The point is not inside this voxel, so stop recursing. | ||
| 1925 | return false; | ||
| 1926 | } | ||
| 1927 | return true; // keep looking | ||
| 1928 | } | ||
| 1929 | |||
| 1930 | VoxelTreeElement* VoxelSystem::getVoxelEnclosing(const glm::vec3& point) { | ||
| 1931 | VoxelAndPoint voxelAndPoint; | ||
| 1932 | voxelAndPoint.point = point; | ||
| 1933 | voxelAndPoint.voxel = NULL; | ||
| 1934 | _tree->recurseTreeWithOperation(getVoxelEnclosingOperation, (void*) &voxelAndPoint); | ||
| 1935 | return voxelAndPoint.voxel; | ||
| 1936 | } | ||
| 1937 | |||
| 1938 | |||
| 1939 | // helper classes and args for falseColorizeBySource | ||
| 1940 | class groupColor { | ||
| 1941 | public: | ||
| 1942 | unsigned char red, green, blue; | ||
| 1943 | groupColor(unsigned char red, unsigned char green, unsigned char blue) : | ||
| 1944 | red(red), green(green), blue(blue) { } | ||
| 1945 | |||
| 1946 | groupColor() : | ||
| 1947 | red(0), green(0), blue(0) { } | ||
| 1948 | }; | ||
| 1949 | |||
| 1950 | class colorizeBySourceArgs { | ||
| 1951 | public: | ||
| 1952 | std::map<uint16_t, groupColor> colors; | ||
| 1953 | }; | ||
| 1954 | |||
| 1955 | // Will false colorize voxels that are not in view | ||
| 1956 | bool VoxelSystem::falseColorizeBySourceOperation(OctreeElement* element, void* extraData) { | ||
| 1957 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 1958 | colorizeBySourceArgs* args = (colorizeBySourceArgs*)extraData; | ||
| 1959 | _nodeCount++; | ||
| 1960 | if (voxel->isColored()) { | ||
| 1961 | // pick a color based on the source - we want each source to be obviously different | ||
| 1962 | uint16_t nodeIDKey = voxel->getSourceUUIDKey(); | ||
| 1963 | voxel->setFalseColor(args->colors[nodeIDKey].red, args->colors[nodeIDKey].green, args->colors[nodeIDKey].blue); | ||
| 1964 | } | ||
| 1965 | return true; // keep going! | ||
| 1966 | } | ||
| 1967 | |||
| 1968 | void VoxelSystem::falseColorizeBySource() { | ||
| 1969 | _nodeCount = 0; | ||
| 1970 | colorizeBySourceArgs args; | ||
| 1971 | const int NUMBER_OF_COLOR_GROUPS = 6; | ||
| 1972 | const unsigned char MIN_COLOR = 128; | ||
| 1973 | int voxelServerCount = 0; | ||
| 1974 | groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { | ||
| 1975 | groupColor(255, 0, 0), | ||
| 1976 | groupColor( 0, 255, 0), | ||
| 1977 | groupColor( 0, 0, 255), | ||
| 1978 | groupColor(255, 0, 255), | ||
| 1979 | groupColor( 0, 255, 255), | ||
| 1980 | groupColor(255, 255, 255) | ||
| 1981 | }; | ||
| 1982 | |||
| 1983 | // create a bunch of colors we'll use during colorization | ||
| 1984 | |||
| 1985 | foreach (const SharedNodePointer& node, NodeList::getInstance()->getNodeHash()) { | ||
| 1986 | if (node->getType() == NodeType::VoxelServer) { | ||
| 1987 | uint16_t nodeID = VoxelTreeElement::getSourceNodeUUIDKey(node->getUUID()); | ||
| 1988 | int groupColor = voxelServerCount % NUMBER_OF_COLOR_GROUPS; | ||
| 1989 | args.colors[nodeID] = groupColors[groupColor]; | ||
| 1990 | |||
| 1991 | if (groupColors[groupColor].red > 0) { | ||
| 1992 | groupColors[groupColor].red = ((groupColors[groupColor].red - MIN_COLOR)/2) + MIN_COLOR; | ||
| 1993 | } | ||
| 1994 | if (groupColors[groupColor].green > 0) { | ||
| 1995 | groupColors[groupColor].green = ((groupColors[groupColor].green - MIN_COLOR)/2) + MIN_COLOR; | ||
| 1996 | } | ||
| 1997 | if (groupColors[groupColor].blue > 0) { | ||
| 1998 | groupColors[groupColor].blue = ((groupColors[groupColor].blue - MIN_COLOR)/2) + MIN_COLOR; | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | voxelServerCount++; | ||
| 2002 | } | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args); | ||
| 2006 | qDebug("setting false color by source for %d nodes", _nodeCount); | ||
| 2007 | _tree->setDirtyBit(); | ||
| 2008 | setupNewVoxelsForDrawing(); | ||
| 2009 | } | ||
| 2010 | |||
| 2011 | // Will false colorize voxels based on distance from view | ||
| 2012 | bool VoxelSystem::falseColorizeDistanceFromViewOperation(OctreeElement* element, void* extraData) { | ||
| 2013 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2014 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; | ||
| 2015 | if (voxel->isColored()) { | ||
| 2016 | float distance = voxel->distanceToCamera(*viewFrustum); | ||
| 2017 | _nodeCount++; | ||
| 2018 | float distanceRatio = (_minDistance == _maxDistance) ? 1 : (distance - _minDistance) / (_maxDistance - _minDistance); | ||
| 2019 | |||
| 2020 | // We want to colorize this in 16 bug chunks of color | ||
| 2021 | const unsigned char maxColor = 255; | ||
| 2022 | const unsigned char colorBands = 16; | ||
| 2023 | const unsigned char gradientOver = 128; | ||
| 2024 | unsigned char colorBand = (colorBands * distanceRatio); | ||
| 2025 | voxel->setFalseColor((colorBand * (gradientOver / colorBands)) + (maxColor - gradientOver), 0, 0); | ||
| 2026 | } | ||
| 2027 | return true; // keep going! | ||
| 2028 | } | ||
| 2029 | |||
| 2030 | float VoxelSystem::_maxDistance = 0.0; | ||
| 2031 | float VoxelSystem::_minDistance = FLT_MAX; | ||
| 2032 | |||
| 2033 | // Helper function will get the distance from view range, would be nice if you could just keep track | ||
| 2034 | // of this as voxels are created and/or colored... seems like some transform math could do that so | ||
| 2035 | // we wouldn't need to do two passes of the tree | ||
| 2036 | bool VoxelSystem::getDistanceFromViewRangeOperation(OctreeElement* element, void* extraData) { | ||
| 2037 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2038 | ViewFrustum* viewFrustum = (ViewFrustum*) extraData; | ||
| 2039 | // only do this for truly colored voxels... | ||
| 2040 | if (voxel->isColored()) { | ||
| 2041 | float distance = voxel->distanceToCamera(*viewFrustum); | ||
| 2042 | // calculate the range of distances | ||
| 2043 | if (distance > _maxDistance) { | ||
| 2044 | _maxDistance = distance; | ||
| 2045 | } | ||
| 2046 | if (distance < _minDistance) { | ||
| 2047 | _minDistance = distance; | ||
| 2048 | } | ||
| 2049 | _nodeCount++; | ||
| 2050 | } | ||
| 2051 | return true; // keep going! | ||
| 2052 | } | ||
| 2053 | |||
| 2054 | void VoxelSystem::falseColorizeDistanceFromView() { | ||
| 2055 | _nodeCount = 0; | ||
| 2056 | _maxDistance = 0.0; | ||
| 2057 | _minDistance = FLT_MAX; | ||
| 2058 | _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation, (void*) _viewFrustum); | ||
| 2059 | qDebug("determining distance range for %d nodes", _nodeCount); | ||
| 2060 | _nodeCount = 0; | ||
| 2061 | _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation, (void*) _viewFrustum); | ||
| 2062 | qDebug("setting in distance false color for %d nodes", _nodeCount); | ||
| 2063 | _tree->setDirtyBit(); | ||
| 2064 | setupNewVoxelsForDrawing(); | ||
| 2065 | } | ||
| 2066 | |||
| 2067 | // combines the removeOutOfView args into a single class | ||
| 2068 | class removeOutOfViewArgs { | ||
| 2069 | public: | ||
| 2070 | VoxelSystem* thisVoxelSystem; | ||
| 2071 | ViewFrustum thisViewFrustum; | ||
| 2072 | OctreeElementBag dontRecurseBag; | ||
| 2073 | unsigned long nodesScanned; | ||
| 2074 | unsigned long nodesRemoved; | ||
| 2075 | unsigned long nodesInside; | ||
| 2076 | unsigned long nodesIntersect; | ||
| 2077 | unsigned long nodesOutside; | ||
| 2078 | VoxelTreeElement* insideRoot; | ||
| 2079 | VoxelTreeElement* outsideRoot; | ||
| 2080 | |||
| 2081 | removeOutOfViewArgs(VoxelSystem* voxelSystem, bool widenViewFrustum = true) : | ||
| 2082 | thisVoxelSystem(voxelSystem), | ||
| 2083 | thisViewFrustum(*voxelSystem->getViewFrustum()), | ||
| 2084 | dontRecurseBag(), | ||
| 2085 | nodesScanned(0), | ||
| 2086 | nodesRemoved(0), | ||
| 2087 | nodesInside(0), | ||
| 2088 | nodesIntersect(0), | ||
| 2089 | nodesOutside(0), | ||
| 2090 | insideRoot(NULL), | ||
| 2091 | outsideRoot(NULL) | ||
| 2092 | { | ||
| 2093 | // Widen the FOV for trimming | ||
| 2094 | if (widenViewFrustum) { | ||
| 2095 | float originalFOV = thisViewFrustum.getFieldOfView(); | ||
| 2096 | float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; | ||
| 2097 | thisViewFrustum.setFieldOfView(wideFOV); | ||
| 2098 | thisViewFrustum.calculate(); | ||
| 2099 | } | ||
| 2100 | } | ||
| 2101 | }; | ||
| 2102 | |||
| 2103 | void VoxelSystem::cancelImport() { | ||
| 2104 | _tree->cancelImport(); | ||
| 2105 | } | ||
| 2106 | |||
| 2107 | // "Remove" voxels from the tree that are not in view. We don't actually delete them, | ||
| 2108 | // we remove them from the tree and place them into a holding area for later deletion | ||
| 2109 | bool VoxelSystem::removeOutOfViewOperation(OctreeElement* element, void* extraData) { | ||
| 2110 | VoxelTreeElement* voxel = (VoxelTreeElement*) element; | ||
| 2111 | removeOutOfViewArgs* args = (removeOutOfViewArgs*)extraData; | ||
| 2112 | |||
| 2113 | // If our node was previously added to the don't recurse bag, then return false to | ||
| 2114 | // stop the further recursion. This means that the whole node and it's children are | ||
| 2115 | // known to be in view, so don't recurse them | ||
| 2116 | if (args->dontRecurseBag.contains(voxel)) { | ||
| 2117 | args->dontRecurseBag.remove(voxel); | ||
| 2118 | return false; // stop recursion | ||
| 2119 | } | ||
| 2120 | |||
| 2121 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; | ||
| 2122 | args->nodesScanned++; | ||
| 2123 | // Need to operate on our child nodes, so we can remove them | ||
| 2124 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { | ||
| 2125 | VoxelTreeElement* childNode = voxel->getChildAtIndex(i); | ||
| 2126 | if (childNode) { | ||
| 2127 | ViewFrustum::location inFrustum = childNode->inFrustum(args->thisViewFrustum); | ||
| 2128 | switch (inFrustum) { | ||
| 2129 | case ViewFrustum::OUTSIDE: { | ||
| 2130 | args->nodesOutside++; | ||
| 2131 | args->nodesRemoved++; | ||
| 2132 | voxel->removeChildAtIndex(i); | ||
| 2133 | thisVoxelSystem->_removedVoxels.insert(childNode); | ||
| 2134 | // by removing the child, it will not get recursed! | ||
| 2135 | } break; | ||
| 2136 | case ViewFrustum::INSIDE: { | ||
| 2137 | // if the child node is fully INSIDE the view, then there's no need to recurse it | ||
| 2138 | // because we know all it's children will also be in the view, so we want to | ||
| 2139 | // tell the caller to NOT recurse this child | ||
| 2140 | args->nodesInside++; | ||
| 2141 | args->dontRecurseBag.insert(childNode); | ||
| 2142 | } break; | ||
| 2143 | case ViewFrustum::INTERSECT: { | ||
| 2144 | // if the child node INTERSECTs the view, then we don't want to remove it because | ||
| 2145 | // it is at least partially in view. But we DO want to recurse the children because | ||
| 2146 | // some of them may not be in view... nothing specifically to do, just keep iterating | ||
| 2147 | // the children | ||
| 2148 | args->nodesIntersect++; | ||
| 2149 | } break; | ||
| 2150 | } | ||
| 2151 | } | ||
| 2152 | } | ||
| 2153 | return true; // keep going! | ||
| 2154 | } | ||
| 2155 | |||
| 2156 | bool VoxelSystem::isViewChanging() { | 1771 | bool VoxelSystem::isViewChanging() { |
| 2157 | bool result = false; // assume the best | 1772 | bool result = false; // assume the best |
| 2158 | 1773 | ||
| @@ -2180,74 +1795,6 @@ bool VoxelSystem::hasViewChanged() { · 21 unmodified lines | |||
| 2180 | return result; | 1795 | return result; |
| 2181 | } | 1796 | } |
| 2182 | 1797 | ||
| 2183 | void VoxelSystem::removeOutOfView() { | ||
| 2184 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "removeOutOfView()"); | ||
| 2185 | removeOutOfViewArgs args(this); | ||
| 2186 | _tree->recurseTreeWithOperation(removeOutOfViewOperation,(void*)&args); | ||
| 2187 | |||
| 2188 | if (args.nodesRemoved) { | ||
| 2189 | _tree->setDirtyBit(); | ||
| 2190 | } | ||
| 2191 | bool showRemoveDebugDetails = false; | ||
| 2192 | if (showRemoveDebugDetails) { | ||
| 2193 | qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d", | ||
| 2194 | args.nodesScanned, args.nodesRemoved, args.nodesInside, | ||
| 2195 | args.nodesIntersect, args.nodesOutside, _removedVoxels.count() | ||
| 2196 | ); | ||
| 2197 | } | ||
| 2198 | } | ||
| 2199 | |||
| 2200 | // combines the removeOutOfView args into a single class | ||
| 2201 | class showAllLocalVoxelsArgs { | ||
| 2202 | public: | ||
| 2203 | VoxelSystem* thisVoxelSystem; | ||
| 2204 | ViewFrustum thisViewFrustum; | ||
| 2205 | unsigned long nodesScanned; | ||
| 2206 | |||
| 2207 | showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) : | ||
| 2208 | thisVoxelSystem(voxelSystem), | ||
| 2209 | thisViewFrustum(*voxelSystem->getViewFrustum()), | ||
| 2210 | nodesScanned(0) | ||
| 2211 | { | ||
| 2212 | } | ||
| 2213 | }; | ||
| 2214 | |||
| 2215 | void VoxelSystem::showAllLocalVoxels() { | ||
| 2216 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "showAllLocalVoxels()"); | ||
| 2217 | showAllLocalVoxelsArgs args(this); | ||
| 2218 | _tree->recurseTreeWithOperation(showAllLocalVoxelsOperation,(void*)&args); | ||
| 2219 | |||
| 2220 | bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | ||
| 2221 | if (showRemoveDebugDetails) { | ||
| 2222 | qDebug("showAllLocalVoxels() scanned=%ld",args.nodesScanned ); | ||
| 2223 | } | ||
| 2224 | } | ||
| 2225 | |||
| 2226 | bool VoxelSystem::showAllLocalVoxelsOperation(OctreeElement* element, void* extraData) { | ||
| 2227 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2228 | showAllLocalVoxelsArgs* args = (showAllLocalVoxelsArgs*)extraData; | ||
| 2229 | |||
| 2230 | args->nodesScanned++; | ||
| 2231 | |||
| 2232 | float voxelSizeScale = Menu::getInstance()->getVoxelSizeScale();; | ||
| 2233 | int boundaryLevelAdjust = Menu::getInstance()->getBoundaryLevelAdjust(); | ||
| 2234 | bool shouldRender = voxel->calculateShouldRender(&args->thisViewFrustum, voxelSizeScale, boundaryLevelAdjust); | ||
| 2235 | voxel->setShouldRender(shouldRender); | ||
| 2236 | |||
| 2237 | if (shouldRender) { | ||
| 2238 | bool falseColorize = false; | ||
| 2239 | if (falseColorize) { | ||
| 2240 | voxel->setFalseColor(0,0,255); // false colorize | ||
| 2241 | } | ||
| 2242 | // These are both needed to force redraw... | ||
| 2243 | voxel->setDirtyBit(); | ||
| 2244 | voxel->markWithChangedTime(); | ||
| 2245 | } | ||
| 2246 | |||
| 2247 | return true; // keep recursing! | ||
| 2248 | } | ||
| 2249 | |||
| 2250 | |||
| 2251 | // combines the removeOutOfView args into a single class | 1798 | // combines the removeOutOfView args into a single class |
| 2252 | class hideOutOfViewArgs { | 1799 | class hideOutOfViewArgs { |
| 2253 | public: | 1800 | public: |
| @@ -2396,15 +1943,9 @@ bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraDat · 142 unmodified lines | |||
| 2396 | args->nodesOutside++; | 1943 | args->nodesOutside++; |
| 2397 | if (voxel->isKnownBufferIndex()) { | 1944 | if (voxel->isKnownBufferIndex()) { |
| 2398 | args->nodesRemoved++; | 1945 | args->nodesRemoved++; |
| 2399 | bool falseColorize = false; | 1946 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; |
| 2400 | if (falseColorize) { | 1947 | thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(voxel); |
| 2401 | voxel->setFalseColor(255,0,0); // false colorize | 1948 | thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); |
| 2402 | } else { | ||
| 2403 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; | ||
| 2404 | thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->forceRemoveNodeFromArrays(voxel); | ||
| 2405 | thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); | ||
| 2406 | } | ||
| 2407 | |||
| 2408 | } | 1949 | } |
| 2409 | 1950 | ||
| 2410 | return true; | 1951 | return true; |
| @@ -2437,20 +1978,9 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat · 26 unmodified lines | |||
| 2437 | voxel->setShouldRender(shouldRender); | 1978 | voxel->setShouldRender(shouldRender); |
| 2438 | 1979 | ||
| 2439 | if (shouldRender && !voxel->isKnownBufferIndex()) { | 1980 | if (shouldRender && !voxel->isKnownBufferIndex()) { |
| 2440 | bool falseColorize = false; | ||
| 2441 | if (falseColorize) { | ||
| 2442 | voxel->setFalseColor(0,0,255); // false colorize | ||
| 2443 | } | ||
| 2444 | // These are both needed to force redraw... | 1981 | // These are both needed to force redraw... |
| 2445 | voxel->setDirtyBit(); | 1982 | voxel->setDirtyBit(); |
| 2446 | voxel->markWithChangedTime(); | 1983 | voxel->markWithChangedTime(); |
| 2447 | // and this? | ||
| 2448 | // no, not needed, because markWithChangedTime notifies hooks, which calls elementUpdated, which calls updateNodeInArrays | ||
| 2449 | // { | ||
| 2450 | // VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; | ||
| 2451 | // thisVoxelSystem->_voxelsUpdated += thisVoxelSystem->updateNodeInArrays(voxel, true, true); | ||
| 2452 | // thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); | ||
| 2453 | // } | ||
| 2454 | args->nodesShown++; | 1984 | args->nodesShown++; |
| 2455 | } | 1985 | } |
| 2456 | 1986 | ||
| @@ -2552,567 +2082,6 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 95 unmodified lines | |||
| 2552 | } | 2082 | } |
| 2553 | 2083 | ||
| 2554 | 2084 | ||
| 2555 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | ||
| 2556 | VoxelDetail& detail, float& distance, BoxFace& face) { | ||
| 2557 | |||
| 2558 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 2559 | "VoxelSystem::findRayIntersection()"); | ||
| 2560 | bool result = false; // assume no intersection | ||
| 2561 | if (_tree->tryLockForRead()) { | ||
| 2562 | OctreeElement* element; | ||
| 2563 | result = _tree->findRayIntersection(origin, direction, element, distance, face); | ||
| 2564 | if (result) { | ||
| 2565 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2566 | detail.x = voxel->getCorner().x; | ||
| 2567 | detail.y = voxel->getCorner().y; | ||
| 2568 | detail.z = voxel->getCorner().z; | ||
| 2569 | detail.s = voxel->getScale(); | ||
| 2570 | detail.red = voxel->getColor()[0]; | ||
| 2571 | detail.green = voxel->getColor()[1]; | ||
| 2572 | detail.blue = voxel->getColor()[2]; | ||
| 2573 | } | ||
| 2574 | _tree->unlock(); | ||
| 2575 | } | ||
| 2576 | return result; | ||
| 2577 | } | ||
| 2578 | |||
| 2579 | bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { | ||
| 2580 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 2581 | "VoxelSystem::findSpherePenetration()"); | ||
| 2582 | bool result = false; // assume no penetration | ||
| 2583 | if (_tree->tryLockForRead()) { | ||
| 2584 | result = _tree->findSpherePenetration(center, radius, penetration); | ||
| 2585 | _tree->unlock(); | ||
| 2586 | } | ||
| 2587 | return result; | ||
| 2588 | } | ||
| 2589 | |||
| 2590 | bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { | ||
| 2591 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 2592 | "VoxelSystem::findCapsulePenetration()"); | ||
| 2593 | bool result = false; // assume no penetration | ||
| 2594 | if (_tree->tryLockForRead()) { | ||
| 2595 | result = _tree->findCapsulePenetration(start, end, radius, penetration); | ||
| 2596 | _tree->unlock(); | ||
| 2597 | } | ||
| 2598 | return result; | ||
| 2599 | } | ||
| 2600 | |||
| 2601 | class falseColorizeRandomEveryOtherArgs { | ||
| 2602 | public: | ||
| 2603 | falseColorizeRandomEveryOtherArgs() : totalNodes(0), colorableNodes(0), coloredNodes(0), colorThis(true) {}; | ||
| 2604 | unsigned long totalNodes; | ||
| 2605 | unsigned long colorableNodes; | ||
| 2606 | unsigned long coloredNodes; | ||
| 2607 | bool colorThis; | ||
| 2608 | }; | ||
| 2609 | |||
| 2610 | bool VoxelSystem::falseColorizeRandomEveryOtherOperation(OctreeElement* element, void* extraData) { | ||
| 2611 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2612 | falseColorizeRandomEveryOtherArgs* args = (falseColorizeRandomEveryOtherArgs*)extraData; | ||
| 2613 | args->totalNodes++; | ||
| 2614 | if (voxel->isColored()) { | ||
| 2615 | args->colorableNodes++; | ||
| 2616 | if (args->colorThis) { | ||
| 2617 | args->coloredNodes++; | ||
| 2618 | voxel->setFalseColor(255, randomColorValue(150), randomColorValue(150)); | ||
| 2619 | } | ||
| 2620 | args->colorThis = !args->colorThis; | ||
| 2621 | } | ||
| 2622 | return true; // keep going! | ||
| 2623 | } | ||
| 2624 | |||
| 2625 | void VoxelSystem::falseColorizeRandomEveryOther() { | ||
| 2626 | falseColorizeRandomEveryOtherArgs args; | ||
| 2627 | _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args); | ||
| 2628 | qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld", | ||
| 2629 | args.totalNodes, args.colorableNodes, args.coloredNodes); | ||
| 2630 | _tree->setDirtyBit(); | ||
| 2631 | setupNewVoxelsForDrawing(); | ||
| 2632 | } | ||
| 2633 | |||
| 2634 | class collectStatsForTreesAndVBOsArgs { | ||
| 2635 | public: | ||
| 2636 | collectStatsForTreesAndVBOsArgs(int maxVoxels) : | ||
| 2637 | totalNodes(0), | ||
| 2638 | dirtyNodes(0), | ||
| 2639 | shouldRenderNodes(0), | ||
| 2640 | coloredNodes(0), | ||
| 2641 | nodesInVBO(0), | ||
| 2642 | nodesInVBONotShouldRender(0), | ||
| 2643 | nodesInVBOOverExpectedMax(0), | ||
| 2644 | duplicateVBOIndex(0), | ||
| 2645 | leafNodes(0), | ||
| 2646 | culledLeafNodes(0), | ||
| 2647 | nodesInPrimitiveRenderer(0) | ||
| 2648 | { | ||
| 2649 | hasIndexFound = new bool[maxVoxels]; | ||
| 2650 | memset(hasIndexFound, false, maxVoxels * sizeof(bool)); | ||
| 2651 | }; | ||
| 2652 | |||
| 2653 | ~collectStatsForTreesAndVBOsArgs() { | ||
| 2654 | delete[] hasIndexFound; | ||
| 2655 | } | ||
| 2656 | |||
| 2657 | unsigned long totalNodes; | ||
| 2658 | unsigned long dirtyNodes; | ||
| 2659 | unsigned long shouldRenderNodes; | ||
| 2660 | unsigned long coloredNodes; | ||
| 2661 | unsigned long nodesInVBO; | ||
| 2662 | unsigned long nodesInVBONotShouldRender; | ||
| 2663 | unsigned long nodesInVBOOverExpectedMax; | ||
| 2664 | unsigned long duplicateVBOIndex; | ||
| 2665 | unsigned long leafNodes; | ||
| 2666 | unsigned long culledLeafNodes; ///< Number of completely culled nodes because of face sharing | ||
| 2667 | unsigned long nodesInPrimitiveRenderer; | ||
| 2668 | |||
| 2669 | unsigned long expectedMax; | ||
| 2670 | |||
| 2671 | bool* hasIndexFound; | ||
| 2672 | }; | ||
| 2673 | |||
| 2674 | bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, void* extraData) { | ||
| 2675 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2676 | |||
| 2677 | collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData; | ||
| 2678 | args->totalNodes++; | ||
| 2679 | |||
| 2680 | if (voxel->isLeaf()) { | ||
| 2681 | args->leafNodes++; | ||
| 2682 | if (voxel->getInteriorOcclusions() == OctreeElement::HalfSpace::All) { | ||
| 2683 | args->culledLeafNodes++; | ||
| 2684 | } | ||
| 2685 | } | ||
| 2686 | |||
| 2687 | if (voxel->isColored()) { | ||
| 2688 | args->coloredNodes++; | ||
| 2689 | } | ||
| 2690 | |||
| 2691 | if (voxel->getShouldRender()) { | ||
| 2692 | args->shouldRenderNodes++; | ||
| 2693 | } | ||
| 2694 | |||
| 2695 | if (voxel->isDirty()) { | ||
| 2696 | args->dirtyNodes++; | ||
| 2697 | } | ||
| 2698 | |||
| 2699 | unsigned long nodeIndex = 0; | ||
| 2700 | if (voxel->getBufferIndex()) { | ||
| 2701 | args->nodesInPrimitiveRenderer++; | ||
| 2702 | nodeIndex = voxel->getBufferIndex(); | ||
| 2703 | |||
| 2704 | const bool extraDebugging = false; // enable for extra debugging | ||
| 2705 | if (extraDebugging) { | ||
| 2706 | qDebug("node In Renderer... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s, culledFaces=0x%02x \n", | ||
| 2707 | voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), | ||
| 2708 | nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender()), | ||
| 2709 | voxel->getInteriorOcclusions()); | ||
| 2710 | } | ||
| 2711 | } | ||
| 2712 | |||
| 2713 | if (voxel->isKnownBufferIndex()) { | ||
| 2714 | args->nodesInVBO++; | ||
| 2715 | nodeIndex = voxel->getBufferIndex(); | ||
| 2716 | |||
| 2717 | const bool extraDebugging = false; // enable for extra debugging | ||
| 2718 | if (extraDebugging) { | ||
| 2719 | qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n", | ||
| 2720 | voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), | ||
| 2721 | nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); | ||
| 2722 | } | ||
| 2723 | |||
| 2724 | if (args->hasIndexFound[nodeIndex]) { | ||
| 2725 | args->duplicateVBOIndex++; | ||
| 2726 | qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s", nodeIndex, | ||
| 2727 | debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); | ||
| 2728 | } else { | ||
| 2729 | args->hasIndexFound[nodeIndex] = true; | ||
| 2730 | } | ||
| 2731 | if (nodeIndex > args->expectedMax) { | ||
| 2732 | args->nodesInVBOOverExpectedMax++; | ||
| 2733 | } | ||
| 2734 | |||
| 2735 | // if it's in VBO but not-shouldRender, track that also... | ||
| 2736 | if (!voxel->getShouldRender()) { | ||
| 2737 | args->nodesInVBONotShouldRender++; | ||
| 2738 | } | ||
| 2739 | } | ||
| 2740 | |||
| 2741 | return true; // keep going! | ||
| 2742 | } | ||
| 2743 | |||
| 2744 | void VoxelSystem::collectStatsForTreesAndVBOs() { | ||
| 2745 | PerformanceWarning warn(true, "collectStatsForTreesAndVBOs()", true); | ||
| 2746 | |||
| 2747 | glBufferIndex minDirty = GLBUFFER_INDEX_UNKNOWN; | ||
| 2748 | glBufferIndex maxDirty = 0; | ||
| 2749 | |||
| 2750 | if (!_usePrimitiveRenderer) { | ||
| 2751 | for (glBufferIndex i = 0; i < _voxelsInWriteArrays; i++) { | ||
| 2752 | if (_writeVoxelDirtyArray[i]) { | ||
| 2753 | minDirty = std::min(minDirty,i); | ||
| 2754 | maxDirty = std::max(maxDirty,i); | ||
| 2755 | } | ||
| 2756 | } | ||
| 2757 | } | ||
| 2758 | |||
| 2759 | collectStatsForTreesAndVBOsArgs args(_maxVoxels); | ||
| 2760 | args.expectedMax = _voxelsInWriteArrays; | ||
| 2761 | |||
| 2762 | qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>"); | ||
| 2763 | |||
| 2764 | _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); | ||
| 2765 | |||
| 2766 | qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", | ||
| 2767 | args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes); | ||
| 2768 | |||
| 2769 | if (!_usePrimitiveRenderer) { | ||
| 2770 | qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld", debug::valueOf(_voxelsDirty), | ||
| 2771 | _voxelsInWriteArrays, minDirty, maxDirty); | ||
| 2772 | |||
| 2773 | qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld", | ||
| 2774 | args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); | ||
| 2775 | |||
| 2776 | qDebug(" memory usage %ld \n gpu memory usage %ld \n", _memoryUsageRAM, _memoryUsageVBO); | ||
| 2777 | |||
| 2778 | glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; | ||
| 2779 | glBufferIndex maxInVBO = 0; | ||
| 2780 | |||
| 2781 | for (glBufferIndex i = 0; i < _maxVoxels; i++) { | ||
| 2782 | if (args.hasIndexFound[i]) { | ||
| 2783 | minInVBO = std::min(minInVBO,i); | ||
| 2784 | maxInVBO = std::max(maxInVBO,i); | ||
| 2785 | } | ||
| 2786 | } | ||
| 2787 | |||
| 2788 | qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld", | ||
| 2789 | minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); | ||
| 2790 | |||
| 2791 | qDebug(" _freeIndexes.size()=%ld", | ||
| 2792 | _freeIndexes.size()); | ||
| 2793 | } else { | ||
| 2794 | qDebug(" PrimitiveRenderer nodes %ld \n completely culled nodes %ld \n", | ||
| 2795 | args.nodesInPrimitiveRenderer, args.culledLeafNodes); | ||
| 2796 | |||
| 2797 | qDebug(" memory usage %ld \n gpu memory usage %ld \n", | ||
| 2798 | _renderer->getMemoryUsage(), _renderer->getMemoryUsageGPU()); | ||
| 2799 | } | ||
| 2800 | qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>"); | ||
| 2801 | } | ||
| 2802 | |||
| 2803 | |||
| 2804 | void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { | ||
| 2805 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 2806 | "VoxelSystem::deleteVoxelAt()"); | ||
| 2807 | _tree->lockForWrite(); | ||
| 2808 | _tree->deleteVoxelAt(x, y, z, s); | ||
| 2809 | _tree->unlock(); | ||
| 2810 | |||
| 2811 | // redraw! | ||
| 2812 | setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? | ||
| 2813 | }; | ||
| 2814 | |||
| 2815 | VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { | ||
| 2816 | return _tree->getVoxelAt(x, y, z, s); | ||
| 2817 | }; | ||
| 2818 | |||
| 2819 | void VoxelSystem::createVoxel(float x, float y, float z, float s, | ||
| 2820 | unsigned char red, unsigned char green, unsigned char blue, bool destructive) { | ||
| 2821 | |||
| 2822 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | ||
| 2823 | "VoxelSystem::createVoxel()"); | ||
| 2824 | |||
| 2825 | _tree->lockForWrite(); | ||
| 2826 | _tree->createVoxel(x, y, z, s, red, green, blue, destructive); | ||
| 2827 | _tree->unlock(); | ||
| 2828 | |||
| 2829 | setupNewVoxelsForDrawing(); | ||
| 2830 | }; | ||
| 2831 | |||
| 2832 | void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { | ||
| 2833 | _tree->createLine(point1, point2, unitSize, color, destructive); | ||
| 2834 | setupNewVoxelsForDrawing(); | ||
| 2835 | }; | ||
| 2836 | |||
| 2837 | void VoxelSystem::copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelSystem* destination, bool rebaseToRoot) { | ||
| 2838 | _tree->copySubTreeIntoNewTree(startNode, destination->_tree, rebaseToRoot); | ||
| 2839 | destination->setupNewVoxelsForDrawing(); | ||
| 2840 | } | ||
| 2841 | |||
| 2842 | void VoxelSystem::copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelTree* destination, bool rebaseToRoot) { | ||
| 2843 | _tree->copySubTreeIntoNewTree(startNode, destination, rebaseToRoot); | ||
| 2844 | } | ||
| 2845 | |||
| 2846 | void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelTreeElement* destinationNode) { | ||
| 2847 | _tree->copyFromTreeIntoSubTree(sourceTree, destinationNode); | ||
| 2848 | } | ||
| 2849 | |||
| 2850 | void VoxelSystem::recurseTreeWithOperation(RecurseOctreeOperation operation, void* extraData) { | ||
| 2851 | _tree->recurseTreeWithOperation(operation, extraData); | ||
| 2852 | } | ||
| 2853 | |||
| 2854 | struct FalseColorizeOccludedArgs { | ||
| 2855 | ViewFrustum* viewFrustum; | ||
| 2856 | CoverageMap* map; | ||
| 2857 | CoverageMapV2* mapV2; | ||
| 2858 | VoxelTree* tree; | ||
| 2859 | long totalVoxels; | ||
| 2860 | long coloredVoxels; | ||
| 2861 | long occludedVoxels; | ||
| 2862 | long notOccludedVoxels; | ||
| 2863 | long outOfView; | ||
| 2864 | long subtreeVoxelsSkipped; | ||
| 2865 | long nonLeaves; | ||
| 2866 | long nonLeavesOutOfView; | ||
| 2867 | long nonLeavesOccluded; | ||
| 2868 | }; | ||
| 2869 | |||
| 2870 | struct FalseColorizeSubTreeOperationArgs { | ||
| 2871 | unsigned char color[NUMBER_OF_COLORS]; | ||
| 2872 | long voxelsTouched; | ||
| 2873 | }; | ||
| 2874 | |||
| 2875 | bool VoxelSystem::falseColorizeSubTreeOperation(OctreeElement* element, void* extraData) { | ||
| 2876 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2877 | if (voxel->getShouldRender()) { | ||
| 2878 | FalseColorizeSubTreeOperationArgs* args = (FalseColorizeSubTreeOperationArgs*) extraData; | ||
| 2879 | voxel->setFalseColor(args->color[0], args->color[1], args->color[2]); | ||
| 2880 | args->voxelsTouched++; | ||
| 2881 | } | ||
| 2882 | return true; | ||
| 2883 | } | ||
| 2884 | |||
| 2885 | bool VoxelSystem::falseColorizeOccludedOperation(OctreeElement* element, void* extraData) { | ||
| 2886 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 2887 | |||
| 2888 | FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; | ||
| 2889 | args->totalVoxels++; | ||
| 2890 | |||
| 2891 | // If we are a parent, let's see if we're completely occluded. | ||
| 2892 | if (!voxel->isLeaf()) { | ||
| 2893 | args->nonLeaves++; | ||
| 2894 | |||
| 2895 | AABox voxelBox = voxel->getAABox(); | ||
| 2896 | voxelBox.scale(TREE_SCALE); | ||
| 2897 | OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(args->viewFrustum->getProjectedPolygon(voxelBox)); | ||
| 2898 | |||
| 2899 | // If we're not all in view, then ignore it, and just return. But keep searching... | ||
| 2900 | if (!voxelPolygon->getAllInView()) { | ||
| 2901 | args->nonLeavesOutOfView++; | ||
| 2902 | delete voxelPolygon; | ||
| 2903 | return true; | ||
| 2904 | } | ||
| 2905 | |||
| 2906 | CoverageMapStorageResult result = args->map->checkMap(voxelPolygon, false); | ||
| 2907 | if (result == OCCLUDED) { | ||
| 2908 | args->nonLeavesOccluded++; | ||
| 2909 | delete voxelPolygon; | ||
| 2910 | |||
| 2911 | FalseColorizeSubTreeOperationArgs subArgs; | ||
| 2912 | subArgs.color[0] = 0; | ||
| 2913 | subArgs.color[1] = 255; | ||
| 2914 | subArgs.color[2] = 0; | ||
| 2915 | subArgs.voxelsTouched = 0; | ||
| 2916 | |||
| 2917 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); | ||
| 2918 | |||
| 2919 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); | ||
| 2920 | args->totalVoxels += (subArgs.voxelsTouched - 1); | ||
| 2921 | |||
| 2922 | return false; | ||
| 2923 | } | ||
| 2924 | |||
| 2925 | delete voxelPolygon; | ||
| 2926 | return true; // keep looking... | ||
| 2927 | } | ||
| 2928 | |||
| 2929 | if (voxel->isLeaf() && voxel->isColored() && voxel->getShouldRender()) { | ||
| 2930 | args->coloredVoxels++; | ||
| 2931 | |||
| 2932 | AABox voxelBox = voxel->getAABox(); | ||
| 2933 | voxelBox.scale(TREE_SCALE); | ||
| 2934 | OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(args->viewFrustum->getProjectedPolygon(voxelBox)); | ||
| 2935 | |||
| 2936 | // If we're not all in view, then ignore it, and just return. But keep searching... | ||
| 2937 | if (!voxelPolygon->getAllInView()) { | ||
| 2938 | args->outOfView++; | ||
| 2939 | delete voxelPolygon; | ||
| 2940 | return true; | ||
| 2941 | } | ||
| 2942 | |||
| 2943 | CoverageMapStorageResult result = args->map->checkMap(voxelPolygon, true); | ||
| 2944 | if (result == OCCLUDED) { | ||
| 2945 | voxel->setFalseColor(255, 0, 0); | ||
| 2946 | args->occludedVoxels++; | ||
| 2947 | } else if (result == STORED) { | ||
| 2948 | args->notOccludedVoxels++; | ||
| 2949 | //qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); | ||
| 2950 | } else if (result == DOESNT_FIT) { | ||
| 2951 | //qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); | ||
| 2952 | } | ||
| 2953 | } | ||
| 2954 | return true; // keep going! | ||
| 2955 | } | ||
| 2956 | |||
| 2957 | void VoxelSystem::falseColorizeOccluded() { | ||
| 2958 | PerformanceWarning warn(true, "falseColorizeOccluded()",true); | ||
| 2959 | myCoverageMap.erase(); | ||
| 2960 | |||
| 2961 | FalseColorizeOccludedArgs args; | ||
| 2962 | args.viewFrustum = _viewFrustum; | ||
| 2963 | args.map = &myCoverageMap; | ||
| 2964 | args.totalVoxels = 0; | ||
| 2965 | args.coloredVoxels = 0; | ||
| 2966 | args.occludedVoxels = 0; | ||
| 2967 | args.notOccludedVoxels = 0; | ||
| 2968 | args.outOfView = 0; | ||
| 2969 | args.subtreeVoxelsSkipped = 0; | ||
| 2970 | args.nonLeaves = 0; | ||
| 2971 | args.nonLeavesOutOfView = 0; | ||
| 2972 | args.nonLeavesOccluded = 0; | ||
| 2973 | args.tree = _tree; | ||
| 2974 | |||
| 2975 | OctreeProjectedPolygon::pointInside_calls = 0; | ||
| 2976 | OctreeProjectedPolygon::occludes_calls = 0; | ||
| 2977 | OctreeProjectedPolygon::intersects_calls = 0; | ||
| 2978 | |||
| 2979 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); | ||
| 2980 | |||
| 2981 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); | ||
| 2982 | |||
| 2983 | qDebug("falseColorizeOccluded()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld", | ||
| 2984 | position.x, position.y, | ||
| 2985 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, | ||
| 2986 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, | ||
| 2987 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, | ||
| 2988 | OctreeProjectedPolygon::pointInside_calls, | ||
| 2989 | OctreeProjectedPolygon::occludes_calls, | ||
| 2990 | OctreeProjectedPolygon::intersects_calls | ||
| 2991 | ); | ||
| 2992 | |||
| 2993 | |||
| 2994 | //myCoverageMap.erase(); | ||
| 2995 | |||
| 2996 | _tree->setDirtyBit(); | ||
| 2997 | setupNewVoxelsForDrawing(); | ||
| 2998 | } | ||
| 2999 | |||
| 3000 | bool VoxelSystem::falseColorizeOccludedV2Operation(OctreeElement* element, void* extraData) { | ||
| 3001 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | ||
| 3002 | |||
| 3003 | FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; | ||
| 3004 | args->totalVoxels++; | ||
| 3005 | |||
| 3006 | // If we are a parent, let's see if we're completely occluded. | ||
| 3007 | if (!voxel->isLeaf()) { | ||
| 3008 | args->nonLeaves++; | ||
| 3009 | |||
| 3010 | AABox voxelBox = voxel->getAABox(); | ||
| 3011 | voxelBox.scale(TREE_SCALE); | ||
| 3012 | OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(args->viewFrustum->getProjectedPolygon(voxelBox)); | ||
| 3013 | |||
| 3014 | // If we're not all in view, then ignore it, and just return. But keep searching... | ||
| 3015 | if (!voxelPolygon->getAllInView()) { | ||
| 3016 | args->nonLeavesOutOfView++; | ||
| 3017 | delete voxelPolygon; | ||
| 3018 | return true; | ||
| 3019 | } | ||
| 3020 | |||
| 3021 | CoverageMapV2StorageResult result = args->mapV2->checkMap(voxelPolygon, false); | ||
| 3022 | if (result == V2_OCCLUDED) { | ||
| 3023 | args->nonLeavesOccluded++; | ||
| 3024 | delete voxelPolygon; | ||
| 3025 | |||
| 3026 | FalseColorizeSubTreeOperationArgs subArgs; | ||
| 3027 | subArgs.color[0] = 0; | ||
| 3028 | subArgs.color[1] = 255; | ||
| 3029 | subArgs.color[2] = 0; | ||
| 3030 | subArgs.voxelsTouched = 0; | ||
| 3031 | |||
| 3032 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); | ||
| 3033 | |||
| 3034 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); | ||
| 3035 | args->totalVoxels += (subArgs.voxelsTouched - 1); | ||
| 3036 | |||
| 3037 | return false; | ||
| 3038 | } | ||
| 3039 | |||
| 3040 | delete voxelPolygon; | ||
| 3041 | return true; // keep looking... | ||
| 3042 | } | ||
| 3043 | |||
| 3044 | if (voxel->isLeaf() && voxel->isColored() && voxel->getShouldRender()) { | ||
| 3045 | args->coloredVoxels++; | ||
| 3046 | |||
| 3047 | AABox voxelBox = voxel->getAABox(); | ||
| 3048 | voxelBox.scale(TREE_SCALE); | ||
| 3049 | OctreeProjectedPolygon* voxelPolygon = new OctreeProjectedPolygon(args->viewFrustum->getProjectedPolygon(voxelBox)); | ||
| 3050 | |||
| 3051 | // If we're not all in view, then ignore it, and just return. But keep searching... | ||
| 3052 | if (!voxelPolygon->getAllInView()) { | ||
| 3053 | args->outOfView++; | ||
| 3054 | delete voxelPolygon; | ||
| 3055 | return true; | ||
| 3056 | } | ||
| 3057 | |||
| 3058 | CoverageMapV2StorageResult result = args->mapV2->checkMap(voxelPolygon, true); | ||
| 3059 | if (result == V2_OCCLUDED) { | ||
| 3060 | voxel->setFalseColor(255, 0, 0); | ||
| 3061 | args->occludedVoxels++; | ||
| 3062 | } else if (result == V2_STORED) { | ||
| 3063 | args->notOccludedVoxels++; | ||
| 3064 | //qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); | ||
| 3065 | } else if (result == V2_DOESNT_FIT) { | ||
| 3066 | //qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); | ||
| 3067 | } | ||
| 3068 | delete voxelPolygon; // V2 maps don't store polygons, so we're always in charge of freeing | ||
| 3069 | } | ||
| 3070 | return true; // keep going! | ||
| 3071 | } | ||
| 3072 | |||
| 3073 | |||
| 3074 | void VoxelSystem::falseColorizeOccludedV2() { | ||
| 3075 | PerformanceWarning warn(true, "falseColorizeOccludedV2()",true); | ||
| 3076 | myCoverageMapV2.erase(); | ||
| 3077 | |||
| 3078 | CoverageMapV2::wantDebugging = true; | ||
| 3079 | |||
| 3080 | OctreeProjectedPolygon::pointInside_calls = 0; | ||
| 3081 | OctreeProjectedPolygon::occludes_calls = 0; | ||
| 3082 | OctreeProjectedPolygon::intersects_calls = 0; | ||
| 3083 | |||
| 3084 | FalseColorizeOccludedArgs args; | ||
| 3085 | args.viewFrustum = _viewFrustum; | ||
| 3086 | args.mapV2 = &myCoverageMapV2; | ||
| 3087 | args.totalVoxels = 0; | ||
| 3088 | args.coloredVoxels = 0; | ||
| 3089 | args.occludedVoxels = 0; | ||
| 3090 | args.notOccludedVoxels = 0; | ||
| 3091 | args.outOfView = 0; | ||
| 3092 | args.subtreeVoxelsSkipped = 0; | ||
| 3093 | args.nonLeaves = 0; | ||
| 3094 | args.nonLeavesOutOfView = 0; | ||
| 3095 | args.nonLeavesOccluded = 0; | ||
| 3096 | args.tree = _tree; | ||
| 3097 | |||
| 3098 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); | ||
| 3099 | |||
| 3100 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedV2Operation, position, (void*)&args); | ||
| 3101 | |||
| 3102 | qDebug("falseColorizeOccludedV2()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n", | ||
| 3103 | position.x, position.y, | ||
| 3104 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, | ||
| 3105 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, | ||
| 3106 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, | ||
| 3107 | OctreeProjectedPolygon::pointInside_calls, | ||
| 3108 | OctreeProjectedPolygon::occludes_calls, | ||
| 3109 | OctreeProjectedPolygon::intersects_calls | ||
| 3110 | ); | ||
| 3111 | //myCoverageMapV2.erase(); | ||
| 3112 | _tree->setDirtyBit(); | ||
| 3113 | setupNewVoxelsForDrawing(); | ||
| 3114 | } | ||
| 3115 | |||
| 3116 | void VoxelSystem::nodeAdded(SharedNodePointer node) { | 2085 | void VoxelSystem::nodeAdded(SharedNodePointer node) { |
| 3117 | if (node->getType() == NodeType::VoxelServer) { | 2086 | if (node->getType() == NodeType::VoxelServer) { |
| 3118 | qDebug("VoxelSystem... voxel server %s added...", node->getUUID().toString().toLocal8Bit().constData()); | 2087 | qDebug("VoxelSystem... voxel server %s added...", node->getUUID().toString().toLocal8Bit().constData()); |