| 386 | } |
| 387 | |
| 388 | AvailabilityNode* OctreeAvailability::addNode( |
| 389 | const OctreeTileID& tileID, |
| 390 | AvailabilityNode* pParentNode) noexcept { |
| 391 | |
| 392 | if (!pParentNode || tileID.level == 0) { |
| 393 | if (this->_pRoot) { |
| 394 | // The root node already exists. |
| 395 | return nullptr; |
| 396 | } else { |
| 397 | // Set the root node. |
| 398 | this->_pRoot = std::make_unique<AvailabilityNode>(); |
| 399 | return this->_pRoot.get(); |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | // We can't insert a new child node if the parent does not have a loaded |
| 404 | // subtree yet. |
| 405 | if (!pParentNode->subtree) { |
| 406 | return nullptr; |
| 407 | } |
| 408 | |
| 409 | // The tile must fall exactly after the parent subtree. |
| 410 | if ((tileID.level % this->_subtreeLevels) != 0) { |
| 411 | return nullptr; |
| 412 | } |
| 413 | |
| 414 | uint32_t subtreeRelativeMask = ~(0xFFFFFFFF << this->_subtreeLevels); |
| 415 | uint32_t mortonIndex = getMortonIndex( |
| 416 | tileID.x & subtreeRelativeMask, |
| 417 | tileID.y & subtreeRelativeMask, |
| 418 | tileID.z & subtreeRelativeMask); |
| 419 | |
| 420 | AvailabilityAccessor subtreeAvailabilityAccessor( |
| 421 | pParentNode->subtree->subtreeAvailability, |
| 422 | *pParentNode->subtree); |
| 423 | |
| 424 | bool subtreeAvailable = false; |
| 425 | uint32_t subtreeIndex = 0; |
| 426 | if (subtreeAvailabilityAccessor.isConstant()) { |
| 427 | subtreeAvailable = subtreeAvailabilityAccessor.getConstant(); |
| 428 | subtreeIndex = mortonIndex; |
| 429 | } else if (subtreeAvailabilityAccessor.isBufferView()) { |
| 430 | uint32_t byteIndex = mortonIndex >> 3; |
| 431 | uint8_t bitIndex = static_cast<uint8_t>(mortonIndex & 7); |
| 432 | uint8_t bitMask = static_cast<uint8_t>(1 << bitIndex); |
| 433 | |
| 434 | std::span<const std::byte> clippedSubtreeAvailability = |
| 435 | subtreeAvailabilityAccessor.getBufferAccessor().subspan(0, byteIndex); |
| 436 | uint8_t availabilityByte = (uint8_t)subtreeAvailabilityAccessor[byteIndex]; |
| 437 | |
| 438 | subtreeAvailable = availabilityByte & bitMask; |
| 439 | |
| 440 | // Calculte the index the child subtree is stored in. |
| 441 | if (subtreeAvailable) { |
| 442 | subtreeIndex = |
| 443 | // TODO: maybe partial sums should be precomputed in the subtree |
| 444 | // availability, instead of iterating through the buffer each time. |
| 445 | AvailabilityUtilities::countOnesInBuffer(clippedSubtreeAvailability) + |
no test coverage detected