Files
2026-06-14 19:09:18 +01:00

187 lines
10 KiB
C++

// -*- 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 <iterator>
#include "imagecodec.hpp"
class ImageSpan {
public:
template <typename PTR = uint8_t*>
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<uint32_t>(diff / slicePitch);
diff = diff % slicePitch;
loc.y = static_cast<uint32_t>(diff / rowPitch);
diff = diff % rowPitch;
loc.x = static_cast<uint32_t>(diff / blockPitch);
return loc;
}
glm::uvec4 getPixelLocation() const {
return getTexelBlockLocation() * span.imageCodec().getTexelBlockDimensions();
}
private:
PTR ptr;
const ImageSpan& span;
};
template <typename TBPTR = TexelBlockPtr<uint8_t*>, 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<uint8_t*>;
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
using reference = TexelBlockPtr<uint8_t*>;
using const_reference = TexelBlockPtr<const uint8_t*>;
using pointer = TexelBlockPtr<uint8_t*>;
using const_pointer = TexelBlockPtr<const uint8_t*>;
using iterator = Iterator<TexelBlockPtr<uint8_t*>, false>;
using const_iterator = Iterator<TexelBlockPtr<const uint8_t*>, false>;
using reverse_iterator = Iterator<TexelBlockPtr<uint8_t*>, true>;
using const_reverse_iterator = Iterator<TexelBlockPtr<const uint8_t*>, 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<uint8_t*>(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();
}
};