Showing the changes to interface/src/VoxelSystem.cpp (1 of 9 files). Show all
Unified · Split
| @@ -35,7 +35,6 @@ · 34 unmodified lines | |||
| 35 | 35 | ||
| 36 | const bool VoxelSystem::DONT_BAIL_EARLY = false; | 36 | const bool VoxelSystem::DONT_BAIL_EARLY = false; |
| 37 | 37 | ||
| 38 | |||
| 39 | float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; | 38 | float identityVerticesGlobalNormals[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1 }; |
| 40 | 39 | ||
| 41 | float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7 | 40 | float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, //0-7 |
| @@ -107,16 +106,18 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) · 65 unmodified lines | |||
| 107 | 106 | ||
| 108 | _inSetupNewVoxelsForDrawing = false; | 107 | _inSetupNewVoxelsForDrawing = false; |
| 109 | _useFastVoxelPipeline = false; | 108 | _useFastVoxelPipeline = false; |
| 110 | 109 | ||
| 111 | _culledOnce = false; | 110 | _culledOnce = false; |
| 112 | _inhideOutOfView = false; | 111 | _inhideOutOfView = false; |
| 113 | _treeIsBusy = false; | 112 | _treeIsBusy = false; |
| 113 | |||
| 114 | } | 114 | } |
| 115 | 115 | ||
| 116 | void VoxelSystem::elementDeleted(OctreeElement* element) { | 116 | void VoxelSystem::elementDeleted(OctreeElement* element) { |
| 117 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | 117 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; |
| 118 | if (voxel->getVoxelSystem() == this) { | 118 | if (voxel->getVoxelSystem() == this) { |
| 119 | if (_voxelsInWriteArrays != 0) { | 119 | if (_voxelsInWriteArrays != 0) { |
| 120 | qDebug() << "elementDeleted()... about to call forceRemoveNodeFromArrays()\n"; | ||
| 120 | forceRemoveNodeFromArrays(voxel); | 121 | forceRemoveNodeFromArrays(voxel); |
| 121 | } else { | 122 | } else { |
| 122 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { | 123 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { |
| @@ -148,11 +149,11 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 25 unmodified lines | |||
| 148 | if (voxel->getShouldRender() != shouldRender) { | 149 | if (voxel->getShouldRender() != shouldRender) { |
| 149 | voxel->setShouldRender(shouldRender); | 150 | voxel->setShouldRender(shouldRender); |
| 150 | } | 151 | } |
| 151 | 152 | ||
| 152 | if (!voxel->isLeaf()) { | 153 | if (!voxel->isLeaf()) { |
| 153 | 154 | ||
| 154 | // As we check our children, see if any of them went from shouldRender to NOT shouldRender | 155 | // As we check our children, see if any of them went from shouldRender to NOT shouldRender |
| 155 | // then we probably dropped LOD and if we don't have color, we want to average our children | 156 | // then we probably dropped LOD and if we don't have color, we want to average our children |
| 156 | // for a new color. | 157 | // for a new color. |
| 157 | int childrenGotHiddenCount = 0; | 158 | int childrenGotHiddenCount = 0; |
| 158 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { | 159 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { |
| @@ -176,7 +177,7 @@ void VoxelSystem::elementUpdated(OctreeElement* element) { · 17 unmodified lines | |||
| 176 | _voxelsUpdated++; | 177 | _voxelsUpdated++; |
| 177 | 178 | ||
| 178 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. | 179 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| 179 | 180 | ||
| 180 | setupNewVoxelsForDrawingSingleNode(); | 181 | setupNewVoxelsForDrawingSingleNode(); |
| 181 | } | 182 | } |
| 182 | } | 183 | } |
| @@ -219,7 +220,7 @@ void VoxelSystem::freeBufferIndex(glBufferIndex index) { · 36 unmodified lines | |||
| 219 | break; | 220 | break; |
| 220 | } | 221 | } |
| 221 | } | 222 | } |
| 222 | } | 223 | } |
| 223 | if (!inList) { | 224 | if (!inList) { |
| 224 | // make the index available for next node that needs to be drawn | 225 | // make the index available for next node that needs to be drawn |
| 225 | pthread_mutex_lock(&_freeIndexLock); | 226 | pthread_mutex_lock(&_freeIndexLock); |
| @@ -308,7 +309,7 @@ void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { · 82 unmodified lines | |||
| 308 | } | 309 | } |
| 309 | 310 | ||
| 310 | bool wasInitialized = _initialized; | 311 | bool wasInitialized = _initialized; |
| 311 | 312 | ||
| 312 | // If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode. | 313 | // If we're "turning on" Voxels as points, we need to double check that we're in voxel shader mode. |
| 313 | // Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode, | 314 | // Voxels as points uses the VoxelShader memory model, so if we're not in voxel shader mode, |
| 314 | // then set it to voxel shader mode. | 315 | // then set it to voxel shader mode. |
| @@ -318,7 +319,7 @@ void VoxelSystem::setVoxelsAsPoints(bool voxelsAsPoints) { · 3 unmodified lines | |||
| 318 | // If enabling this... then do it before checking voxel shader status, that way, if voxel | 319 | // If enabling this... then do it before checking voxel shader status, that way, if voxel |
| 319 | // shader is already enabled, we just start drawing as points. | 320 | // shader is already enabled, we just start drawing as points. |
| 320 | _voxelsAsPoints = true; | 321 | _voxelsAsPoints = true; |
| 321 | 322 | ||
| 322 | if (!_useVoxelShader) { | 323 | if (!_useVoxelShader) { |
| 323 | setUseVoxelShader(true); | 324 | setUseVoxelShader(true); |
| 324 | _voxelShaderModeWhenVoxelsAsPointsEnabled = false; | 325 | _voxelShaderModeWhenVoxelsAsPointsEnabled = false; |
| @@ -354,7 +355,7 @@ void VoxelSystem::cleanupVoxelMemory() { · 29 unmodified lines | |||
| 354 | 355 | ||
| 355 | delete[] _writeVoxelShaderData; | 356 | delete[] _writeVoxelShaderData; |
| 356 | delete[] _readVoxelShaderData; | 357 | delete[] _readVoxelShaderData; |
| 357 | 358 | ||
| 358 | _writeVoxelShaderData = _readVoxelShaderData = NULL; | 359 | _writeVoxelShaderData = _readVoxelShaderData = NULL; |
| 359 | 360 | ||
| 360 | } else { | 361 | } else { |
| @@ -368,7 +369,7 @@ void VoxelSystem::cleanupVoxelMemory() { · 7 unmodified lines | |||
| 368 | glDeleteBuffers(1, &_vboIndicesRight); | 369 | glDeleteBuffers(1, &_vboIndicesRight); |
| 369 | glDeleteBuffers(1, &_vboIndicesFront); | 370 | glDeleteBuffers(1, &_vboIndicesFront); |
| 370 | glDeleteBuffers(1, &_vboIndicesBack); | 371 | glDeleteBuffers(1, &_vboIndicesBack); |
| 371 | 372 | ||
| 372 | delete[] _readVerticesArray; | 373 | delete[] _readVerticesArray; |
| 373 | delete[] _writeVerticesArray; | 374 | delete[] _writeVerticesArray; |
| 374 | delete[] _readColorsArray; | 375 | delete[] _readColorsArray; |
| @@ -420,12 +421,12 @@ void VoxelSystem::initVoxelMemory() { · 45 unmodified lines | |||
| 420 | 421 | ||
| 421 | _memoryUsageRAM = 0; | 422 | _memoryUsageRAM = 0; |
| 422 | _memoryUsageVBO = 0; // our VBO allocations as we know them | 423 | _memoryUsageVBO = 0; // our VBO allocations as we know them |
| 423 | 424 | ||
| 424 | // if _voxelsAsPoints then we must have _useVoxelShader | 425 | // if _voxelsAsPoints then we must have _useVoxelShader |
| 425 | if (_voxelsAsPoints && !_useVoxelShader) { | 426 | if (_voxelsAsPoints && !_useVoxelShader) { |
| 426 | _useVoxelShader = true; | 427 | _useVoxelShader = true; |
| 427 | } | 428 | } |
| 428 | 429 | ||
| 429 | if (_useVoxelShader) { | 430 | if (_useVoxelShader) { |
| 430 | GLuint* indicesArray = new GLuint[_maxVoxels]; | 431 | GLuint* indicesArray = new GLuint[_maxVoxels]; |
| 431 | 432 | ||
| @@ -445,7 +446,7 @@ void VoxelSystem::initVoxelMemory() { · 13 unmodified lines | |||
| 445 | glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); | 446 | glBindBuffer(GL_ARRAY_BUFFER, _vboVoxelsID); |
| 446 | glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_DRAW); | 447 | glBufferData(GL_ARRAY_BUFFER, _maxVoxels * sizeof(VoxelShaderVBOData), NULL, GL_DYNAMIC_DRAW); |
| 447 | _memoryUsageVBO += _maxVoxels * sizeof(VoxelShaderVBOData); | 448 | _memoryUsageVBO += _maxVoxels * sizeof(VoxelShaderVBOData); |
| 448 | 449 | ||
| 449 | // delete the indices and normals arrays that are no longer needed | 450 | // delete the indices and normals arrays that are no longer needed |
| 450 | delete[] indicesArray; | 451 | delete[] indicesArray; |
| 451 | 452 | ||
| @@ -474,7 +475,7 @@ void VoxelSystem::initVoxelMemory() { · 22 unmodified lines | |||
| 474 | setupFaceIndices(_vboIndicesRight, identityIndicesRight); | 475 | setupFaceIndices(_vboIndicesRight, identityIndicesRight); |
| 475 | setupFaceIndices(_vboIndicesFront, identityIndicesFront); | 476 | setupFaceIndices(_vboIndicesFront, identityIndicesFront); |
| 476 | setupFaceIndices(_vboIndicesBack, identityIndicesBack); | 477 | setupFaceIndices(_vboIndicesBack, identityIndicesBack); |
| 477 | 478 | ||
| 478 | // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel | 479 | // Depending on if we're using per vertex normals, we will need more or less vertex points per voxel |
| 479 | int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; | 480 | int vertexPointsPerVoxel = GLOBAL_NORMALS_VERTEX_POINTS_PER_VOXEL; |
| 480 | glGenBuffers(1, &_vboVerticesID); | 481 | glGenBuffers(1, &_vboVerticesID); |
| @@ -519,10 +520,10 @@ void VoxelSystem::initVoxelMemory() { · 38 unmodified lines | |||
| 519 | _perlinModulateProgram.bind(); | 520 | _perlinModulateProgram.bind(); |
| 520 | _perlinModulateProgram.setUniformValue("permutationNormalTexture", 0); | 521 | _perlinModulateProgram.setUniformValue("permutationNormalTexture", 0); |
| 521 | _perlinModulateProgram.release(); | 522 | _perlinModulateProgram.release(); |
| 522 | 523 | ||
| 523 | _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/shadow_map.frag"); | 524 | _shadowMapProgram.addShaderFromSourceFile(QGLShader::Fragment, "resources/shaders/shadow_map.frag"); |
| 524 | _shadowMapProgram.link(); | 525 | _shadowMapProgram.link(); |
| 525 | 526 | ||
| 526 | _shadowMapProgram.bind(); | 527 | _shadowMapProgram.bind(); |
| 527 | _shadowMapProgram.setUniformValue("shadowMap", 0); | 528 | _shadowMapProgram.setUniformValue("shadowMap", 0); |
| 528 | _shadowMapProgram.release(); | 529 | _shadowMapProgram.release(); |
| @@ -571,26 +572,26 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 42 unmodified lines | |||
| 571 | switch(command) { | 572 | switch(command) { |
| 572 | case PACKET_TYPE_VOXEL_DATA: { | 573 | case PACKET_TYPE_VOXEL_DATA: { |
| 573 | PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() PACKET_TYPE_VOXEL_DATA part...",showTimingDetails); | 574 | PerformanceWarning warn(showTimingDetails, "VoxelSystem::parseData() PACKET_TYPE_VOXEL_DATA part...",showTimingDetails); |
| 574 | 575 | ||
| 575 | unsigned char* dataAt = sourceBuffer + numBytesPacketHeader; | 576 | unsigned char* dataAt = sourceBuffer + numBytesPacketHeader; |
| 576 | 577 | ||
| 577 | VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); | 578 | VOXEL_PACKET_FLAGS flags = (*(VOXEL_PACKET_FLAGS*)(dataAt)); |
| 578 | dataAt += sizeof(VOXEL_PACKET_FLAGS); | 579 | dataAt += sizeof(VOXEL_PACKET_FLAGS); |
| 579 | VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); | 580 | VOXEL_PACKET_SEQUENCE sequence = (*(VOXEL_PACKET_SEQUENCE*)dataAt); |
| 580 | dataAt += sizeof(VOXEL_PACKET_SEQUENCE); | 581 | dataAt += sizeof(VOXEL_PACKET_SEQUENCE); |
| 581 | 582 | ||
| 582 | VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); | 583 | VOXEL_PACKET_SENT_TIME sentAt = (*(VOXEL_PACKET_SENT_TIME*)dataAt); |
| 583 | dataAt += sizeof(VOXEL_PACKET_SENT_TIME); | 584 | dataAt += sizeof(VOXEL_PACKET_SENT_TIME); |
| 584 | 585 | ||
| 585 | bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); | 586 | bool packetIsColored = oneAtBit(flags, PACKET_IS_COLOR_BIT); |
| 586 | bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); | 587 | bool packetIsCompressed = oneAtBit(flags, PACKET_IS_COMPRESSED_BIT); |
| 587 | 588 | ||
| 588 | VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); | 589 | VOXEL_PACKET_SENT_TIME arrivedAt = usecTimestampNow(); |
| 589 | int flightTime = arrivedAt - sentAt; | 590 | int flightTime = arrivedAt - sentAt; |
| 590 | 591 | ||
| 591 | VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; | 592 | VOXEL_PACKET_INTERNAL_SECTION_SIZE sectionLength = 0; |
| 592 | int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; | 593 | int dataBytes = numBytes - VOXEL_PACKET_HEADER_SIZE; |
| 593 | 594 | ||
| 594 | int subsection = 1; | 595 | int subsection = 1; |
| 595 | while (dataBytes > 0) { | 596 | while (dataBytes > 0) { |
| 596 | if (packetIsCompressed) { | 597 | if (packetIsCompressed) { |
| @@ -605,7 +606,7 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 8 unmodified lines | |||
| 605 | } else { | 606 | } else { |
| 606 | sectionLength = dataBytes; | 607 | sectionLength = dataBytes; |
| 607 | } | 608 | } |
| 608 | 609 | ||
| 609 | if (sectionLength) { | 610 | if (sectionLength) { |
| 610 | // ask the VoxelTree to read the bitstream into the tree | 611 | // ask the VoxelTree to read the bitstream into the tree |
| 611 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); | 612 | ReadBitstreamToTreeParams args(packetIsColored ? WANT_COLOR : NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); |
| @@ -616,12 +617,12 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 4 unmodified lines | |||
| 616 | qDebug("VoxelSystem::parseData() ... Got Packet Section" | 617 | qDebug("VoxelSystem::parseData() ... Got Packet Section" |
| 617 | " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" | 618 | " color:%s compressed:%s sequence: %u flight:%d usec size:%d data:%d" |
| 618 | " subsection:%d sectionLength:%d uncompressed:%d\n", | 619 | " subsection:%d sectionLength:%d uncompressed:%d\n", |
| 619 | debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), | 620 | debug::valueOf(packetIsColored), debug::valueOf(packetIsCompressed), |
| 620 | sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize()); | 621 | sequence, flightTime, numBytes, dataBytes, subsection, sectionLength, packetData.getUncompressedSize()); |
| 621 | } | 622 | } |
| 622 | _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); | 623 | _tree->readBitstreamToTree(packetData.getUncompressedData(), packetData.getUncompressedSize(), args); |
| 623 | unlockTree(); | 624 | unlockTree(); |
| 624 | 625 | ||
| 625 | dataBytes -= sectionLength; | 626 | dataBytes -= sectionLength; |
| 626 | dataAt += sectionLength; | 627 | dataAt += sectionLength; |
| 627 | } | 628 | } |
| @@ -635,15 +636,13 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { · 7 unmodified lines | |||
| 635 | } else { | 636 | } else { |
| 636 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); | 637 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); |
| 637 | } | 638 | } |
| 638 | 639 | ||
| 639 | Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes); | 640 | Application::getInstance()->getBandwidthMeter()->inputStream(BandwidthMeter::VOXELS).updateValue(numBytes); |
| 640 | 641 | ||
| 641 | return numBytes; | 642 | return numBytes; |
| 642 | } | 643 | } |
| 643 | 644 | ||
| 644 | void VoxelSystem::setupNewVoxelsForDrawing() { | 645 | void VoxelSystem::setupNewVoxelsForDrawing() { |
| 645 | |||
| 646 | |||
| 647 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), | 646 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), |
| 648 | "setupNewVoxelsForDrawing()"); | 647 | "setupNewVoxelsForDrawing()"); |
| 649 | 648 | ||
| @@ -653,7 +652,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 3 unmodified lines | |||
| 653 | 652 | ||
| 654 | uint64_t start = usecTimestampNow(); | 653 | uint64_t start = usecTimestampNow(); |
| 655 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; | 654 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; |
| 656 | 655 | ||
| 657 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging | 656 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging |
| 658 | if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { | 657 | if (!iAmDebugging && sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { |
| 659 | return; // bail early, it hasn't been long enough since the last time we ran | 658 | return; // bail early, it hasn't been long enough since the last time we ran |
| @@ -665,7 +664,7 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 5 unmodified lines | |||
| 665 | if (_tree->isDirty()) { | 664 | if (_tree->isDirty()) { |
| 666 | static char buffer[64] = { 0 }; | 665 | static char buffer[64] = { 0 }; |
| 667 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { | 666 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { |
| 668 | sprintf(buffer, "newTreeToArrays() _writeRenderFullVBO=%s", debug::valueOf(_writeRenderFullVBO)); | 667 | sprintf(buffer, "newTreeToArrays() _writeRenderFullVBO=%s", debug::valueOf(_writeRenderFullVBO)); |
| 669 | }; | 668 | }; |
| 670 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); | 669 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), buffer); |
| 671 | _callsToTreesToArrays++; | 670 | _callsToTreesToArrays++; |
| @@ -678,17 +677,17 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 6 unmodified lines | |||
| 678 | if (_writeRenderFullVBO) { | 677 | if (_writeRenderFullVBO) { |
| 679 | _abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier???? | 678 | _abandonedVBOSlots = 0; // reset the count of our abandoned slots, why is this here and not earlier???? |
| 680 | } | 679 | } |
| 681 | 680 | ||
| 682 | // since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are | 681 | // since we called treeToArrays, we can assume that our VBO is in sync, and so partial updates to the VBOs are |
| 683 | // ok again, until/unless we call removeOutOfView() | 682 | // ok again, until/unless we call removeOutOfView() |
| 684 | _writeRenderFullVBO = false; | 683 | _writeRenderFullVBO = false; |
| 685 | } else { | 684 | } else { |
| 686 | _voxelsUpdated = 0; | 685 | _voxelsUpdated = 0; |
| 687 | } | 686 | } |
| 688 | 687 | ||
| 689 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it | 688 | // lock on the buffer write lock so we can't modify the data when the GPU is reading it |
| 690 | pthread_mutex_lock(&_bufferWriteLock); | 689 | pthread_mutex_lock(&_bufferWriteLock); |
| 691 | 690 | ||
| 692 | if (_voxelsUpdated) { | 691 | if (_voxelsUpdated) { |
| 693 | _voxelsDirty=true; | 692 | _voxelsDirty=true; |
| 694 | } | 693 | } |
| @@ -703,6 +702,11 @@ void VoxelSystem::setupNewVoxelsForDrawing() { · 8 unmodified lines | |||
| 703 | _setupNewVoxelsForDrawingLastFinished = end; | 702 | _setupNewVoxelsForDrawingLastFinished = end; |
| 704 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; | 703 | _setupNewVoxelsForDrawingLastElapsed = elapsedmsec; |
| 705 | _inSetupNewVoxelsForDrawing = false; | 704 | _inSetupNewVoxelsForDrawing = false; |
| 705 | |||
| 706 | bool extraDebugging = Application::getInstance()->getLogger()->extraDebugging(); | ||
| 707 | if (extraDebugging) { | ||
| 708 | qDebug("setupNewVoxelsForDrawing()... _voxelsUpdated=%lu...\n",_voxelsUpdated); | ||
| 709 | } | ||
| 706 | } | 710 | } |
| 707 | 711 | ||
| 708 | void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { | 712 | void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { |
| @@ -713,7 +717,7 @@ void VoxelSystem::setupNewVoxelsForDrawingSingleNode(bool allowBailEarly) { · 4 unmodified lines | |||
| 713 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; | 717 | uint64_t sinceLastTime = (start - _setupNewVoxelsForDrawingLastFinished) / 1000; |
| 714 | 718 | ||
| 715 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging | 719 | bool iAmDebugging = false; // if you're debugging set this to true, so you won't get skipped for slow debugging |
| 716 | if (allowBailEarly && !iAmDebugging && | 720 | if (allowBailEarly && !iAmDebugging && |
| 717 | sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { | 721 | sinceLastTime <= std::max((float) _setupNewVoxelsForDrawingLastElapsed, SIXTY_FPS_IN_MILLISECONDS)) { |
| 718 | return; // bail early, it hasn't been long enough since the last time we ran | 722 | return; // bail early, it hasn't been long enough since the last time we ran |
| 719 | } | 723 | } |
| @@ -745,19 +749,17 @@ void VoxelSystem::checkForCulling() { · 25 unmodified lines | |||
| 745 | 749 | ||
| 746 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()"); | 750 | PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "checkForCulling()"); |
| 747 | uint64_t start = usecTimestampNow(); | 751 | uint64_t start = usecTimestampNow(); |
| 748 | 752 | ||
| 749 | |||
| 750 | // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if | 753 | // track how long its been since we were last moving. If we have recently moved then only use delta frustums, if |
| 751 | // it's been a long time since we last moved, then go ahead and do a full frustum cull. | 754 | // it's been a long time since we last moved, then go ahead and do a full frustum cull. |
| 752 | if (isViewChanging()) { | 755 | if (isViewChanging()) { |
| 753 | _lastViewIsChanging = start; | 756 | _lastViewIsChanging = start; |
| 754 | } | 757 | } |
| 755 | uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000; | 758 | uint64_t sinceLastMoving = (start - _lastViewIsChanging) / 1000; |
| 756 | |||
| 757 | bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)); | 759 | bool enoughTime = (sinceLastMoving >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)); |
| 758 | 760 | ||
| 759 | // These has changed events will occur before we stop. So we need to remember this for when we finally have stopped | 761 | // These has changed events will occur before we stop. So we need to remember this for when we finally have stopped |
| 760 | // moving long enough to be enoughTime | 762 | // moving long enough to be enoughTime |
| 761 | if (hasViewChanged()) { | 763 | if (hasViewChanged()) { |
| 762 | _hasRecentlyChanged = true; | 764 | _hasRecentlyChanged = true; |
| 763 | } | 765 | } |
| @@ -767,25 +769,25 @@ void VoxelSystem::checkForCulling() { · 3 unmodified lines | |||
| 767 | bool forceFullFrustum = enoughTime && _hasRecentlyChanged; | 769 | bool forceFullFrustum = enoughTime && _hasRecentlyChanged; |
| 768 | 770 | ||
| 769 | // in hide mode, we only track the full frustum culls, because we don't care about the partials. | 771 | // in hide mode, we only track the full frustum culls, because we don't care about the partials. |
| 770 | if (forceFullFrustum) { | 772 | if (forceFullFrustum) { |
| 771 | _lastViewCulling = start; | 773 | _lastViewCulling = start; |
| 772 | _hasRecentlyChanged = false; | 774 | _hasRecentlyChanged = false; |
| 773 | } | 775 | } |
| 774 | 776 | ||
| 775 | hideOutOfView(forceFullFrustum); | 777 | hideOutOfView(forceFullFrustum); |
| 776 | 778 | ||
| 777 | if (forceFullFrustum) { | 779 | if (forceFullFrustum) { |
| 778 | uint64_t endViewCulling = usecTimestampNow(); | 780 | uint64_t endViewCulling = usecTimestampNow(); |
| 779 | _lastViewCullingElapsed = (endViewCulling - start) / 1000; | 781 | _lastViewCullingElapsed = (endViewCulling - start) / 1000; |
| 780 | } | 782 | } |
| 781 | 783 | ||
| 782 | // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, | 784 | // Once we call cleanupRemovedVoxels() we do need to rebuild our VBOs (if anything was actually removed). So, |
| 783 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on | 785 | // we should consider putting this someplace else... as this might be able to occur less frequently, and save us on |
| 784 | // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. | 786 | // VBO reubuilding. Possibly we should do this only if our actual VBO usage crosses some lower boundary. |
| 785 | cleanupRemovedVoxels(); | 787 | cleanupRemovedVoxels(); |
| 786 | 788 | ||
| 787 | uint64_t sinceLastAudit = (start - _lastAudit) / 1000; | 789 | uint64_t sinceLastAudit = (start - _lastAudit) / 1000; |
| 788 | 790 | ||
| 789 | if (Menu::getInstance()->isOptionChecked(MenuOption::AutomaticallyAuditTree)) { | 791 | if (Menu::getInstance()->isOptionChecked(MenuOption::AutomaticallyAuditTree)) { |
| 790 | if (sinceLastAudit >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) { | 792 | if (sinceLastAudit >= std::max((float) _lastViewCullingElapsed, VIEW_CULLING_RATE_IN_MILLISECONDS)) { |
| 791 | _lastAudit = start; | 793 | _lastAudit = start; |
| @@ -812,7 +814,7 @@ void VoxelSystem::cleanupRemovedVoxels() { · 20 unmodified lines | |||
| 812 | const float TOO_MANY_ABANDONED_RATIO = 0.5f; | 814 | const float TOO_MANY_ABANDONED_RATIO = 0.5f; |
| 813 | if (!_writeRenderFullVBO && (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) { | 815 | if (!_writeRenderFullVBO && (_abandonedVBOSlots > (_voxelsInWriteArrays * TOO_MANY_ABANDONED_RATIO))) { |
| 814 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { | 816 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { |
| 815 | qDebug() << "cleanupRemovedVoxels().. _abandonedVBOSlots [" | 817 | qDebug() << "cleanupRemovedVoxels().. _abandonedVBOSlots [" |
| 816 | << _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO \n"; | 818 | << _abandonedVBOSlots << "] > TOO_MANY_ABANDONED_RATIO \n"; |
| 817 | } | 819 | } |
| 818 | _writeRenderFullVBO = true; | 820 | _writeRenderFullVBO = true; |
| @@ -822,10 +824,10 @@ void VoxelSystem::cleanupRemovedVoxels() { · 3 unmodified lines | |||
| 822 | void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { | 824 | void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { |
| 823 | copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); | 825 | copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); |
| 824 | _voxelsInReadArrays = _voxelsInWriteArrays; | 826 | _voxelsInReadArrays = _voxelsInWriteArrays; |
| 825 | 827 | ||
| 826 | // clear our dirty flags | 828 | // clear our dirty flags |
| 827 | memset(_writeVoxelDirtyArray, false, _voxelsInWriteArrays * sizeof(bool)); | 829 | memset(_writeVoxelDirtyArray, false, _voxelsInWriteArrays * sizeof(bool)); |
| 828 | 830 | ||
| 829 | // let the reader know to get the full array | 831 | // let the reader know to get the full array |
| 830 | _readRenderFullVBO = true; | 832 | _readRenderFullVBO = true; |
| 831 | } | 833 | } |
| @@ -851,7 +853,7 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { · 19 unmodified lines | |||
| 851 | } | 853 | } |
| 852 | } | 854 | } |
| 853 | } | 855 | } |
| 854 | 856 | ||
| 855 | // if we got to the end of the array, and we're in an active dirty segment... | 857 | // if we got to the end of the array, and we're in an active dirty segment... |
| 856 | if (inSegment) { | 858 | if (inSegment) { |
| 857 | copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); | 859 | copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); |
| @@ -910,9 +912,9 @@ int VoxelSystem::newTreeToArrays(VoxelTreeElement* voxel) { · 52 unmodified lines | |||
| 910 | voxel->setShouldRender(shouldRender); | 912 | voxel->setShouldRender(shouldRender); |
| 911 | // let children figure out their renderness | 913 | // let children figure out their renderness |
| 912 | if (!voxel->isLeaf()) { | 914 | if (!voxel->isLeaf()) { |
| 913 | 915 | ||
| 914 | // As we check our children, see if any of them went from shouldRender to NOT shouldRender | 916 | // As we check our children, see if any of them went from shouldRender to NOT shouldRender |
| 915 | // then we probably dropped LOD and if we don't have color, we want to average our children | 917 | // then we probably dropped LOD and if we don't have color, we want to average our children |
| 916 | // for a new color. | 918 | // for a new color. |
| 917 | int childrenGotHiddenCount = 0; | 919 | int childrenGotHiddenCount = 0; |
| 918 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { | 920 | for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { |
| @@ -930,17 +932,23 @@ int VoxelSystem::newTreeToArrays(VoxelTreeElement* voxel) { · 11 unmodified lines | |||
| 930 | voxel->calculateAverageFromChildren(); | 932 | voxel->calculateAverageFromChildren(); |
| 931 | } | 933 | } |
| 932 | } | 934 | } |
| 933 | if (_writeRenderFullVBO) { | 935 | |
| 934 | const bool DONT_REUSE_INDEX = false; | 936 | // for either voxels that should not render, or those that should render and are in view |
| 935 | const bool FORCE_REDRAW = true; | 937 | // update their geometry in the array.if the voxel "should render" but is not in view, then |
| 936 | voxelsUpdated += updateNodeInArrays(voxel, DONT_REUSE_INDEX, FORCE_REDRAW); | 938 | // it actually doesn't need to be rendered |
| 937 | } else { | 939 | if (!shouldRender || voxel->isInView(*_viewFrustum)) { |
| 938 | const bool REUSE_INDEX = true; | 940 | if (_writeRenderFullVBO) { |
| 939 | const bool DONT_FORCE_REDRAW = false; | 941 | const bool DONT_REUSE_INDEX = false; |
| 940 | voxelsUpdated += updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); | 942 | const bool FORCE_REDRAW = true; |
| 943 | voxelsUpdated += updateNodeInArrays(voxel, DONT_REUSE_INDEX, FORCE_REDRAW); | ||
| 944 | } else { | ||
| 945 | const bool REUSE_INDEX = true; | ||
| 946 | const bool DONT_FORCE_REDRAW = false; | ||
| 947 | voxelsUpdated += updateNodeInArrays(voxel, REUSE_INDEX, DONT_FORCE_REDRAW); | ||
| 948 | } | ||
| 941 | } | 949 | } |
| 942 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. | 950 | voxel->clearDirtyBit(); // clear the dirty bit, do this before we potentially delete things. |
| 943 | 951 | ||
| 944 | return voxelsUpdated; | 952 | return voxelsUpdated; |
| 945 | } | 953 | } |
| 946 | 954 | ||
| @@ -959,7 +967,7 @@ int VoxelSystem::forceRemoveNodeFromArrays(VoxelTreeElement* node) { · 12 unmodified lines | |||
| 959 | // If this node has not yet been written to the array, then add it to the end of the array. | 967 | // If this node has not yet been written to the array, then add it to the end of the array. |
| 960 | glBufferIndex nodeIndex = node->getBufferIndex(); | 968 | glBufferIndex nodeIndex = node->getBufferIndex(); |
| 961 | node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); | 969 | node->setBufferIndex(GLBUFFER_INDEX_UNKNOWN); |
| 962 | freeBufferIndex(nodeIndex); // NOTE: This is make the node invisible! | 970 | freeBufferIndex(nodeIndex); // NOTE: This will make the node invisible! |
| 963 | return 1; // updated! | 971 | return 1; // updated! |
| 964 | } | 972 | } |
| 965 | return 0; // not-updated | 973 | return 0; // not-updated |
| @@ -982,11 +990,11 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo · 16 unmodified lines | |||
| 982 | if (!_initialized) { | 990 | if (!_initialized) { |
| 983 | return 0; | 991 | return 0; |
| 984 | } | 992 | } |
| 985 | 993 | ||
| 986 | // If we've changed any attributes (our renderness, our color, etc), or we've been told to force a redraw | 994 | // If we've changed any attributes (our renderness, our color, etc), or we've been told to force a redraw |
| 987 | // then update the Arrays... | 995 | // then update the Arrays... |
| 988 | if (forceDraw || node->isDirty()) { | 996 | if (forceDraw || node->isDirty()) { |
| 989 | // If we're should render, use our legit location and scale, | 997 | // If we're should render, use our legit location and scale, |
| 990 | if (node->getShouldRender()) { | 998 | if (node->getShouldRender()) { |
| 991 | glm::vec3 startVertex = node->getCorner(); | 999 | glm::vec3 startVertex = node->getCorner(); |
| 992 | float voxelScale = node->getScale(); | 1000 | float voxelScale = node->getScale(); |
| @@ -1016,9 +1024,9 @@ int VoxelSystem::updateNodeInArrays(VoxelTreeElement* node, bool reuseIndex, boo · 23 unmodified lines | |||
| 1016 | void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, | 1024 | void VoxelSystem::updateArraysDetails(glBufferIndex nodeIndex, const glm::vec3& startVertex, |
| 1017 | float voxelScale, const nodeColor& color) { | 1025 | float voxelScale, const nodeColor& color) { |
| 1018 | 1026 | ||
| 1019 | if (_initialized) { | 1027 | if (_initialized && nodeIndex <= _maxVoxels) { |
| 1020 | _writeVoxelDirtyArray[nodeIndex] = true; | 1028 | _writeVoxelDirtyArray[nodeIndex] = true; |
| 1021 | 1029 | ||
| 1022 | if (_useVoxelShader) { | 1030 | if (_useVoxelShader) { |
| 1023 | if (_writeVoxelShaderData) { | 1031 | if (_writeVoxelShaderData) { |
| 1024 | VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; | 1032 | VoxelShaderVBOData* writeVerticesAt = &_writeVoxelShaderData[nodeIndex]; |
| @@ -1071,15 +1079,17 @@ void VoxelSystem::init() { · 46 unmodified lines | |||
| 1071 | // VBO for the verticesArray | 1079 | // VBO for the verticesArray |
| 1072 | _initialMemoryUsageGPU = getFreeMemoryGPU(); | 1080 | _initialMemoryUsageGPU = getFreeMemoryGPU(); |
| 1073 | initVoxelMemory(); | 1081 | initVoxelMemory(); |
| 1074 | 1082 | ||
| 1075 | // our own _removedVoxels doesn't need to be notified of voxel deletes | 1083 | // our own _removedVoxels doesn't need to be notified of voxel deletes |
| 1076 | VoxelTreeElement::removeDeleteHook(&_removedVoxels); | 1084 | VoxelTreeElement::removeDeleteHook(&_removedVoxels); |
| 1085 | |||
| 1077 | } | 1086 | } |
| 1078 | 1087 | ||
| 1079 | void VoxelSystem::changeTree(VoxelTree* newTree) { | 1088 | void VoxelSystem::changeTree(VoxelTree* newTree) { |
| 1080 | disconnect(_tree, 0, this, 0); | 1089 | disconnect(_tree, 0, this, 0); |
| 1081 | 1090 | ||
| 1082 | _tree = newTree; | 1091 | _tree = newTree; |
| 1092 | |||
| 1083 | _tree->setDirtyBit(); | 1093 | _tree->setDirtyBit(); |
| 1084 | _tree->getRoot()->setVoxelSystem(this); | 1094 | _tree->getRoot()->setVoxelSystem(this); |
| 1085 | 1095 | ||
| @@ -1102,7 +1112,7 @@ void VoxelSystem::updateFullVBOs() { · 16 unmodified lines | |||
| 1102 | PerformanceWarning warn(outputWarning,buffer); | 1112 | PerformanceWarning warn(outputWarning,buffer); |
| 1103 | updateVBOSegment(0, _voxelsInReadArrays); | 1113 | updateVBOSegment(0, _voxelsInReadArrays); |
| 1104 | } | 1114 | } |
| 1105 | 1115 | ||
| 1106 | { | 1116 | { |
| 1107 | PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)"); | 1117 | PerformanceWarning warn(outputWarning,"updateFullVBOs() : memset(_readVoxelDirtyArray...)"); |
| 1108 | // consider the _readVoxelDirtyArray[] clean! | 1118 | // consider the _readVoxelDirtyArray[] clean! |
| @@ -1131,7 +1141,7 @@ void VoxelSystem::updatePartialVBOs() { · 22 unmodified lines | |||
| 1131 | _readVoxelDirtyArray[i] = false; // consider us clean! | 1141 | _readVoxelDirtyArray[i] = false; // consider us clean! |
| 1132 | } | 1142 | } |
| 1133 | } | 1143 | } |
| 1134 | 1144 | ||
| 1135 | // if we got to the end of the array, and we're in an active dirty segment... | 1145 | // if we got to the end of the array, and we're in an active dirty segment... |
| 1136 | if (inSegment) { | 1146 | if (inSegment) { |
| 1137 | updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); | 1147 | updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); |
| @@ -1195,7 +1205,7 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg · 57 unmodified lines | |||
| 1195 | PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);"); | 1205 | PerformanceWarning warn(showWarning, "updateVBOSegment() : glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID);"); |
| 1196 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); | 1206 | glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); |
| 1197 | } | 1207 | } |
| 1198 | 1208 | ||
| 1199 | { | 1209 | { |
| 1200 | PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);"); | 1210 | PerformanceWarning warn(showWarning, "updateVBOSegment() : glBufferSubData() _vboColorsID);"); |
| 1201 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); | 1211 | glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); |
| @@ -1206,14 +1216,14 @@ void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex seg · 4 unmodified lines | |||
| 1206 | void VoxelSystem::render(bool texture) { | 1216 | void VoxelSystem::render(bool texture) { |
| 1207 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 1217 | bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1208 | PerformanceWarning warn(showWarnings, "render()"); | 1218 | PerformanceWarning warn(showWarnings, "render()"); |
| 1209 | 1219 | ||
| 1210 | // If we got here and we're not initialized then bail! | 1220 | // If we got here and we're not initialized then bail! |
| 1211 | if (!_initialized) { | 1221 | if (!_initialized) { |
| 1212 | return; | 1222 | return; |
| 1213 | } | 1223 | } |
| 1214 | 1224 | ||
| 1215 | updateVBOs(); | 1225 | updateVBOs(); |
| 1216 | 1226 | ||
| 1217 | bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels); | 1227 | bool dontCallOpenGLDraw = Menu::getInstance()->isOptionChecked(MenuOption::DontCallOpenGLForVoxels); |
| 1218 | // if not don't... then do... | 1228 | // if not don't... then do... |
| 1219 | if (_useVoxelShader) { | 1229 | if (_useVoxelShader) { |
| @@ -1253,8 +1263,8 @@ void VoxelSystem::render(bool texture) { · 33 unmodified lines | |||
| 1253 | glEnableVertexAttribArray(attributeLocation); | 1263 | glEnableVertexAttribArray(attributeLocation); |
| 1254 | glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); | 1264 | glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); |
| 1255 | } | 1265 | } |
| 1256 | 1266 | ||
| 1257 | 1267 | ||
| 1258 | glEnableClientState(GL_COLOR_ARRAY); | 1268 | glEnableClientState(GL_COLOR_ARRAY); |
| 1259 | glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors | 1269 | glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(4*sizeof(float)));//The starting point of colors |
| 1260 | 1270 | ||
| @@ -1285,7 +1295,7 @@ void VoxelSystem::render(bool texture) { · 24 unmodified lines | |||
| 1285 | 1295 | ||
| 1286 | { | 1296 | { |
| 1287 | PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()..."); | 1297 | PerformanceWarning warn(showWarnings,"render().. setup before glDrawRangeElementsEXT()..."); |
| 1288 | 1298 | ||
| 1289 | // tell OpenGL where to find vertex and color information | 1299 | // tell OpenGL where to find vertex and color information |
| 1290 | glEnableClientState(GL_VERTEX_ARRAY); | 1300 | glEnableClientState(GL_VERTEX_ARRAY); |
| 1291 | glEnableClientState(GL_COLOR_ARRAY); | 1301 | glEnableClientState(GL_COLOR_ARRAY); |
| @@ -1306,7 +1316,7 @@ void VoxelSystem::render(bool texture) { · 14 unmodified lines | |||
| 1306 | 1316 | ||
| 1307 | if (!dontCallOpenGLDraw) { | 1317 | if (!dontCallOpenGLDraw) { |
| 1308 | PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()..."); | 1318 | PerformanceWarning warn(showWarnings, "render().. glDrawRangeElementsEXT()..."); |
| 1309 | 1319 | ||
| 1310 | glNormal3f(0,1.0f,0); | 1320 | glNormal3f(0,1.0f,0); |
| 1311 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); | 1321 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesTop); |
| 1312 | glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, | 1322 | glDrawRangeElementsEXT(GL_TRIANGLES, 0, GLOBAL_NORMALS_VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, |
| @@ -1340,7 +1350,7 @@ void VoxelSystem::render(bool texture) { · 27 unmodified lines | |||
| 1340 | 1350 | ||
| 1341 | { | 1351 | { |
| 1342 | PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()..."); | 1352 | PerformanceWarning warn(showWarnings, "render().. cleanup after glDrawRangeElementsEXT()..."); |
| 1343 | 1353 | ||
| 1344 | glDisable(GL_CULL_FACE); | 1354 | glDisable(GL_CULL_FACE); |
| 1345 | 1355 | ||
| 1346 | removeScaleAndReleaseProgram(texture); | 1356 | removeScaleAndReleaseProgram(texture); |
| @@ -1365,16 +1375,16 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { · 18 unmodified lines | |||
| 1365 | glEnable(GL_TEXTURE_GEN_T); | 1375 | glEnable(GL_TEXTURE_GEN_T); |
| 1366 | glEnable(GL_TEXTURE_GEN_R); | 1376 | glEnable(GL_TEXTURE_GEN_R); |
| 1367 | glEnable(GL_TEXTURE_2D); | 1377 | glEnable(GL_TEXTURE_2D); |
| 1368 | 1378 | ||
| 1369 | glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); | 1379 | glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[0]); |
| 1370 | glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); | 1380 | glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[1]); |
| 1371 | glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); | 1381 | glTexGenfv(GL_R, GL_EYE_PLANE, (const GLfloat*)&Application::getInstance()->getShadowMatrix()[2]); |
| 1372 | 1382 | ||
| 1373 | } else if (texture) { | 1383 | } else if (texture) { |
| 1374 | _perlinModulateProgram.bind(); | 1384 | _perlinModulateProgram.bind(); |
| 1375 | glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); | 1385 | glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getPermutationNormalTextureID()); |
| 1376 | } | 1386 | } |
| 1377 | 1387 | ||
| 1378 | glPushMatrix(); | 1388 | glPushMatrix(); |
| 1379 | glScalef(_treeScale, _treeScale, _treeScale); | 1389 | glScalef(_treeScale, _treeScale, _treeScale); |
| 1380 | } | 1390 | } |
| @@ -1382,7 +1392,7 @@ void VoxelSystem::applyScaleAndBindProgram(bool texture) { · 1 unmodified line | |||
| 1382 | void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { | 1392 | void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { |
| 1383 | // scale back down to 1 so heads aren't massive | 1393 | // scale back down to 1 so heads aren't massive |
| 1384 | glPopMatrix(); | 1394 | glPopMatrix(); |
| 1385 | 1395 | ||
| 1386 | if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { | 1396 | if (Menu::getInstance()->isOptionChecked(MenuOption::Shadows)) { |
| 1387 | _shadowMapProgram.release(); | 1397 | _shadowMapProgram.release(); |
| 1388 | glBindTexture(GL_TEXTURE_2D, 0); | 1398 | glBindTexture(GL_TEXTURE_2D, 0); |
| @@ -1390,7 +1400,7 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { · 1 unmodified line | |||
| 1390 | glDisable(GL_TEXTURE_GEN_T); | 1400 | glDisable(GL_TEXTURE_GEN_T); |
| 1391 | glDisable(GL_TEXTURE_GEN_R); | 1401 | glDisable(GL_TEXTURE_GEN_R); |
| 1392 | glDisable(GL_TEXTURE_2D); | 1402 | glDisable(GL_TEXTURE_2D); |
| 1393 | 1403 | ||
| 1394 | } else if (texture) { | 1404 | } else if (texture) { |
| 1395 | _perlinModulateProgram.release(); | 1405 | _perlinModulateProgram.release(); |
| 1396 | glBindTexture(GL_TEXTURE_2D, 0); | 1406 | glBindTexture(GL_TEXTURE_2D, 0); |
| @@ -1403,7 +1413,7 @@ void VoxelSystem::killLocalVoxels() { · 6 unmodified lines | |||
| 1403 | lockTree(); | 1413 | lockTree(); |
| 1404 | _tree->eraseAllOctreeElements(); | 1414 | _tree->eraseAllOctreeElements(); |
| 1405 | unlockTree(); | 1415 | unlockTree(); |
| 1406 | clearFreeBufferIndexes(); | 1416 | clearFreeBufferIndexes(); |
| 1407 | _voxelsInReadArrays = 0; // do we need to do this? | 1417 | _voxelsInReadArrays = 0; // do we need to do this? |
| 1408 | setupNewVoxelsForDrawing(); | 1418 | setupNewVoxelsForDrawing(); |
| 1409 | } | 1419 | } |
| @@ -1422,7 +1432,7 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(OctreeElement* element, void · 12 unmodified lines | |||
| 1422 | 1432 | ||
| 1423 | void VoxelSystem::clearAllNodesBufferIndex() { | 1433 | void VoxelSystem::clearAllNodesBufferIndex() { |
| 1424 | _nodeCount = 0; | 1434 | _nodeCount = 0; |
| 1425 | lockTree(); | 1435 | lockTree(); |
| 1426 | _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); | 1436 | _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); |
| 1427 | unlockTree(); | 1437 | unlockTree(); |
| 1428 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { | 1438 | if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { |
| @@ -1584,9 +1594,9 @@ void VoxelSystem::falseColorizeBySource() { · 155 unmodified lines | |||
| 1584 | const int NUMBER_OF_COLOR_GROUPS = 6; | 1594 | const int NUMBER_OF_COLOR_GROUPS = 6; |
| 1585 | const unsigned char MIN_COLOR = 128; | 1595 | const unsigned char MIN_COLOR = 128; |
| 1586 | int voxelServerCount = 0; | 1596 | int voxelServerCount = 0; |
| 1587 | groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { | 1597 | groupColor groupColors[NUMBER_OF_COLOR_GROUPS] = { |
| 1588 | groupColor(255, 0, 0), | 1598 | groupColor(255, 0, 0), |
| 1589 | groupColor( 0, 255, 0), | 1599 | groupColor( 0, 255, 0), |
| 1590 | groupColor( 0, 0, 255), | 1600 | groupColor( 0, 0, 255), |
| 1591 | groupColor(255, 0, 255), | 1601 | groupColor(255, 0, 255), |
| 1592 | groupColor( 0, 255, 255), | 1602 | groupColor( 0, 255, 255), |
| @@ -1614,7 +1624,7 @@ void VoxelSystem::falseColorizeBySource() { · 21 unmodified lines | |||
| 1614 | voxelServerCount++; | 1624 | voxelServerCount++; |
| 1615 | } | 1625 | } |
| 1616 | } | 1626 | } |
| 1617 | 1627 | ||
| 1618 | _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args); | 1628 | _tree->recurseTreeWithOperation(falseColorizeBySourceOperation, &args); |
| 1619 | qDebug("setting false color by source for %d nodes\n", _nodeCount); | 1629 | qDebug("setting false color by source for %d nodes\n", _nodeCount); |
| 1620 | _tree->setDirtyBit(); | 1630 | _tree->setDirtyBit(); |
| @@ -1690,7 +1700,7 @@ public: · 69 unmodified lines | |||
| 1690 | unsigned long nodesOutside; | 1700 | unsigned long nodesOutside; |
| 1691 | VoxelTreeElement* insideRoot; | 1701 | VoxelTreeElement* insideRoot; |
| 1692 | VoxelTreeElement* outsideRoot; | 1702 | VoxelTreeElement* outsideRoot; |
| 1693 | 1703 | ||
| 1694 | removeOutOfViewArgs(VoxelSystem* voxelSystem, bool widenViewFrustum = true) : | 1704 | removeOutOfViewArgs(VoxelSystem* voxelSystem, bool widenViewFrustum = true) : |
| 1695 | thisVoxelSystem(voxelSystem), | 1705 | thisVoxelSystem(voxelSystem), |
| 1696 | thisViewFrustum(*voxelSystem->getViewFrustum()), | 1706 | thisViewFrustum(*voxelSystem->getViewFrustum()), |
| @@ -1730,7 +1740,7 @@ bool VoxelSystem::removeOutOfViewOperation(OctreeElement* element, void* extraDa · 33 unmodified lines | |||
| 1730 | args->dontRecurseBag.remove(voxel); | 1740 | args->dontRecurseBag.remove(voxel); |
| 1731 | return false; // stop recursion | 1741 | return false; // stop recursion |
| 1732 | } | 1742 | } |
| 1733 | 1743 | ||
| 1734 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; | 1744 | VoxelSystem* thisVoxelSystem = args->thisVoxelSystem; |
| 1735 | args->nodesScanned++; | 1745 | args->nodesScanned++; |
| 1736 | // Need to operate on our child nodes, so we can remove them | 1746 | // Need to operate on our child nodes, so we can remove them |
| @@ -1748,7 +1758,7 @@ bool VoxelSystem::removeOutOfViewOperation(OctreeElement* element, void* extraDa · 11 unmodified lines | |||
| 1748 | } break; | 1758 | } break; |
| 1749 | case ViewFrustum::INSIDE: { | 1759 | case ViewFrustum::INSIDE: { |
| 1750 | // if the child node is fully INSIDE the view, then there's no need to recurse it | 1760 | // if the child node is fully INSIDE the view, then there's no need to recurse it |
| 1751 | // because we know all it's children will also be in the view, so we want to | 1761 | // because we know all it's children will also be in the view, so we want to |
| 1752 | // tell the caller to NOT recurse this child | 1762 | // tell the caller to NOT recurse this child |
| 1753 | args->nodesInside++; | 1763 | args->nodesInside++; |
| 1754 | args->dontRecurseBag.insert(childNode); | 1764 | args->dontRecurseBag.insert(childNode); |
| @@ -1779,12 +1789,12 @@ bool VoxelSystem::isViewChanging() { · 24 unmodified lines | |||
| 1779 | 1789 | ||
| 1780 | bool VoxelSystem::hasViewChanged() { | 1790 | bool VoxelSystem::hasViewChanged() { |
| 1781 | bool result = false; // assume the best | 1791 | bool result = false; // assume the best |
| 1782 | 1792 | ||
| 1783 | // If we're still changing, report no change yet. | 1793 | // If we're still changing, report no change yet. |
| 1784 | if (isViewChanging()) { | 1794 | if (isViewChanging()) { |
| 1785 | return false; | 1795 | return false; |
| 1786 | } | 1796 | } |
| 1787 | 1797 | ||
| 1788 | // If our viewFrustum has changed since our _lastKnownViewFrustum | 1798 | // If our viewFrustum has changed since our _lastKnownViewFrustum |
| 1789 | if (!_lastStableViewFrustum.isVerySimilar(_viewFrustum)) { | 1799 | if (!_lastStableViewFrustum.isVerySimilar(_viewFrustum)) { |
| 1790 | result = true; | 1800 | result = true; |
| @@ -1803,8 +1813,8 @@ void VoxelSystem::removeOutOfView() { · 12 unmodified lines | |||
| 1803 | } | 1813 | } |
| 1804 | bool showRemoveDebugDetails = false; | 1814 | bool showRemoveDebugDetails = false; |
| 1805 | if (showRemoveDebugDetails) { | 1815 | if (showRemoveDebugDetails) { |
| 1806 | qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n", | 1816 | qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n", |
| 1807 | args.nodesScanned, args.nodesRemoved, args.nodesInside, | 1817 | args.nodesScanned, args.nodesRemoved, args.nodesInside, |
| 1808 | args.nodesIntersect, args.nodesOutside, _removedVoxels.count() | 1818 | args.nodesIntersect, args.nodesOutside, _removedVoxels.count() |
| 1809 | ); | 1819 | ); |
| 1810 | } | 1820 | } |
| @@ -1816,9 +1826,9 @@ public: · 5 unmodified lines | |||
| 1816 | VoxelSystem* thisVoxelSystem; | 1826 | VoxelSystem* thisVoxelSystem; |
| 1817 | ViewFrustum thisViewFrustum; | 1827 | ViewFrustum thisViewFrustum; |
| 1818 | unsigned long nodesScanned; | 1828 | unsigned long nodesScanned; |
| 1819 | 1829 | ||
| 1820 | showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) : | 1830 | showAllLocalVoxelsArgs(VoxelSystem* voxelSystem) : |
| 1821 | thisVoxelSystem(voxelSystem), | 1831 | thisVoxelSystem(voxelSystem), |
| 1822 | thisViewFrustum(*voxelSystem->getViewFrustum()), | 1832 | thisViewFrustum(*voxelSystem->getViewFrustum()), |
| 1823 | nodesScanned(0) | 1833 | nodesScanned(0) |
| 1824 | { | 1834 | { |
| @@ -1880,8 +1890,9 @@ public: · 55 unmodified lines | |||
| 1880 | unsigned long nodesOutsideInside; | 1890 | unsigned long nodesOutsideInside; |
| 1881 | unsigned long nodesInsideOutside; | 1891 | unsigned long nodesInsideOutside; |
| 1882 | unsigned long nodesOutsideOutside; | 1892 | unsigned long nodesOutsideOutside; |
| 1883 | 1893 | unsigned long nodesShown; | |
| 1884 | hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, | 1894 | |
| 1895 | hideOutOfViewArgs(VoxelSystem* voxelSystem, VoxelTree* tree, | ||
| 1885 | bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) : | 1896 | bool culledOnce, bool widenViewFrustum, bool wantDeltaFrustums) : |
| 1886 | thisVoxelSystem(voxelSystem), | 1897 | thisVoxelSystem(voxelSystem), |
| 1887 | tree(tree), | 1898 | tree(tree), |
| @@ -1898,7 +1909,8 @@ public: · 10 unmodified lines | |||
| 1898 | nodesIntersectInside(0), | 1909 | nodesIntersectInside(0), |
| 1899 | nodesOutsideInside(0), | 1910 | nodesOutsideInside(0), |
| 1900 | nodesInsideOutside(0), | 1911 | nodesInsideOutside(0), |
| 1901 | nodesOutsideOutside(0) | 1912 | nodesOutsideOutside(0), |
| 1913 | nodesShown(0) | ||
| 1902 | { | 1914 | { |
| 1903 | // Widen the FOV for trimming | 1915 | // Widen the FOV for trimming |
| 1904 | if (widenViewFrustum) { | 1916 | if (widenViewFrustum) { |
| @@ -1916,13 +1928,14 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { · 11 unmodified lines | |||
| 1916 | if (_inhideOutOfView) { | 1928 | if (_inhideOutOfView) { |
| 1917 | return; | 1929 | return; |
| 1918 | } | 1930 | } |
| 1919 | 1931 | ||
| 1920 | _inhideOutOfView = true; | 1932 | _inhideOutOfView = true; |
| 1921 | 1933 | ||
| 1922 | bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); | 1934 | bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); |
| 1923 | PerformanceWarning warn(showDebugDetails, "hideOutOfView()"); | 1935 | PerformanceWarning warn(showDebugDetails, "hideOutOfView()"); |
| 1924 | bool widenFrustum = true; | 1936 | bool widenFrustum = true; |
| 1925 | 1937 | ||
| 1938 | |||
| 1926 | // When using "delta" view frustums and only hide/show items that are in the difference | 1939 | // When using "delta" view frustums and only hide/show items that are in the difference |
| 1927 | // between the two view frustums. There are some potential problems with this mode. | 1940 | // between the two view frustums. There are some potential problems with this mode. |
| 1928 | // | 1941 | // |
| @@ -1932,7 +1945,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { · 3 unmodified lines | |||
| 1932 | // | 1945 | // |
| 1933 | // 2) Also, voxels will arrive from the network that are OUTSIDE of the view | 1946 | // 2) Also, voxels will arrive from the network that are OUTSIDE of the view |
| 1934 | // frustum... these won't get hidden... and so we can't assume they are correctly | 1947 | // frustum... these won't get hidden... and so we can't assume they are correctly |
| 1935 | // hidden... | 1948 | // hidden... |
| 1936 | // | 1949 | // |
| 1937 | // Both these problems are solved by intermittently calling this with forceFullFrustum set | 1950 | // Both these problems are solved by intermittently calling this with forceFullFrustum set |
| 1938 | // to true. This will essentially clean up the improperly hidden or shown voxels. | 1951 | // to true. This will essentially clean up the improperly hidden or shown voxels. |
| @@ -1947,13 +1960,13 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { · 8 unmodified lines | |||
| 1947 | args.lastViewFrustum.printDebugDetails(); | 1960 | args.lastViewFrustum.printDebugDetails(); |
| 1948 | } | 1961 | } |
| 1949 | } | 1962 | } |
| 1950 | 1963 | ||
| 1951 | if (!forceFullFrustum && _culledOnce && args.lastViewFrustum.isVerySimilar(args.thisViewFrustum)) { | 1964 | if (!forceFullFrustum && _culledOnce && args.lastViewFrustum.isVerySimilar(args.thisViewFrustum)) { |
| 1952 | _inhideOutOfView = false; | 1965 | _inhideOutOfView = false; |
| 1953 | return; | 1966 | return; |
| 1954 | } | 1967 | } |
| 1955 | 1968 | ||
| 1956 | lockTree(); | 1969 | lockTree(); |
| 1957 | _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); | 1970 | _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); |
| 1958 | unlockTree(); | 1971 | unlockTree(); |
| 1959 | _lastCulledViewFrustum = args.thisViewFrustum; // save last stable | 1972 | _lastCulledViewFrustum = args.thisViewFrustum; // save last stable |
| @@ -1963,16 +1976,19 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { · 3 unmodified lines | |||
| 1963 | _tree->setDirtyBit(); | 1976 | _tree->setDirtyBit(); |
| 1964 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); | 1977 | setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); |
| 1965 | } | 1978 | } |
| 1966 | 1979 | ||
| 1967 | bool extraDebugDetails = Application::getInstance()->getLogger()->extraDebugging(); | 1980 | bool extraDebugDetails = false; // Application::getInstance()->getLogger()->extraDebugging(); |
| 1968 | if (extraDebugDetails) { | 1981 | if (extraDebugDetails) { |
| 1969 | qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n", | 1982 | qDebug("hideOutOfView() scanned=%ld removed=%ld show=%ld inside=%ld intersect=%ld outside=%ld\n", |
| 1970 | args.nodesScanned, args.nodesRemoved, args.nodesInside, | 1983 | args.nodesScanned, args.nodesRemoved, args.nodesShown, args.nodesInside, |
| 1971 | args.nodesIntersect, args.nodesOutside | 1984 | args.nodesIntersect, args.nodesOutside |
| 1972 | ); | 1985 | ); |
| 1973 | qDebug(" inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n", | 1986 | qDebug(" inside/inside=%ld intersect/inside=%ld outside/outside=%ld\n", |
| 1974 | args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside | 1987 | args.nodesInsideInside, args.nodesIntersectInside, args.nodesOutsideOutside |
| 1975 | ); | 1988 | ); |
| 1989 | |||
| 1990 | qDebug() << "args.thisViewFrustum....\n"; | ||
| 1991 | args.thisViewFrustum.printDebugDetails(); | ||
| 1976 | } | 1992 | } |
| 1977 | _inhideOutOfView = false; | 1993 | _inhideOutOfView = false; |
| 1978 | } | 1994 | } |
| @@ -1985,10 +2001,10 @@ bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraDat · 6 unmodified lines | |||
| 1985 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not | 2001 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not |
| 1986 | // consider that case. | 2002 | // consider that case. |
| 1987 | ViewFrustum::location inLastCulledFrustum; | 2003 | ViewFrustum::location inLastCulledFrustum; |
| 1988 | 2004 | ||
| 1989 | if (args->culledOnce && args->wantDeltaFrustums) { | 2005 | if (args->culledOnce && args->wantDeltaFrustums) { |
| 1990 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); | 2006 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); |
| 1991 | 2007 | ||
| 1992 | // if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further | 2008 | // if this node is fully OUTSIDE our last culled view frustum, then we don't need to recurse further |
| 1993 | if (inLastCulledFrustum == ViewFrustum::OUTSIDE) { | 2009 | if (inLastCulledFrustum == ViewFrustum::OUTSIDE) { |
| 1994 | args->nodesOutsideOutside++; | 2010 | args->nodesOutsideOutside++; |
| @@ -2009,7 +2025,7 @@ bool VoxelSystem::hideAllSubTreeOperation(OctreeElement* element, void* extraDat · 14 unmodified lines | |||
| 2009 | } | 2025 | } |
| 2010 | 2026 | ||
| 2011 | } | 2027 | } |
| 2012 | 2028 | ||
| 2013 | return true; | 2029 | return true; |
| 2014 | } | 2030 | } |
| 2015 | 2031 | ||
| @@ -2021,10 +2037,10 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat · 5 unmodified lines | |||
| 2021 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not | 2037 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not |
| 2022 | // consider that case. | 2038 | // consider that case. |
| 2023 | ViewFrustum::location inLastCulledFrustum; | 2039 | ViewFrustum::location inLastCulledFrustum; |
| 2024 | 2040 | ||
| 2025 | if (args->culledOnce && args->wantDeltaFrustums) { | 2041 | if (args->culledOnce && args->wantDeltaFrustums) { |
| 2026 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); | 2042 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); |
| 2027 | 2043 | ||
| 2028 | // if this node is fully inside our last culled view frustum, then we don't need to recurse further | 2044 | // if this node is fully inside our last culled view frustum, then we don't need to recurse further |
| 2029 | if (inLastCulledFrustum == ViewFrustum::INSIDE) { | 2045 | if (inLastCulledFrustum == ViewFrustum::INSIDE) { |
| 2030 | args->nodesInsideInside++; | 2046 | args->nodesInsideInside++; |
| @@ -2047,35 +2063,36 @@ bool VoxelSystem::showAllSubTreeOperation(OctreeElement* element, void* extraDat · 16 unmodified lines | |||
| 2047 | // These are both needed to force redraw... | 2063 | // These are both needed to force redraw... |
| 2048 | voxel->setDirtyBit(); | 2064 | voxel->setDirtyBit(); |
| 2049 | voxel->markWithChangedTime(); | 2065 | voxel->markWithChangedTime(); |
| 2066 | args->nodesShown++; | ||
| 2050 | } | 2067 | } |
| 2051 | 2068 | ||
| 2052 | return true; // keep recursing! | 2069 | return true; // keep recursing! |
| 2053 | } | 2070 | } |
| 2054 | 2071 | ||
| 2055 | // "hide" voxels in the VBOs that are still in the tree that but not in view. | 2072 | // "hide" voxels in the VBOs that are still in the tree that but not in view. |
| 2056 | // We don't remove them from the tree, we don't delete them, we do remove them | 2073 | // We don't remove them from the tree, we don't delete them, we do remove them |
| 2057 | // from the VBOs and mark them as such in the tree. | 2074 | // from the VBOs and mark them as such in the tree. |
| 2058 | bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData) { | 2075 | bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData) { |
| 2059 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | 2076 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; |
| 2060 | hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData; | 2077 | hideOutOfViewArgs* args = (hideOutOfViewArgs*)extraData; |
| 2061 | 2078 | ||
| 2062 | // If we're still recursing the tree using this operator, then we don't know if we're inside or outside... | 2079 | // If we're still recursing the tree using this operator, then we don't know if we're inside or outside... |
| 2063 | // so before we move forward we need to determine our frustum location | 2080 | // so before we move forward we need to determine our frustum location |
| 2064 | ViewFrustum::location inFrustum = voxel->inFrustum(args->thisViewFrustum); | 2081 | ViewFrustum::location inFrustum = voxel->inFrustum(args->thisViewFrustum); |
| 2065 | 2082 | ||
| 2066 | // If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine | 2083 | // If we've culled at least once, then we will use the status of this voxel in the last culled frustum to determine |
| 2067 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not | 2084 | // how to proceed. If we've never culled, then we just consider all these voxels to be UNKNOWN so that we will not |
| 2068 | // consider that case. | 2085 | // consider that case. |
| 2069 | ViewFrustum::location inLastCulledFrustum; | 2086 | ViewFrustum::location inLastCulledFrustum; |
| 2070 | 2087 | ||
| 2071 | if (args->culledOnce && args->wantDeltaFrustums) { | 2088 | if (args->culledOnce && args->wantDeltaFrustums) { |
| 2072 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); | 2089 | inLastCulledFrustum = voxel->inFrustum(args->lastViewFrustum); |
| 2073 | } | 2090 | } |
| 2074 | 2091 | ||
| 2075 | // ok, now do some processing for this node... | 2092 | // ok, now do some processing for this node... |
| 2076 | switch (inFrustum) { | 2093 | switch (inFrustum) { |
| 2077 | case ViewFrustum::OUTSIDE: { | 2094 | case ViewFrustum::OUTSIDE: { |
| 2078 | 2095 | ||
| 2079 | // If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE, | 2096 | // If this node is outside the current view, then we might want to hide it... unless it was previously OUTSIDE, |
| 2080 | // if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume | 2097 | // if it was previously outside, then we can safely assume it's already hidden, and we can also safely assume |
| 2081 | // that all of it's children are outside both of our views, in which case we can just stop recursing... | 2098 | // that all of it's children are outside both of our views, in which case we can just stop recursing... |
| @@ -2084,17 +2101,17 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 2 unmodified lines | |||
| 2084 | args->nodesOutsideOutside++; | 2101 | args->nodesOutsideOutside++; |
| 2085 | return false; // stop recursing this branch! | 2102 | return false; // stop recursing this branch! |
| 2086 | } | 2103 | } |
| 2087 | 2104 | ||
| 2088 | // if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then | 2105 | // if this node is fully OUTSIDE the view, but previously intersected and/or was inside the last view, then |
| 2089 | // we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse | 2106 | // we need to hide it. Additionally we know that ALL of it's children are also fully OUTSIDE so we can recurse |
| 2090 | // the children and simply mark them as hidden | 2107 | // the children and simply mark them as hidden |
| 2091 | args->tree->recurseNodeWithOperation(voxel, hideAllSubTreeOperation, args ); | 2108 | args->tree->recurseNodeWithOperation(voxel, hideAllSubTreeOperation, args ); |
| 2092 | 2109 | ||
| 2093 | return false; | 2110 | return false; |
| 2094 | 2111 | ||
| 2095 | } break; | 2112 | } break; |
| 2096 | case ViewFrustum::INSIDE: { | 2113 | case ViewFrustum::INSIDE: { |
| 2097 | 2114 | ||
| 2098 | // If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE, | 2115 | // If this node is INSIDE the current view, then we might want to show it... unless it was previously INSIDE, |
| 2099 | // if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume | 2116 | // if it was previously INSIDE, then we can safely assume it's already shown, and we can also safely assume |
| 2100 | // that all of it's children are INSIDE both of our views, in which case we can just stop recursing... | 2117 | // that all of it's children are INSIDE both of our views, in which case we can just stop recursing... |
| @@ -2103,18 +2120,18 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 2 unmodified lines | |||
| 2103 | args->nodesInsideInside++; | 2120 | args->nodesInsideInside++; |
| 2104 | return false; // stop recursing this branch! | 2121 | return false; // stop recursing this branch! |
| 2105 | } | 2122 | } |
| 2106 | 2123 | ||
| 2107 | // if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then | 2124 | // if this node is fully INSIDE the view, but previously INTERSECTED and/or was OUTSIDE the last view, then |
| 2108 | // we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse | 2125 | // we need to show it. Additionally we know that ALL of it's children are also fully INSIDE so we can recurse |
| 2109 | // the children and simply mark them as visible (as appropriate based on LOD) | 2126 | // the children and simply mark them as visible (as appropriate based on LOD) |
| 2110 | args->tree->recurseNodeWithOperation(voxel, showAllSubTreeOperation, args); | 2127 | args->tree->recurseNodeWithOperation(voxel, showAllSubTreeOperation, args); |
| 2111 | 2128 | ||
| 2112 | return false; | 2129 | return false; |
| 2113 | } break; | 2130 | } break; |
| 2114 | case ViewFrustum::INTERSECT: { | 2131 | case ViewFrustum::INTERSECT: { |
| 2115 | args->nodesScanned++; | 2132 | args->nodesScanned++; |
| 2116 | 2133 | ||
| 2117 | // If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE | 2134 | // If this node INTERSECTS the current view, then we might want to show it... unless it was previously INSIDE |
| 2118 | // the last known view, in which case it will already be visible, and we know that all it's children are also | 2135 | // the last known view, in which case it will already be visible, and we know that all it's children are also |
| 2119 | // previously INSIDE and visible. So in this case stop recursing | 2136 | // previously INSIDE and visible. So in this case stop recursing |
| 2120 | if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) { | 2137 | if (args->culledOnce && args->wantDeltaFrustums && inLastCulledFrustum == ViewFrustum::INSIDE) { |
| @@ -2125,21 +2142,22 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 4 unmodified lines | |||
| 2125 | args->nodesIntersect++; | 2142 | args->nodesIntersect++; |
| 2126 | 2143 | ||
| 2127 | // if the child node INTERSECTs the view, then we want to check to see if it thinks it should render | 2144 | // if the child node INTERSECTs the view, then we want to check to see if it thinks it should render |
| 2128 | // if it should render but is missing it's VBO index, then we want to flip it on, and we can stop recursing from | 2145 | // if it should render but is missing it's VBO index, then we want to flip it on, and we can stop recursing from |
| 2129 | // here because we know will block any children anyway | 2146 | // here because we know will block any children anyway |
| 2130 | if (voxel->getShouldRender() && !voxel->isKnownBufferIndex()) { | 2147 | if (voxel->getShouldRender() && !voxel->isKnownBufferIndex()) { |
| 2131 | voxel->setDirtyBit(); // will this make it draw? | 2148 | voxel->setDirtyBit(); // will this make it draw? |
| 2149 | args->nodesShown++; | ||
| 2132 | return false; | 2150 | return false; |
| 2133 | } | 2151 | } |
| 2134 | 2152 | ||
| 2135 | // If it INTERSECTS but shouldn't be displayed, then it's probably a parent and it is at least partially in view. | 2153 | // If it INTERSECTS but shouldn't be displayed, then it's probably a parent and it is at least partially in view. |
| 2136 | // So we DO want to recurse the children because some of them may not be in view... nothing specifically to do, | 2154 | // So we DO want to recurse the children because some of them may not be in view... nothing specifically to do, |
| 2137 | // just keep iterating the children | 2155 | // just keep iterating the children |
| 2138 | return true; | 2156 | return true; |
| 2139 | 2157 | ||
| 2140 | } break; | 2158 | } break; |
| 2141 | } // switch | 2159 | } // switch |
| 2142 | 2160 | ||
| 2143 | 2161 | ||
| 2144 | return true; // keep going! | 2162 | return true; // keep going! |
| 2145 | } | 2163 | } |
| @@ -2147,7 +2165,7 @@ bool VoxelSystem::hideOutOfViewOperation(OctreeElement* element, void* extraData · 1 unmodified line | |||
| 2147 | 2165 | ||
| 2148 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, | 2166 | bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, |
| 2149 | VoxelDetail& detail, float& distance, BoxFace& face) { | 2167 | VoxelDetail& detail, float& distance, BoxFace& face) { |
| 2150 | lockTree(); | 2168 | lockTree(); |
| 2151 | OctreeElement* element; | 2169 | OctreeElement* element; |
| 2152 | if (!_tree->findRayIntersection(origin, direction, element, distance, face)) { | 2170 | if (!_tree->findRayIntersection(origin, direction, element, distance, face)) { |
| 2153 | unlockTree(); | 2171 | unlockTree(); |
| @@ -2206,7 +2224,7 @@ bool VoxelSystem::falseColorizeRandomEveryOtherOperation(OctreeElement* element, · 52 unmodified lines | |||
| 2206 | void VoxelSystem::falseColorizeRandomEveryOther() { | 2224 | void VoxelSystem::falseColorizeRandomEveryOther() { |
| 2207 | falseColorizeRandomEveryOtherArgs args; | 2225 | falseColorizeRandomEveryOtherArgs args; |
| 2208 | _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args); | 2226 | _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args); |
| 2209 | qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n", | 2227 | qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n", |
| 2210 | args.totalNodes, args.colorableNodes, args.coloredNodes); | 2228 | args.totalNodes, args.colorableNodes, args.coloredNodes); |
| 2211 | _tree->setDirtyBit(); | 2229 | _tree->setDirtyBit(); |
| 2212 | setupNewVoxelsForDrawing(); | 2230 | setupNewVoxelsForDrawing(); |
| @@ -2214,9 +2232,9 @@ void VoxelSystem::falseColorizeRandomEveryOther() { · 1 unmodified line | |||
| 2214 | 2232 | ||
| 2215 | class collectStatsForTreesAndVBOsArgs { | 2233 | class collectStatsForTreesAndVBOsArgs { |
| 2216 | public: | 2234 | public: |
| 2217 | collectStatsForTreesAndVBOsArgs(int maxVoxels) : | 2235 | collectStatsForTreesAndVBOsArgs(int maxVoxels) : |
| 2218 | totalNodes(0), | 2236 | totalNodes(0), |
| 2219 | dirtyNodes(0), | 2237 | dirtyNodes(0), |
| 2220 | shouldRenderNodes(0), | 2238 | shouldRenderNodes(0), |
| 2221 | coloredNodes(0), | 2239 | coloredNodes(0), |
| 2222 | nodesInVBO(0), | 2240 | nodesInVBO(0), |
| @@ -2228,7 +2246,7 @@ public: · 5 unmodified lines | |||
| 2228 | hasIndexFound = new bool[maxVoxels]; | 2246 | hasIndexFound = new bool[maxVoxels]; |
| 2229 | memset(hasIndexFound, false, maxVoxels * sizeof(bool)); | 2247 | memset(hasIndexFound, false, maxVoxels * sizeof(bool)); |
| 2230 | }; | 2248 | }; |
| 2231 | 2249 | ||
| 2232 | ~collectStatsForTreesAndVBOsArgs() { | 2250 | ~collectStatsForTreesAndVBOsArgs() { |
| 2233 | delete[] hasIndexFound; | 2251 | delete[] hasIndexFound; |
| 2234 | } | 2252 | } |
| @@ -2244,13 +2262,13 @@ public: · 9 unmodified lines | |||
| 2244 | unsigned long leafNodes; | 2262 | unsigned long leafNodes; |
| 2245 | 2263 | ||
| 2246 | unsigned long expectedMax; | 2264 | unsigned long expectedMax; |
| 2247 | 2265 | ||
| 2248 | bool* hasIndexFound; | 2266 | bool* hasIndexFound; |
| 2249 | }; | 2267 | }; |
| 2250 | 2268 | ||
| 2251 | bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, void* extraData) { | 2269 | bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, void* extraData) { |
| 2252 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; | 2270 | VoxelTreeElement* voxel = (VoxelTreeElement*)element; |
| 2253 | 2271 | ||
| 2254 | collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData; | 2272 | collectStatsForTreesAndVBOsArgs* args = (collectStatsForTreesAndVBOsArgs*)extraData; |
| 2255 | args->totalNodes++; | 2273 | args->totalNodes++; |
| 2256 | 2274 | ||
| @@ -2273,17 +2291,17 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v · 16 unmodified lines | |||
| 2273 | if (voxel->isKnownBufferIndex()) { | 2291 | if (voxel->isKnownBufferIndex()) { |
| 2274 | args->nodesInVBO++; | 2292 | args->nodesInVBO++; |
| 2275 | unsigned long nodeIndex = voxel->getBufferIndex(); | 2293 | unsigned long nodeIndex = voxel->getBufferIndex(); |
| 2276 | 2294 | ||
| 2277 | const bool extraDebugging = false; // enable for extra debugging | 2295 | const bool extraDebugging = false; // enable for extra debugging |
| 2278 | if (extraDebugging) { | 2296 | if (extraDebugging) { |
| 2279 | qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n", | 2297 | qDebug("node In VBO... [%f,%f,%f] %f ... index=%ld, isDirty=%s, shouldRender=%s \n", |
| 2280 | voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), | 2298 | voxel->getCorner().x, voxel->getCorner().y, voxel->getCorner().z, voxel->getScale(), |
| 2281 | nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); | 2299 | nodeIndex, debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); |
| 2282 | } | 2300 | } |
| 2283 | 2301 | ||
| 2284 | if (args->hasIndexFound[nodeIndex]) { | 2302 | if (args->hasIndexFound[nodeIndex]) { |
| 2285 | args->duplicateVBOIndex++; | 2303 | args->duplicateVBOIndex++; |
| 2286 | qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, | 2304 | qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, |
| 2287 | debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); | 2305 | debug::valueOf(voxel->isDirty()), debug::valueOf(voxel->getShouldRender())); |
| 2288 | } else { | 2306 | } else { |
| 2289 | args->hasIndexFound[nodeIndex] = true; | 2307 | args->hasIndexFound[nodeIndex] = true; |
| @@ -2291,7 +2309,7 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(OctreeElement* element, v · 1 unmodified line | |||
| 2291 | if (nodeIndex > args->expectedMax) { | 2309 | if (nodeIndex > args->expectedMax) { |
| 2292 | args->nodesInVBOOverExpectedMax++; | 2310 | args->nodesInVBOOverExpectedMax++; |
| 2293 | } | 2311 | } |
| 2294 | 2312 | ||
| 2295 | // if it's in VBO but not-shouldRender, track that also... | 2313 | // if it's in VBO but not-shouldRender, track that also... |
| 2296 | if (!voxel->getShouldRender()) { | 2314 | if (!voxel->getShouldRender()) { |
| 2297 | args->nodesInVBONotShouldRender++; | 2315 | args->nodesInVBONotShouldRender++; |
| @@ -2316,9 +2334,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 18 unmodified lines | |||
| 2316 | 2334 | ||
| 2317 | collectStatsForTreesAndVBOsArgs args(_maxVoxels); | 2335 | collectStatsForTreesAndVBOsArgs args(_maxVoxels); |
| 2318 | args.expectedMax = _voxelsInWriteArrays; | 2336 | args.expectedMax = _voxelsInWriteArrays; |
| 2319 | 2337 | ||
| 2320 | qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>\n"); | 2338 | qDebug("CALCULATING Local Voxel Tree Statistics >>>>>>>>>>>>\n"); |
| 2321 | 2339 | ||
| 2322 | _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); | 2340 | _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); |
| 2323 | 2341 | ||
| 2324 | qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", | 2342 | qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", |
| @@ -2327,7 +2345,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 2 unmodified lines | |||
| 2327 | qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty), | 2345 | qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty), |
| 2328 | _voxelsInWriteArrays, minDirty, maxDirty); | 2346 | _voxelsInWriteArrays, minDirty, maxDirty); |
| 2329 | 2347 | ||
| 2330 | qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n", | 2348 | qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n", |
| 2331 | args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); | 2349 | args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); |
| 2332 | 2350 | ||
| 2333 | glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; | 2351 | glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; |
| @@ -2340,10 +2358,10 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { · 6 unmodified lines | |||
| 2340 | } | 2358 | } |
| 2341 | } | 2359 | } |
| 2342 | 2360 | ||
| 2343 | qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", | 2361 | qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", |
| 2344 | minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); | 2362 | minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); |
| 2345 | 2363 | ||
| 2346 | qDebug(" _freeIndexes.size()=%ld \n", | 2364 | qDebug(" _freeIndexes.size()=%ld \n", |
| 2347 | _freeIndexes.size()); | 2365 | _freeIndexes.size()); |
| 2348 | 2366 | ||
| 2349 | qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>\n"); | 2367 | qDebug("DONE WITH Local Voxel Tree Statistics >>>>>>>>>>>>\n"); |
| @@ -2354,36 +2372,36 @@ void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { · 4 unmodified lines | |||
| 2354 | lockTree(); | 2372 | lockTree(); |
| 2355 | _tree->deleteVoxelAt(x, y, z, s); | 2373 | _tree->deleteVoxelAt(x, y, z, s); |
| 2356 | unlockTree(); | 2374 | unlockTree(); |
| 2357 | 2375 | ||
| 2358 | // redraw! | 2376 | // redraw! |
| 2359 | setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? | 2377 | setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? |
| 2360 | 2378 | ||
| 2361 | }; | 2379 | }; |
| 2362 | 2380 | ||
| 2363 | VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { | 2381 | VoxelTreeElement* VoxelSystem::getVoxelAt(float x, float y, float z, float s) const { |
| 2364 | return _tree->getVoxelAt(x, y, z, s); | 2382 | return _tree->getVoxelAt(x, y, z, s); |
| 2365 | }; | 2383 | }; |
| 2366 | 2384 | ||
| 2367 | void VoxelSystem::createVoxel(float x, float y, float z, float s, | 2385 | void VoxelSystem::createVoxel(float x, float y, float z, float s, |
| 2368 | unsigned char red, unsigned char green, unsigned char blue, bool destructive) { | 2386 | unsigned char red, unsigned char green, unsigned char blue, bool destructive) { |
| 2369 | 2387 | ||
| 2370 | //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); | 2388 | //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); |
| 2371 | lockTree(); | 2389 | lockTree(); |
| 2372 | _tree->createVoxel(x, y, z, s, red, green, blue, destructive); | 2390 | _tree->createVoxel(x, y, z, s, red, green, blue, destructive); |
| 2373 | unlockTree(); | 2391 | unlockTree(); |
| 2374 | 2392 | ||
| 2375 | setupNewVoxelsForDrawing(); | 2393 | setupNewVoxelsForDrawing(); |
| 2376 | }; | 2394 | }; |
| 2377 | 2395 | ||
| 2378 | void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { | 2396 | void VoxelSystem::createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive) { |
| 2379 | _tree->createLine(point1, point2, unitSize, color, destructive); | 2397 | _tree->createLine(point1, point2, unitSize, color, destructive); |
| 2380 | setupNewVoxelsForDrawing(); | 2398 | setupNewVoxelsForDrawing(); |
| 2381 | }; | 2399 | }; |
| 2382 | 2400 | ||
| 2383 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, | 2401 | void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bool solid, |
| 2384 | creationMode mode, bool destructive, bool debug) { | 2402 | creationMode mode, bool destructive, bool debug) { |
| 2385 | _tree->createSphere(r, xc, yc, zc, s, solid, mode, destructive, debug); | 2403 | _tree->createSphere(r, xc, yc, zc, s, solid, mode, destructive, debug); |
| 2386 | setupNewVoxelsForDrawing(); | 2404 | setupNewVoxelsForDrawing(); |
| 2387 | }; | 2405 | }; |
| 2388 | 2406 | ||
| 2389 | void VoxelSystem::copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelSystem* destination, bool rebaseToRoot) { | 2407 | void VoxelSystem::copySubTreeIntoNewTree(VoxelTreeElement* startNode, VoxelSystem* destination, bool rebaseToRoot) { |
| @@ -2431,7 +2449,7 @@ bool VoxelSystem::falseColorizeSubTreeOperation(OctreeElement* element, void* ex · 41 unmodified lines | |||
| 2431 | voxel->setFalseColor(args->color[0], args->color[1], args->color[2]); | 2449 | voxel->setFalseColor(args->color[0], args->color[1], args->color[2]); |
| 2432 | args->voxelsTouched++; | 2450 | args->voxelsTouched++; |
| 2433 | } | 2451 | } |
| 2434 | return true; | 2452 | return true; |
| 2435 | } | 2453 | } |
| 2436 | 2454 | ||
| 2437 | bool VoxelSystem::falseColorizeOccludedOperation(OctreeElement* element, void* extraData) { | 2455 | bool VoxelSystem::falseColorizeOccludedOperation(OctreeElement* element, void* extraData) { |
| @@ -2459,18 +2477,18 @@ bool VoxelSystem::falseColorizeOccludedOperation(OctreeElement* element, void* e · 21 unmodified lines | |||
| 2459 | if (result == OCCLUDED) { | 2477 | if (result == OCCLUDED) { |
| 2460 | args->nonLeavesOccluded++; | 2478 | args->nonLeavesOccluded++; |
| 2461 | delete voxelPolygon; | 2479 | delete voxelPolygon; |
| 2462 | 2480 | ||
| 2463 | FalseColorizeSubTreeOperationArgs subArgs; | 2481 | FalseColorizeSubTreeOperationArgs subArgs; |
| 2464 | subArgs.color[0] = 0; | 2482 | subArgs.color[0] = 0; |
| 2465 | subArgs.color[1] = 255; | 2483 | subArgs.color[1] = 255; |
| 2466 | subArgs.color[2] = 0; | 2484 | subArgs.color[2] = 0; |
| 2467 | subArgs.voxelsTouched = 0; | 2485 | subArgs.voxelsTouched = 0; |
| 2468 | 2486 | ||
| 2469 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); | 2487 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); |
| 2470 | 2488 | ||
| 2471 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); | 2489 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); |
| 2472 | args->totalVoxels += (subArgs.voxelsTouched - 1); | 2490 | args->totalVoxels += (subArgs.voxelsTouched - 1); |
| 2473 | 2491 | ||
| 2474 | return false; | 2492 | return false; |
| 2475 | } | 2493 | } |
| 2476 | 2494 | ||
| @@ -2509,10 +2527,10 @@ bool VoxelSystem::falseColorizeOccludedOperation(OctreeElement* element, void* e · 32 unmodified lines | |||
| 2509 | void VoxelSystem::falseColorizeOccluded() { | 2527 | void VoxelSystem::falseColorizeOccluded() { |
| 2510 | PerformanceWarning warn(true, "falseColorizeOccluded()",true); | 2528 | PerformanceWarning warn(true, "falseColorizeOccluded()",true); |
| 2511 | myCoverageMap.erase(); | 2529 | myCoverageMap.erase(); |
| 2512 | 2530 | ||
| 2513 | FalseColorizeOccludedArgs args; | 2531 | FalseColorizeOccludedArgs args; |
| 2514 | args.viewFrustum = _viewFrustum; | 2532 | args.viewFrustum = _viewFrustum; |
| 2515 | args.map = &myCoverageMap; | 2533 | args.map = &myCoverageMap; |
| 2516 | args.totalVoxels = 0; | 2534 | args.totalVoxels = 0; |
| 2517 | args.coloredVoxels = 0; | 2535 | args.coloredVoxels = 0; |
| 2518 | args.occludedVoxels = 0; | 2536 | args.occludedVoxels = 0; |
| @@ -2527,15 +2545,15 @@ void VoxelSystem::falseColorizeOccluded() { · 8 unmodified lines | |||
| 2527 | OctreeProjectedPolygon::pointInside_calls = 0; | 2545 | OctreeProjectedPolygon::pointInside_calls = 0; |
| 2528 | OctreeProjectedPolygon::occludes_calls = 0; | 2546 | OctreeProjectedPolygon::occludes_calls = 0; |
| 2529 | OctreeProjectedPolygon::intersects_calls = 0; | 2547 | OctreeProjectedPolygon::intersects_calls = 0; |
| 2530 | 2548 | ||
| 2531 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); | 2549 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); |
| 2532 | 2550 | ||
| 2533 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); | 2551 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); |
| 2534 | 2552 | ||
| 2535 | 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\n", | 2553 | 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\n", |
| 2536 | position.x, position.y, | 2554 | position.x, position.y, |
| 2537 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, | 2555 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, |
| 2538 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, | 2556 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, |
| 2539 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, | 2557 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, |
| 2540 | OctreeProjectedPolygon::pointInside_calls, | 2558 | OctreeProjectedPolygon::pointInside_calls, |
| 2541 | OctreeProjectedPolygon::occludes_calls, | 2559 | OctreeProjectedPolygon::occludes_calls, |
| @@ -2574,18 +2592,18 @@ bool VoxelSystem::falseColorizeOccludedV2Operation(OctreeElement* element, void* · 32 unmodified lines | |||
| 2574 | if (result == V2_OCCLUDED) { | 2592 | if (result == V2_OCCLUDED) { |
| 2575 | args->nonLeavesOccluded++; | 2593 | args->nonLeavesOccluded++; |
| 2576 | delete voxelPolygon; | 2594 | delete voxelPolygon; |
| 2577 | 2595 | ||
| 2578 | FalseColorizeSubTreeOperationArgs subArgs; | 2596 | FalseColorizeSubTreeOperationArgs subArgs; |
| 2579 | subArgs.color[0] = 0; | 2597 | subArgs.color[0] = 0; |
| 2580 | subArgs.color[1] = 255; | 2598 | subArgs.color[1] = 255; |
| 2581 | subArgs.color[2] = 0; | 2599 | subArgs.color[2] = 0; |
| 2582 | subArgs.voxelsTouched = 0; | 2600 | subArgs.voxelsTouched = 0; |
| 2583 | 2601 | ||
| 2584 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); | 2602 | args->tree->recurseNodeWithOperation(voxel, falseColorizeSubTreeOperation, &subArgs ); |
| 2585 | 2603 | ||
| 2586 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); | 2604 | args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); |
| 2587 | args->totalVoxels += (subArgs.voxelsTouched - 1); | 2605 | args->totalVoxels += (subArgs.voxelsTouched - 1); |
| 2588 | 2606 | ||
| 2589 | return false; | 2607 | return false; |
| 2590 | } | 2608 | } |
| 2591 | 2609 | ||
| @@ -2632,10 +2650,10 @@ void VoxelSystem::falseColorizeOccludedV2() { · 40 unmodified lines | |||
| 2632 | OctreeProjectedPolygon::pointInside_calls = 0; | 2650 | OctreeProjectedPolygon::pointInside_calls = 0; |
| 2633 | OctreeProjectedPolygon::occludes_calls = 0; | 2651 | OctreeProjectedPolygon::occludes_calls = 0; |
| 2634 | OctreeProjectedPolygon::intersects_calls = 0; | 2652 | OctreeProjectedPolygon::intersects_calls = 0; |
| 2635 | 2653 | ||
| 2636 | FalseColorizeOccludedArgs args; | 2654 | FalseColorizeOccludedArgs args; |
| 2637 | args.viewFrustum = _viewFrustum; | 2655 | args.viewFrustum = _viewFrustum; |
| 2638 | args.mapV2 = &myCoverageMapV2; | 2656 | args.mapV2 = &myCoverageMapV2; |
| 2639 | args.totalVoxels = 0; | 2657 | args.totalVoxels = 0; |
| 2640 | args.coloredVoxels = 0; | 2658 | args.coloredVoxels = 0; |
| 2641 | args.occludedVoxels = 0; | 2659 | args.occludedVoxels = 0; |
| @@ -2646,15 +2664,15 @@ void VoxelSystem::falseColorizeOccludedV2() { · 4 unmodified lines | |||
| 2646 | args.nonLeavesOutOfView = 0; | 2664 | args.nonLeavesOutOfView = 0; |
| 2647 | args.nonLeavesOccluded = 0; | 2665 | args.nonLeavesOccluded = 0; |
| 2648 | args.tree = _tree; | 2666 | args.tree = _tree; |
| 2649 | 2667 | ||
| 2650 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); | 2668 | glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); |
| 2651 | 2669 | ||
| 2652 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedV2Operation, position, (void*)&args); | 2670 | _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedV2Operation, position, (void*)&args); |
| 2653 | 2671 | ||
| 2654 | 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", | 2672 | 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", |
| 2655 | position.x, position.y, | 2673 | position.x, position.y, |
| 2656 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, | 2674 | args.totalVoxels, args.coloredVoxels, args.occludedVoxels, |
| 2657 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, | 2675 | args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, |
| 2658 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, | 2676 | args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded, |
| 2659 | OctreeProjectedPolygon::pointInside_calls, | 2677 | OctreeProjectedPolygon::pointInside_calls, |
| 2660 | OctreeProjectedPolygon::occludes_calls, | 2678 | OctreeProjectedPolygon::occludes_calls, |
| @@ -2717,7 +2735,7 @@ unsigned long VoxelSystem::getFreeMemoryGPU() { · 56 unmodified lines | |||
| 2717 | const GLenum VBO_FREE_MEMORY_ATI = 0x87FB; | 2735 | const GLenum VBO_FREE_MEMORY_ATI = 0x87FB; |
| 2718 | glGetIntegerv(VBO_FREE_MEMORY_ATI, &results[0]); | 2736 | glGetIntegerv(VBO_FREE_MEMORY_ATI, &results[0]); |
| 2719 | GLenum errorATI = glGetError(); | 2737 | GLenum errorATI = glGetError(); |
| 2720 | 2738 | ||
| 2721 | if (errorATI == GL_NO_ERROR) { | 2739 | if (errorATI == GL_NO_ERROR) { |
| 2722 | _hasMemoryUsageGPU = true; | 2740 | _hasMemoryUsageGPU = true; |
| 2723 | freeMemory = results[0]; | 2741 | freeMemory = results[0]; |
| @@ -2730,19 +2748,19 @@ unsigned long VoxelSystem::getFreeMemoryGPU() { · 6 unmodified lines | |||
| 2730 | //const GLenum GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x904A; | 2748 | //const GLenum GPU_MEMORY_INFO_EVICTION_COUNT_NVX = 0x904A; |
| 2731 | //const GLenum GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x904B; | 2749 | //const GLenum GPU_MEMORY_INFO_EVICTED_MEMORY_NVX = 0x904B; |
| 2732 | //const GLenum GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048; | 2750 | //const GLenum GPU_MEMORY_INFO_TOTAL_AVAILABLE_MEMORY_NVX = 0x9048; |
| 2733 | 2751 | ||
| 2734 | const GLenum GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049; | 2752 | const GLenum GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX = 0x9049; |
| 2735 | results[0] = 0; | 2753 | results[0] = 0; |
| 2736 | glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &results[0]); | 2754 | glGetIntegerv(GPU_MEMORY_INFO_CURRENT_AVAILABLE_VIDMEM_NVX, &results[0]); |
| 2737 | freeMemory += results[0]; | 2755 | freeMemory += results[0]; |
| 2738 | GLenum errorNVIDIA = glGetError(); | 2756 | GLenum errorNVIDIA = glGetError(); |
| 2739 | 2757 | ||
| 2740 | if (errorNVIDIA == GL_NO_ERROR) { | 2758 | if (errorNVIDIA == GL_NO_ERROR) { |
| 2741 | _hasMemoryUsageGPU = true; | 2759 | _hasMemoryUsageGPU = true; |
| 2742 | freeMemory = results[0]; | 2760 | freeMemory = results[0]; |
| 2743 | } | 2761 | } |
| 2744 | } | 2762 | } |
| 2745 | 2763 | ||
| 2746 | const unsigned long BYTES_PER_KBYTE = 1024; | 2764 | const unsigned long BYTES_PER_KBYTE = 1024; |
| 2747 | return freeMemory * BYTES_PER_KBYTE; // API results in KB, we want it in bytes | 2765 | return freeMemory * BYTES_PER_KBYTE; // API results in KB, we want it in bytes |
| 2748 | } | 2766 | } |
| @@ -2763,4 +2781,22 @@ void VoxelSystem::unlockTree() { · 14 unmodified lines | |||
| 2763 | } | 2781 | } |
| 2764 | 2782 | ||
| 2765 | 2783 | ||
| 2784 | void VoxelSystem::localVoxelCacheLoaded() { | ||
| 2785 | qDebug() << "localVoxelCacheLoaded()\n"; | ||
| 2786 | |||
| 2787 | // Make sure that the application has properly set up the view frustum for our loaded state | ||
| 2788 | Application::getInstance()->initAvatarAndViewFrustum(); | ||
| 2789 | |||
| 2790 | _tree->setDirtyBit(); | ||
| 2791 | setupNewVoxelsForDrawing(); | ||
| 2792 | _inhideOutOfView = false; // reenable hideOutOfView behavior | ||
| 2793 | } | ||
| 2794 | |||
| 2795 | void VoxelSystem::beginLoadingLocalVoxelCache() { | ||
| 2796 | qDebug() << "beginLoadingLocalVoxelCache()\n"; | ||
| 2797 | _writeRenderFullVBO = true; // this will disable individual node updates | ||
| 2798 | _inhideOutOfView = true; // this will disable hidOutOfView which we want to do until local cache is loaded | ||
| 2799 | } | ||
| 2800 | |||
| 2801 | |||
| 2766 | 2802 | ||