| 643 | /// @param toHalf if true, convert floating-point values to 16-bit half floats |
| 644 | template<typename ValueT, typename MaskT> |
| 645 | inline void |
| 646 | writeCompressedValues(std::ostream& os, const ValueT* srcBuf, Index srcCount, |
| 647 | const MaskT& valueMask, const MaskT& childMask, bool toHalf) |
| 648 | { |
| 649 | // Get the stream's compression settings. |
| 650 | const uint32_t compress = getDataCompression(os); |
| 651 | const bool maskCompress = compress & COMPRESS_ACTIVE_MASK; |
| 652 | |
| 653 | Index tempCount = srcCount; |
| 654 | ValueT* tempBuf = nullptr; |
| 655 | std::unique_ptr<ValueT[]> scopedTempBuf; |
| 656 | |
| 657 | int8_t metadata = NO_MASK_AND_ALL_VALS; |
| 658 | |
| 659 | if (!maskCompress) { |
| 660 | os.write(reinterpret_cast<const char*>(&metadata), /*bytes=*/1); |
| 661 | } else { |
| 662 | // A valid level set's inactive values are either +background (outside) |
| 663 | // or -background (inside), and a fog volume's inactive values are all zero. |
| 664 | // Rather than write out all of these values, we can store just the active values |
| 665 | // (given that the value mask specifies their positions) and, if necessary, |
| 666 | // an inside/outside bitmask. |
| 667 | |
| 668 | const ValueT zero = zeroVal<ValueT>(); |
| 669 | ValueT background = zero; |
| 670 | if (const void* bgPtr = getGridBackgroundValuePtr(os)) { |
| 671 | background = *static_cast<const ValueT*>(bgPtr); |
| 672 | } |
| 673 | |
| 674 | MaskCompress<ValueT, MaskT> maskCompressData(valueMask, childMask, srcBuf, background); |
| 675 | metadata = maskCompressData.metadata; |
| 676 | |
| 677 | os.write(reinterpret_cast<const char*>(&metadata), /*bytes=*/1); |
| 678 | |
| 679 | if (metadata == NO_MASK_AND_ONE_INACTIVE_VAL || |
| 680 | metadata == MASK_AND_ONE_INACTIVE_VAL || |
| 681 | metadata == MASK_AND_TWO_INACTIVE_VALS) |
| 682 | { |
| 683 | if (!toHalf) { |
| 684 | // Write one of at most two distinct inactive values. |
| 685 | os.write(reinterpret_cast<const char*>(&maskCompressData.inactiveVal[0]), sizeof(ValueT)); |
| 686 | if (metadata == MASK_AND_TWO_INACTIVE_VALS) { |
| 687 | // Write the second of two distinct inactive values. |
| 688 | os.write(reinterpret_cast<const char*>(&maskCompressData.inactiveVal[1]), sizeof(ValueT)); |
| 689 | } |
| 690 | } else { |
| 691 | // Write one of at most two distinct inactive values. |
| 692 | ValueT truncatedVal = static_cast<ValueT>(truncateRealToHalf(maskCompressData.inactiveVal[0])); |
| 693 | os.write(reinterpret_cast<const char*>(&truncatedVal), sizeof(ValueT)); |
| 694 | if (metadata == MASK_AND_TWO_INACTIVE_VALS) { |
| 695 | // Write the second of two distinct inactive values. |
| 696 | truncatedVal = truncateRealToHalf(maskCompressData.inactiveVal[1]); |
| 697 | os.write(reinterpret_cast<const char*>(&truncatedVal), sizeof(ValueT)); |
| 698 | } |
| 699 | } |
| 700 | } |
| 701 | |
| 702 | if (metadata == NO_MASK_AND_ALL_VALS) { |