// -*- tab-width: 4; -*- // vi: set sw=2 ts=4 expandtab: // Copyright 2023-2024 The Khronos Group Inc. // Copyright 2023-2024 RasterGrid Kft. // SPDX-License-Identifier: Apache-2.0 //! //! @internal //! @~English //! @file //! //! @brief Internal Image Span container and iterator classes //! #pragma once #include #include "imagecodec.hpp" class ImageSpan { public: template class TexelBlockPtr { public: using pointer = PTR; TexelBlockPtr(PTR ptr, const ImageSpan& span) noexcept : ptr(ptr), span(span) {} uint32_t getPackedElement(uint32_t index) const { return span.imageCodec().getPackedElement(ptr, index); } glm::uvec4 decodeUINT() const { return span.imageCodec().decodeUINT(ptr); } glm::ivec4 decodeSINT() const { return span.imageCodec().decodeSINT(ptr); } glm::vec4 decodeFLOAT() const { return span.imageCodec().decodeFLOAT(ptr); } const ImageCodec& imageCodec() const { return span.codec; } constexpr bool isBlockCompressed() const { return span.imageCodec().isBlockCompressed(); } constexpr bool isPacked() const { return span.imageCodec().isPacked(); } constexpr bool isFloat() const { return span.imageCodec().isFloat(); } constexpr bool isFloatHalf() const { return span.imageCodec().isFloatHalf(); } constexpr bool isSigned() const { return span.imageCodec().isSigned(); } constexpr bool isNormalized() const { return span.imageCodec().isNormalized(); } constexpr bool canDecodeUINT() const { return span.imageCodec().canDecodeUINT(); } constexpr bool canDecodeSINT() const { return span.imageCodec().canDecodeSINT(); } constexpr bool canDecodeFLOAT() const { return span.imageCodec().canDecodeFLOAT(); } glm::uvec4 getTexelBlockDimensions() const { return span.imageCodec().getTexelBlockDimensions(); } constexpr uint32_t getPackedElementByteSize() const { return span.imageCodec().getPackedElementByteSize(); } constexpr uint32_t getPackedElementCount() const { return span.imageCodec().getPackedElementCount(); } constexpr uint32_t getTexelBlockByteSize() const { return span.imageCodec().getTexelBlockByteSize(); } constexpr uint32_t getChannelCount() const { return span.imageCodec().getChannelCount(); } std::ptrdiff_t getTexelBlockByteOffset() const { return ptr - span.data(); } glm::uvec4 getTexelBlockLocation() const { const std::ptrdiff_t blockPitch = span.imageCodec().getTexelBlockByteSize(); const std::ptrdiff_t rowPitch = span.getTexelBlockWidth() * blockPitch; const std::ptrdiff_t slicePitch = span.getTexelBlockHeight() * rowPitch; glm::uvec4 loc; auto diff = getTexelBlockByteOffset(); loc.w = 0; loc.z = static_cast(diff / slicePitch); diff = diff % slicePitch; loc.y = static_cast(diff / rowPitch); diff = diff % rowPitch; loc.x = static_cast(diff / blockPitch); return loc; } glm::uvec4 getPixelLocation() const { return getTexelBlockLocation() * span.imageCodec().getTexelBlockDimensions(); } private: PTR ptr; const ImageSpan& span; }; template , bool REVERSE = false> class Iterator { public: using iterator_category = std::random_access_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = TBPTR; using pointer = TBPTR; using reference = TBPTR; Iterator& operator+=(difference_type rhs) noexcept { ptr = advance(rhs); return *this; } Iterator& operator-=(difference_type rhs) noexcept { ptr = advance(-rhs); return *this; } reference operator*() const { return reference(ptr, span); } pointer operator->() const { return pointer(ptr, span); } reference operator[](difference_type rhs) const { return *advance(rhs); } Iterator& operator++() noexcept { ptr = advance(1); return *this; } Iterator& operator--() noexcept { ptr = advance(-1); return *this; } Iterator operator++(int) const noexcept { return Iterator(span, advance(1), stride); } Iterator operator--(int) const noexcept { return Iterator(span, advance(-1), stride); } difference_type operator-(const Iterator& rhs) const noexcept { return diff(rhs.ptr); } Iterator operator+(difference_type rhs) const noexcept { return Iterator(span, advance(rhs), stride); } Iterator operator-(difference_type rhs) const noexcept { return Iterator(span, advance(-rhs), stride); } friend Iterator operator+(difference_type lhs, const Iterator& rhs) { return Iterator(rhs.span, rhs.advance(lhs), rhs.stride); } friend Iterator operator-(difference_type lhs, const Iterator& rhs) { return Iterator(rhs.span, rhs.advance(-lhs), rhs.stride); } bool operator==(const Iterator& rhs) const noexcept { return (ptr == rhs.ptr) != REVERSE; } bool operator!=(const Iterator& rhs) const noexcept { return (ptr != rhs.ptr) != REVERSE; } bool operator>(const Iterator& rhs) const noexcept { return (ptr > rhs.ptr) != REVERSE; } bool operator<(const Iterator& rhs) const noexcept { return (ptr < rhs.ptr) != REVERSE; } bool operator>=(const Iterator& rhs) const noexcept { return (ptr >= rhs.ptr) != REVERSE; } bool operator<=(const Iterator& rhs) const noexcept { return (ptr <= rhs.ptr) != REVERSE; } private: const ImageSpan& span; typename TBPTR::pointer ptr; const uint32_t stride; Iterator(const ImageSpan& span, typename TBPTR::pointer ptr, uint32_t stride) noexcept : span(span), ptr(ptr), stride(stride) {} typename TBPTR::pointer advance(difference_type diff) const noexcept { return ptr + (REVERSE ? -1 : +1) * diff * stride; } difference_type diff(pointer other) const noexcept { return (REVERSE ? -1 : +1) * (ptr - other) / stride; } friend class ImageSpan; }; using value_type = TexelBlockPtr; using size_type = std::size_t; using difference_type = std::ptrdiff_t; using reference = TexelBlockPtr; using const_reference = TexelBlockPtr; using pointer = TexelBlockPtr; using const_pointer = TexelBlockPtr; using iterator = Iterator, false>; using const_iterator = Iterator, false>; using reverse_iterator = Iterator, true>; using const_reverse_iterator = Iterator, true>; ImageSpan(uint32_t width, uint32_t height, uint32_t depth, void* pixels, const ImageCodec& imageCodec) : texelBlockWidth((width + imageCodec.getTexelBlockDimensions()[0] - 1) / imageCodec.getTexelBlockDimensions()[0]), texelBlockHeight((height + imageCodec.getTexelBlockDimensions()[1] - 1) / imageCodec.getTexelBlockDimensions()[1]), texelBlockDepth((depth + imageCodec.getTexelBlockDimensions()[2] - 1) / imageCodec.getTexelBlockDimensions()[2]), pixels(reinterpret_cast(pixels)), codec(imageCodec) {} const ImageCodec& imageCodec() const { return codec; } reference at(uint32_t blockX, uint32_t blockY, uint32_t blockZ) { return reference(pixels + texelBlockByteOffset(blockX, blockY, blockZ), *this); } const_reference at(uint32_t blockX, uint32_t blockY, uint32_t blockZ) const { return const_reference(pixels + texelBlockByteOffset(blockX, blockY, blockZ), *this); } iterator begin() noexcept { return iterator(*this, pixels, codec.getTexelBlockByteSize()); } const_iterator begin() const noexcept { return const_iterator(*this, pixels, codec.getTexelBlockByteSize()); } const_iterator cbegin() const noexcept { return const_iterator(*this, pixels, codec.getTexelBlockByteSize()); } iterator end() noexcept { return iterator(*this, pixels, codec.getTexelBlockByteSize()) + size(); } const_iterator end() const noexcept { return const_iterator(*this, pixels, codec.getTexelBlockByteSize()) + size(); } const_iterator cend() const noexcept { return const_iterator(*this, pixels, codec.getTexelBlockByteSize()) + size(); } reverse_iterator rbegin() noexcept { return reverse_iterator(*this, pixels, codec.getTexelBlockByteSize()) - size() + 1; } const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(*this, pixels, codec.getTexelBlockByteSize()) - size() + 1; } const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(*this, pixels, codec.getTexelBlockByteSize()) - size() + 1; } reverse_iterator rend() noexcept { return reverse_iterator(*this, pixels , codec.getTexelBlockByteSize()) + 1; } const_reverse_iterator rend() const noexcept { return const_reverse_iterator(*this, pixels, codec.getTexelBlockByteSize()) + 1; } const_reverse_iterator crend() const noexcept { return const_reverse_iterator(*this, pixels, codec.getTexelBlockByteSize()) + 1; } uint8_t* data() noexcept { return pixels; } const uint8_t* data() const noexcept { return pixels; } constexpr size_type size() const noexcept { return texelBlockWidth * texelBlockHeight; } constexpr std::ptrdiff_t byteSize() const { return size() * codec.getTexelBlockByteSize(); } constexpr uint32_t getTexelBlockWidth() const { return texelBlockWidth; } constexpr uint32_t getTexelBlockHeight() const { return texelBlockHeight; } constexpr uint32_t getTexelBlockDepth() const { return texelBlockDepth; } private: const uint32_t texelBlockWidth; const uint32_t texelBlockHeight; const uint32_t texelBlockDepth; uint8_t* const pixels; const ImageCodec& codec; constexpr std::ptrdiff_t texelBlockByteOffset(uint32_t blockX, uint32_t blockY, uint32_t blockZ) const { return (blockX + blockY * texelBlockWidth + blockZ * texelBlockWidth * texelBlockHeight) * codec.getTexelBlockByteSize(); } };