Showing the changes to interface/src/VoxelSystem.cpp (1 of 8 files). Show all
Unified · Split
| @@ -109,12 +109,15 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) · 108 unmodified lines | |||
| 109 | 109 | ||
| 110 | void VoxelSystem::voxelDeleted(VoxelNode* node) { | 110 | void VoxelSystem::voxelDeleted(VoxelNode* node) { |
| 111 | if (node->isKnownBufferIndex() && (node->getVoxelSystem() == this)) { | 111 | if (node->isKnownBufferIndex() && (node->getVoxelSystem() == this)) { |
| 112 | forceRemoveNodeFromArraysAsPartialVBO(node); | ||
| 113 | |||
| 114 | /*** | ||
| 112 | if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { | 115 | if (!_useFastVoxelPipeline || _inSetupNewVoxelsForDrawing || _writeRenderFullVBO) { |
| 113 | freeBufferIndex(node->getBufferIndex()); | 116 | freeBufferIndex(node->getBufferIndex()); |
| 114 | } else { | 117 | } else { |
| 115 | forceRemoveNodeFromArraysAsPartialVBO(node); | 118 | forceRemoveNodeFromArraysAsPartialVBO(node); |
| 116 | freeBufferIndex(node->getBufferIndex()); | ||
| 117 | } | 119 | } |
| 120 | ***/ | ||
| 118 | } | 121 | } |
| 119 | } | 122 | } |
| 120 | 123 | ||
| @@ -160,7 +163,9 @@ void VoxelSystem::voxelUpdated(VoxelNode* node) { · 39 unmodified lines | |||
| 160 | } | 163 | } |
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | updateNodeInArraysAsPartialVBO(node); | 166 | const bool REUSE_INDEX = true; |
| 167 | const bool DONT_FORCE_REDRAW = false; | ||
| 168 | updateNodeInArrays(node, REUSE_INDEX, DONT_FORCE_REDRAW); | ||
| 164 | _voxelsUpdated++; | 169 | _voxelsUpdated++; |
| 165 | 170 | ||
| 166 | node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. | 171 | node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| @@ -185,26 +190,44 @@ glBufferIndex VoxelSystem::getNextBufferIndex() { · 18 unmodified lines | |||
| 185 | return output; | 190 | return output; |
| 186 | } | 191 | } |
| 187 | 192 | ||
| 188 | // Doesn't actually clean up the VBOs for the index, but does release responsibility of the index from the VoxelNode, | 193 | // Release responsibility of the buffer/vbo index from the VoxelNode, and makes the index available for some other node to use |
| 189 | // and makes the index available for some other node to use | 194 | // will also "clean up" the index data for the buffer/vbo slot, so that if it's in the middle of the draw range, the triangles |
| 195 | // will be "invisible" | ||
| 190 | void VoxelSystem::freeBufferIndex(glBufferIndex index) { | 196 | void VoxelSystem::freeBufferIndex(glBufferIndex index) { |
| 191 | _freeIndexes.push_back(index); | 197 | assert(_voxelsInWriteArrays > 0); |
| 198 | |||
| 199 | // if the "freed" index was our max index, then just drop the _voxelsInWriteArrays down one... | ||
| 200 | if (index == (_voxelsInWriteArrays - 1)) { | ||
| 201 | _voxelsInWriteArrays--; | ||
| 202 | } else { | ||
| 203 | bool inList = false; | ||
| 204 | // make sure the index isn't already in the free list... | ||
| 205 | for (long i = 0; i < _freeIndexes.size(); i++) { | ||
| 206 | if (_freeIndexes[i] == index) { | ||
| 207 | printf("freeBufferIndex(glBufferIndex index)... index=%ld already in free list!\n", index); | ||
| 208 | inList = true; | ||
| 209 | break; | ||
| 210 | } | ||
| 211 | } | ||
| 212 | |||
| 213 | if (!inList) { | ||
| 214 | // make the index available for next node that needs to be drawn | ||
| 215 | _freeIndexes.push_back(index); | ||
| 216 | |||
| 217 | // make the VBO slot "invisible" in case this slot is not used | ||
| 218 | const glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); | ||
| 219 | const float voxelScale = 0; | ||
| 220 | const nodeColor BLACK = {0, 0, 0, 0}; | ||
| 221 | updateArraysDetails(index, startVertex, voxelScale, BLACK); | ||
| 222 | } | ||
| 223 | } | ||
| 192 | } | 224 | } |
| 193 | 225 | ||
| 194 | // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". | 226 | // This will run through the list of _freeIndexes and reset their VBO array values to be "invisible". |
| 195 | void VoxelSystem::clearFreeBufferIndexes() { | 227 | void VoxelSystem::clearFreeBufferIndexes() { |
| 196 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()"); | 228 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "###### clearFreeBufferIndexes()"); |
| 197 | |||
| 198 | for (int i = 0; i < _freeIndexes.size(); i++) { | ||
| 199 | glBufferIndex nodeIndex = _freeIndexes[i]; | ||
| 200 | glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); | ||
| 201 | float voxelScale = 0; | ||
| 202 | _writeVoxelDirtyArray[nodeIndex] = true; | ||
| 203 | nodeColor color = {0, 0, 0, 0}; | ||
| 204 | updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); | ||
| 205 | _abandonedVBOSlots++; | ||
| 206 | } | ||
| 207 | _freeIndexes.clear(); | 229 | _freeIndexes.clear(); |
| 230 | _abandonedVBOSlots = 0; | ||
| 208 | } | 231 | } |
| 209 | 232 | ||
| 210 | VoxelSystem::~VoxelSystem() { | 233 | VoxelSystem::~VoxelSystem() { |
| @@ -589,8 +612,11 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 378 unmodified lines | |||
| 589 | 612 | ||
| 590 | 613 | ||
| 591 | if (!_useFastVoxelPipeline || _writeRenderFullVBO) { | 614 | if (!_useFastVoxelPipeline || _writeRenderFullVBO) { |
| 615 | //printf("parseData about to call setupNewVoxelsForDrawing();\n"); | ||
| 592 | setupNewVoxelsForDrawing(); | 616 | setupNewVoxelsForDrawing(); |
| 593 | } else { | 617 | } else { |
| 618 | printf("parseData about to call checkForCulling() and setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY)\n"); | ||
| 619 | checkForCulling(); | ||
| 594 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); | 620 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); |
| 595 | } | 621 | } |
| 596 | 622 | ||
| @@ -611,7 +637,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 14 unmodified lines | |||
| 611 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; | 637 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; |
| 612 | 638 | ||
| 613 | // clear up the VBOs for any nodes that have been recently deleted. | 639 | // clear up the VBOs for any nodes that have been recently deleted. |
| 614 | clearFreeBufferIndexes(); | 640 | //clearFreeBufferIndexes(); |
| 615 | 641 | ||
| 616 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging | 642 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging |
| 617 | if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { | 643 | if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { |
| @@ -631,6 +657,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 13 unmodified lines | |||
| 631 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); | 657 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); |
| 632 | _callsToTreesToArrays++; | 658 | _callsToTreesToArrays++; |
| 633 | if (_writeRenderFullVBO) { | 659 | if (_writeRenderFullVBO) { |
| 660 | printf("resetting _freeIndexes and _voxelsInWriteArrays\n"); | ||
| 634 | _voxelsInWriteArrays = 0; // reset our VBO | 661 | _voxelsInWriteArrays = 0; // reset our VBO |
| 635 | _freeIndexes.clear(); // reset our free indexes | 662 | _freeIndexes.clear(); // reset our free indexes |
| 636 | } | 663 | } |
| @@ -676,7 +703,7 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 39 unmodified lines | |||
| 676 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; | 703 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; |
| 677 | 704 | ||
| 678 | // clear up the VBOs for any nodes that have been recently deleted. | 705 | // clear up the VBOs for any nodes that have been recently deleted. |
| 679 | clearFreeBufferIndexes(); | 706 | //clearFreeBufferIndexes(); |
| 680 | 707 | ||
| 681 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging | 708 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging |
| 682 | if (allowBailEarly && !iAmDebugging && | 709 | if (allowBailEarly && !iAmDebugging && |
| @@ -684,7 +711,7 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 1 unmodified line | |||
| 684 | return; // bail early, it hasn't been long enough since the last time we ran | 711 | return; // bail early, it hasn't been long enough since the last time we ran |
| 685 | } | 712 | } |
| 686 | 713 | ||
| 687 | checkForCulling(); // check for out of view and deleted voxels... | 714 | //checkForCulling(); // check for out of view and deleted voxels... |
| 688 | 715 | ||
| 689 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it | 716 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 690 | { | 717 | { |
| @@ -723,7 +750,12 @@ void VoxelSystem::checkForCulling() { · 32 unmodified lines | |||
| 723 | // When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove | 750 | // When we call removeOutOfView() voxels, we don't actually remove the voxels from the VBOs, but we do remove |
| 724 | // them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which | 751 | // them from tree, this makes our tree caclulations faster, but doesn't require us to fully rebuild the VBOs (which |
| 725 | // can be expensive). | 752 | // can be expensive). |
| 726 | removeOutOfView(); | 753 | if (Menu::getInstance()->isOptionChecked(MenuOption::HideOutOfView)) { |
| 754 | hideOutOfView(); | ||
| 755 | } | ||
| 756 | if (!Menu::getInstance()->isOptionChecked(MenuOption::DontRemoveOutOfView)) { | ||
| 757 | removeOutOfView(); | ||
| 758 | } | ||
| 727 | 759 | ||
| 728 | // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, | 760 | // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, |
| 729 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on | 761 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on |
| @@ -747,6 +779,7 @@ void VoxelSystem::cleanupRemovedVoxels() { · 17 unmodified lines | |||
| 747 | } | 779 | } |
| 748 | _writeRenderFullVBO = true; // if we remove voxels, we must update our full VBOs | 780 | _writeRenderFullVBO = true; // if we remove voxels, we must update our full VBOs |
| 749 | } | 781 | } |
| 782 | |||
| 750 | // we also might have VBO slots that have been abandoned, if too many of our VBO slots | 783 | // we also might have VBO slots that have been abandoned, if too many of our VBO slots |
| 751 | // are abandonded we want to rerender our full VBOs | 784 | // are abandonded we want to rerender our full VBOs |
| 752 | const float TOO_MANY_ABANDONED_RATIO = 0.5f; | 785 | const float TOO_MANY_ABANDONED_RATIO = 0.5f; |
| @@ -830,6 +863,7 @@ void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, · 77 unmodified lines | |||
| 830 | void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { | 863 | void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { |
| 831 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | 864 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 832 | "copyWrittenDataToReadArrays()"); | 865 | "copyWrittenDataToReadArrays()"); |
| 866 | |||
| 833 | if (_voxelsDirty && _voxelsUpdated) { | 867 | if (_voxelsDirty && _voxelsUpdated) { |
| 834 | if (fullVBOs) { | 868 | if (fullVBOs) { |
| 835 | copyWrittenDataToReadArraysFullVBOs(); | 869 | copyWrittenDataToReadArraysFullVBOs(); |
| @@ -869,39 +903,21 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { · 33 unmodified lines | |||
| 869 | } | 903 | } |
| 870 | } | 904 | } |
| 871 | if (_writeRenderFullVBO) { | 905 | if (_writeRenderFullVBO) { |
| 872 | voxelsUpdated += updateNodeInArraysAsFullVBO(node); | 906 | const bool DONT_REUSE_INDEX = false; |
| 907 | const bool FORCE_REDRAW = true; | ||
| 908 | //printf("newTreeToArrays() about to call updateNodeInArrays(node, DONT_REUSE_INDEX, FORCE_REDRAW);\n"); | ||
| 909 | voxelsUpdated += updateNodeInArrays(node, DONT_REUSE_INDEX, FORCE_REDRAW); | ||
| 873 | } else { | 910 | } else { |
| 874 | voxelsUpdated += updateNodeInArraysAsPartialVBO(node); | 911 | const bool REUSE_INDEX = true; |
| 912 | const bool DONT_FORCE_REDRAW = false; | ||
| 913 | //printf("newTreeToArrays() about to call updateNodeInArrays(node, REUSE_INDEX, DONT_FORCE_REDRAW);\n"); | ||
| 914 | voxelsUpdated += updateNodeInArrays(node, REUSE_INDEX, DONT_FORCE_REDRAW); | ||
| 875 | } | 915 | } |
| 876 | node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. | 916 | node->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| 877 | 917 | ||
| 878 | return voxelsUpdated; | 918 | return voxelsUpdated; |
| 879 | } | 919 | } |
| 880 | 920 | ||
| 881 | int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { | ||
| 882 | // If we've run out of room, then just bail... | ||
| 883 | if (_voxelsInWriteArrays >= _maxVoxels) { | ||
| 884 | return 0; | ||
| 885 | } | ||
| 886 | |||
| 887 | if (node->getShouldRender()) { | ||
| 888 | glm::vec3 startVertex = node->getCorner(); | ||
| 889 | float voxelScale = node->getScale(); | ||
| 890 | glBufferIndex nodeIndex = getNextBufferIndex(); | ||
| 891 | |||
| 892 | // populate the array with points for the 8 vertices | ||
| 893 | // and RGB color for each added vertex | ||
| 894 | updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); | ||
| 895 | node->setBufferIndex(nodeIndex); | ||
| 896 | node->setVoxelSystem(this); | ||
| 897 | return 1; // rendered | ||
| 898 | } else { | ||
| 899 | node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); | ||
| 900 | } | ||
| 901 | |||
| 902 | return 0; // not-rendered | ||
| 903 | } | ||
| 904 | |||
| 905 | // called as response to voxelDeleted() in fast pipeline case. The node | 921 | // called as response to voxelDeleted() in fast pipeline case. The node |
| 906 | // is being deleted, but it's state is such that it thinks it should render | 922 | // is being deleted, but it's state is such that it thinks it should render |
| 907 | // and therefore we can't use the normal render calculations. This method | 923 | // and therefore we can't use the normal render calculations. This method |
| @@ -914,29 +930,22 @@ int VoxelSystem::forceRemoveNodeFromArraysAsPartialVBO(VoxelNode* node) { · 6 unmodified lines | |||
| 914 | 930 | ||
| 915 | // if the node is not in the VBOs then we have nothing to do! | 931 | // if the node is not in the VBOs then we have nothing to do! |
| 916 | if (node->isKnownBufferIndex()) { | 932 | if (node->isKnownBufferIndex()) { |
| 917 | |||
| 918 | // if we shouldn't render then set out location to some infinitely distant location, | ||
| 919 | // and our scale as infinitely small | ||
| 920 | glm::vec3 startVertex(FLT_MAX, FLT_MAX, FLT_MAX); | ||
| 921 | float voxelScale = 0; | ||
| 922 | _abandonedVBOSlots++; | ||
| 923 | |||
| 924 | // If this node has not yet been written to the array, then add it to the end of the array. | 933 | // If this node has not yet been written to the array, then add it to the end of the array. |
| 925 | glBufferIndex nodeIndex = node->getBufferIndex(); | 934 | glBufferIndex nodeIndex = node->getBufferIndex(); |
| 926 | 935 | freeBufferIndex(nodeIndex); // NOTE: This is make the node invisible! | |
| 927 | _writeVoxelDirtyArray[nodeIndex] = true; | 936 | node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); |
| 928 | |||
| 929 | // populate the array with points for the 8 vertices | ||
| 930 | // and RGB color for each added vertex | ||
| 931 | const nodeColor BLACK = { 0,0,0}; | ||
| 932 | updateNodeInArrays(nodeIndex, startVertex, voxelScale, BLACK); | ||
| 933 | |||
| 934 | return 1; // updated! | 937 | return 1; // updated! |
| 935 | } | 938 | } |
| 936 | return 0; // not-updated | 939 | return 0; // not-updated |
| 937 | } | 940 | } |
| 938 | 941 | ||
| 939 | int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { | 942 | int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool forceDraw) { |
| 943 | |||
| 944 | /* | ||
| 945 | printf("updateNodeInArrays(VoxelNode* node=[%f, %f, %f] %f, bool reuseIndex=%s, bool forceDraw=%s)\n", | ||
| 946 | node->getCorner().x,node->getCorner().y,node->getCorner().z, node->getScale(), | ||
| 947 | debug::valueOf(reuseIndex),debug::valueOf(forceDraw)); | ||
| 948 | */ | ||
| 940 | // If we've run out of room, then just bail... | 949 | // If we've run out of room, then just bail... |
| 941 | if (_voxelsInWriteArrays >= _maxVoxels) { | 950 | if (_voxelsInWriteArrays >= _maxVoxels) { |
| 942 | return 0; | 951 | return 0; |
| @@ -946,64 +955,76 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { · 3 unmodified lines | |||
| 946 | return 0; | 955 | return 0; |
| 947 | } | 956 | } |
| 948 | 957 | ||
| 949 | // Now, if we've changed any attributes (our renderness, our color, etc) then update the Arrays... | 958 | // If we've changed any attributes (our renderness, our color, etc), or we've been told to force a redraw |
| 950 | if (node->isDirty()) { | 959 | // then update the Arrays... |
| 951 | glm::vec3 startVertex; | 960 | if (forceDraw || node->isDirty()) { |
| 952 | float voxelScale = 0; | 961 | /* |
| 962 | printf("updateNodeInArrays(VoxelNode* node=[%f, %f, %f] %f, bool reuseIndex=%s, bool forceDraw=%s)\n", | ||
| 963 | node->getCorner().x,node->getCorner().y,node->getCorner().z, node->getScale(), | ||
| 964 | debug::valueOf(reuseIndex),debug::valueOf(forceDraw)); | ||
| 965 | */ | ||
| 966 | //printf("....(isDirty() [isDirty()=%s] or forceRedraw=%s_...\n",debug::valueOf(node->isDirty()),debug::valueOf(forceDraw)); | ||
| 967 | |||
| 953 | // If we're should render, use our legit location and scale, | 968 | // If we're should render, use our legit location and scale, |
| 954 | if (node->getShouldRender()) { | 969 | if (node->getShouldRender()) { |
| 955 | startVertex = node->getCorner(); | 970 | //printf("....shouldRender()...\n"); |
| 956 | voxelScale = node->getScale(); | 971 | glm::vec3 startVertex = node->getCorner(); |
| 957 | } else { | 972 | float voxelScale = node->getScale(); |
| 958 | // if we shouldn't render then set out location to some infinitely distant location, | 973 | |
| 959 | // and our scale as infinitely small | 974 | glBufferIndex nodeIndex = GLBUFFER_INDEX_UNKNOWN; |
| 960 | startVertex[0] = startVertex[1] = startVertex[2] = FLT_MAX; | 975 | if (reuseIndex && node->isKnownBufferIndex()) { |
| 961 | voxelScale = 0; | 976 | //printf("....shouldRender() and reuseIndex && node->isKnownBufferIndex() reusing...\n"); |
| 962 | _abandonedVBOSlots++; | 977 | nodeIndex = node->getBufferIndex(); |
| 963 | } | 978 | } else { |
| 964 | 979 | //printf("....shouldRender() and NOT(reuseIndex && node->isKnownBufferIndex()) getting new index...\n"); | |
| 965 | // If this node has not yet been written to the array, then add it to the end of the array. | 980 | nodeIndex = getNextBufferIndex(); |
| 966 | glBufferIndex nodeIndex; | 981 | node->setBufferIndex(nodeIndex); |
| 967 | if (node->isKnownBufferIndex()) { | 982 | node->setVoxelSystem(this); |
| 968 | nodeIndex = node->getBufferIndex(); | 983 | } |
| 984 | // populate the array with points for the 8 vertices and RGB color for each added vertex | ||
| 985 | updateArraysDetails(nodeIndex, startVertex, voxelScale, node->getColor()); | ||
| 986 | return 1; // updated! | ||
| 969 | } else { | 987 | } else { |
| 970 | nodeIndex = getNextBufferIndex(); | 988 | //printf("....NOT shouldRender()...\n"); |
| 971 | node->setBufferIndex(nodeIndex); | 989 | // If we shouldn't render, but we did have a known index, then we will need to release our index |
| 972 | node->setVoxelSystem(this); | 990 | if (reuseIndex && node->isKnownBufferIndex()) { |
| 991 | //printf("....NOT shouldRender() and reuseIndex && node->isKnownBufferIndex() freeBufferIndex!...\n"); | ||
| 992 | freeBufferIndex(node->getBufferIndex()); // this will make the node invisible | ||
| 993 | return 1; // updated! | ||
| 994 | } | ||
| 973 | } | 995 | } |
| 974 | _writeVoxelDirtyArray[nodeIndex] = true; | 996 | } else { |
| 975 | 997 | //printf("....NOT (dirty [isDirty()=%s] or forceRedraw=%s_...\n",debug::valueOf(node->isDirty()),debug::valueOf(forceDraw)); | |
| 976 | // populate the array with points for the 8 vertices | ||
| 977 | // and RGB color for each added vertex | ||
| 978 | updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); | ||
| 979 | |||
| 980 | return 1; // updated! | ||
| 981 | } | 998 | } |
| 982 | return 0; // not-updated | 999 | return 0; // not-updated |
| 983 | } | 1000 | } |
| 984 | 1001 | ||
| 985 | void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, | 1002 | void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, |
| 986 | float voxelScale, const nodeColor& color) { | 1003 | float voxelScale, const nodeColor& color) { |
| 1004 | |||
| 1005 | if (_initialized) { | ||
| 1006 | _writeVoxelDirtyArray[nodeIndex] = true; | ||
| 987 | 1007 | ||
| 988 | if (_useVoxelShader) { | 1008 | if (_useVoxelShader) { |
| 989 | if (_writeVoxelShaderData) { | 1009 | if (_writeVoxelShaderData) { |
| 990 | VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; | 1010 | VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; |
| 991 | writeVerticesAt->x = startVertex.x * TREE_SCALE; | 1011 | writeVerticesAt->x = startVertex.x * TREE_SCALE; |
| 992 | writeVerticesAt->y = startVertex.y * TREE_SCALE; | 1012 | writeVerticesAt->y = startVertex.y * TREE_SCALE; |
| 993 | writeVerticesAt->z = startVertex.z * TREE_SCALE; | 1013 | writeVerticesAt->z = startVertex.z * TREE_SCALE; |
| 994 | writeVerticesAt->s = voxelScale * TREE_SCALE; | 1014 | writeVerticesAt->s = voxelScale * TREE_SCALE; |
| 995 | writeVerticesAt->r = color[RED_INDEX]; | 1015 | writeVerticesAt->r = color[RED_INDEX]; |
| 996 | writeVerticesAt->g = color[GREEN_INDEX]; | 1016 | writeVerticesAt->g = color[GREEN_INDEX]; |
| 997 | writeVerticesAt->b = color[BLUE_INDEX]; | 1017 | writeVerticesAt->b = color[BLUE_INDEX]; |
| 998 | } | 1018 | } |
| 999 | } else { | 1019 | } else { |
| 1000 | if (_writeVerticesArray && _writeColorsArray) { | 1020 | if (_writeVerticesArray && _writeColorsArray) { |
| 1001 | int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; | 1021 | int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; |
| 1002 | for (int j = 0; j < vertexPointsPerVoxel; j++ ) { | 1022 | for (int j = 0; j < vertexPointsPerVoxel; j++ ) { |
| 1003 | GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); | 1023 | GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * vertexPointsPerVoxel); |
| 1004 | GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); | 1024 | GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * vertexPointsPerVoxel); |
| 1005 | *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); | 1025 | *(writeVerticesAt+j) = startVertex[j % 3] + (identityVerticesGlobalNormals[j] * voxelScale); |
| 1006 | *(writeColorsAt +j) = color[j % 3]; | 1026 | *(writeColorsAt +j) = color[j % 3]; |
| 1027 | } | ||
| 1007 | } | 1028 | } |
| 1008 | } | 1029 | } |
| 1009 | } | 1030 | } |
| @@ -1517,7 +1538,7 @@ public: · 507 unmodified lines | |||
| 1517 | unsigned long nodesIntersect; | 1538 | unsigned long nodesIntersect; |
| 1518 | unsigned long nodesOutside; | 1539 | unsigned long nodesOutside; |
| 1519 | 1540 | ||
| 1520 | removeOutOfViewArgs(VoxelSystem* voxelSystem) : | 1541 | removeOutOfViewArgs(VoxelSystem* voxelSystem, bool widenViewFrustum = true) : |
| 1521 | thisVoxelSystem(voxelSystem), | 1542 | thisVoxelSystem(voxelSystem), |
| 1522 | thisViewFrustum(*voxelSystem->getViewFrustum()), | 1543 | thisViewFrustum(*voxelSystem->getViewFrustum()), |
| 1523 | dontRecurseBag(), | 1544 | dontRecurseBag(), |
| @@ -1528,10 +1549,12 @@ public: · 4 unmodified lines | |||
| 1528 | nodesOutside(0) | 1549 | nodesOutside(0) |
| 1529 | { | 1550 | { |
| 1530 | // Widen the FOV for trimming | 1551 | // Widen the FOV for trimming |
| 1531 | float originalFOV = thisViewFrustum.getFieldOfView(); | 1552 | if (widenViewFrustum) { |
| 1532 | float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; | 1553 | float originalFOV = thisViewFrustum.getFieldOfView(); |
| 1533 | thisViewFrustum.setFieldOfView(wideFOV); | 1554 | float wideFOV = originalFOV + VIEW_FRUSTUM_FOV_OVERSEND; |
| 1534 | thisViewFrustum.calculate(); | 1555 | thisViewFrustum.setFieldOfView(wideFOV); |
| 1556 | thisViewFrustum.calculate(); | ||
| 1557 | } | ||
| 1535 | } | 1558 | } |
| 1536 | }; | 1559 | }; |
| 1537 | 1560 | ||
| @@ -1587,6 +1610,80 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { · 49 unmodified lines | |||
| 1587 | return true; // keep going! | 1610 | return true; // keep going! |
| 1588 | } | 1611 | } |
| 1589 | 1612 | ||
| 1613 | // "hide" voxels in the VBOs that are still in the tree that but not in view. | ||
| 1614 | // We don't remove them from the tree, we don't delete them, we do remove them | ||
| 1615 | // from the VBOs and mark them as such in the tree. | ||
| 1616 | bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) { | ||
| 1617 | removeOutOfViewArgs* args = (removeOutOfViewArgs*)extraData; | ||
| 1618 | |||
| 1619 | // If our node was previously added to the don't recurse bag, then return false to | ||
| 1620 | // stop the further recursion. This means that the whole node and it's children are | ||
| 1621 | // known to be in view, so don't recurse them | ||
| 1622 | if (args->dontRecurseBag.contains(node)) { | ||
| 1623 | args->dontRecurseBag.remove(node); | ||
| 1624 | return false; // stop recursion | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; | ||
| 1628 | args->nodesScanned++; | ||
| 1629 | // Need to operate on our child nodes, so we can remove them | ||
| 1630 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { | ||
| 1631 | VoxelNode* childNode = node->getChildAtIndex(i); | ||
| 1632 | if (childNode) { | ||
| 1633 | ViewFrustum::location inFrustum = childNode->inFrustum(args->thisViewFrustum); | ||
| 1634 | switch (inFrustum) { | ||
| 1635 | case ViewFrustum::OUTSIDE: { | ||
| 1636 | args->nodesOutside++; | ||
| 1637 | if (childNode->isKnownBufferIndex()) { | ||
| 1638 | args->nodesRemoved++; | ||
| 1639 | thisVoxelSystem->forceRemoveNodeFromArraysAsPartialVBO(childNode); | ||
| 1640 | thisVoxelSystem->_voxelsUpdated++; | ||
| 1641 | thisVoxelSystem->setupNewVoxelsForDrawingSingleNode(); | ||
| 1642 | } | ||
| 1643 | // how to handle recursion???? we probably want to continue | ||
| 1644 | } break; | ||
| 1645 | case ViewFrustum::INSIDE: { | ||
| 1646 | |||
| 1647 | // if the child node is fully INSIDE the view, then there's no need to recurse it | ||
| 1648 | // because we know all it's children will also be in the view, so we want to | ||
| 1649 | // tell the caller to NOT recurse this child | ||
| 1650 | args->nodesInside++; | ||
| 1651 | |||
| 1652 | if (childNode->getShouldRender() && !childNode->isKnownBufferIndex()) { | ||
| 1653 | /* | ||
| 1654 | printf("in view, isKnownIndex()=%s isDirty()=%s shouldRender()=%s\n", | ||
| 1655 | debug::valueOf(childNode->isKnownBufferIndex()), | ||
| 1656 | debug::valueOf(childNode->isDirty()), | ||
| 1657 | debug::valueOf(childNode->getShouldRender())); | ||
| 1658 | */ | ||
| 1659 | childNode->setDirtyBit(); // will this make it draw? | ||
| 1660 | } | ||
| 1661 | //args->dontRecurseBag.insert(childNode); | ||
| 1662 | } break; | ||
| 1663 | case ViewFrustum::INTERSECT: { | ||
| 1664 | // if the child node INTERSECTs the view, then we don't want to remove it because | ||
| 1665 | // it is at least partially in view. But we DO want to recurse the children because | ||
| 1666 | // some of them may not be in view... nothing specifically to do, just keep iterating | ||
| 1667 | // the children | ||
| 1668 | args->nodesIntersect++; | ||
| 1669 | |||
| 1670 | if (childNode->getShouldRender() && !childNode->isKnownBufferIndex()) { | ||
| 1671 | /* | ||
| 1672 | printf("intersect view, isKnownIndex()=%s isDirty()=%s shouldRender()=%s\n", | ||
| 1673 | debug::valueOf(childNode->isKnownBufferIndex()), | ||
| 1674 | debug::valueOf(childNode->isDirty()), | ||
| 1675 | debug::valueOf(childNode->getShouldRender())); | ||
| 1676 | */ | ||
| 1677 | childNode->setDirtyBit(); // will this make it draw? | ||
| 1678 | } | ||
| 1679 | |||
| 1680 | } break; | ||
| 1681 | } | ||
| 1682 | } | ||
| 1683 | } | ||
| 1684 | return true; // keep going! | ||
| 1685 | } | ||
| 1686 | |||
| 1590 | 1687 | ||
| 1591 | bool VoxelSystem::isViewChanging() { | 1688 | bool VoxelSystem::isViewChanging() { |
| 1592 | bool result = false; // assume the best | 1689 | bool result = false; // assume the best |
| @@ -1632,6 +1729,29 @@ void VoxelSystem::removeOutOfView() { · 39 unmodified lines | |||
| 1632 | } | 1729 | } |
| 1633 | } | 1730 | } |
| 1634 | 1731 | ||
| 1732 | void VoxelSystem::hideOutOfView() { | ||
| 1733 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "hideOutOfView()",true); | ||
| 1734 | removeOutOfViewArgs args(this, true); // widen to match server! | ||
| 1735 | _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); | ||
| 1736 | |||
| 1737 | if (args.nodesRemoved) { | ||
| 1738 | _tree->setDirtyBit(); | ||
| 1739 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); | ||
| 1740 | } | ||
| 1741 | |||
| 1742 | |||
| 1743 | bool showRemoveDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | ||
| 1744 | if (showRemoveDebugDetails) { | ||
| 1745 | qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n", | ||
| 1746 | args.nodesScanned, args.nodesRemoved, args.nodesInside, | ||
| 1747 | args.nodesIntersect, args.nodesOutside | ||
| 1748 | ); | ||
| 1749 | } | ||
| 1750 | |||
| 1751 | collectStatsForTreesAndVBOs(); | ||
| 1752 | } | ||
| 1753 | |||
| 1754 | |||
| 1635 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 1755 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 1636 | VoxelDetail& detail, float& distance, BoxFace& face) { | 1756 | VoxelDetail& detail, float& distance, BoxFace& face) { |
| 1637 | pthread_mutex_lock(&_treeLock); | 1757 | pthread_mutex_lock(&_treeLock); |
| @@ -1751,6 +1871,14 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* ex · 113 unmodified lines | |||
| 1751 | if (node->isKnownBufferIndex()) { | 1871 | if (node->isKnownBufferIndex()) { |
| 1752 | args->nodesInVBO++; | 1872 | args->nodesInVBO++; |
| 1753 | unsigned long nodeIndex = node->getBufferIndex(); | 1873 | unsigned long nodeIndex = node->getBufferIndex(); |
| 1874 | |||
| 1875 | const bool extraDebugging = false; // enable for extra debugging | ||
| 1876 | if (extraDebugging) { | ||
| 1877 | qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n", | ||
| 1878 | node->getCorner().x, node->getCorner().y, node->getCorner().z, node->getScale(), | ||
| 1879 | nodeIndex, debug::valueOf(node->isDirty()), debug::valueOf(node->getShouldRender())); | ||
| 1880 | } | ||
| 1881 | |||
| 1754 | if (args->hasIndexFound[nodeIndex]) { | 1882 | if (args->hasIndexFound[nodeIndex]) { |
| 1755 | args->duplicateVBOIndex++; | 1883 | args->duplicateVBOIndex++; |
| 1756 | qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, | 1884 | qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, |
| @@ -1786,6 +1914,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 29 unmodified lines | |||
| 1786 | 1914 | ||
| 1787 | collectStatsForTreesAndVBOsArgs args; | 1915 | collectStatsForTreesAndVBOsArgs args; |
| 1788 | args.expectedMax = _voxelsInWriteArrays; | 1916 | args.expectedMax = _voxelsInWriteArrays; |
| 1917 | |||
| 1918 | qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>\n"); | ||
| 1919 | |||
| 1789 | _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); | 1920 | _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); |
| 1790 | 1921 | ||
| 1791 | qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", | 1922 | qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", |
| @@ -1810,6 +1941,10 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 18 unmodified lines | |||
| 1810 | qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", | 1941 | qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", |
| 1811 | minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); | 1942 | minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); |
| 1812 | 1943 | ||
| 1944 | qDebug(" _freeIndexes.size()=%ld \n", | ||
| 1945 | _freeIndexes.size()); | ||
| 1946 | |||
| 1947 | qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>\n"); | ||
| 1813 | } | 1948 | } |
| 1814 | 1949 | ||
| 1815 | 1950 | ||