From fa3fab4ca0e8a035d1533fce10ef89055dbea8ac Mon Sep 17 00:00:00 2001 From: drewcassidy Date: Thu, 1 Apr 2021 16:37:15 -0700 Subject: [PATCH] Block refactor --- quicktex/{Block.h => ColorBlock.h} | 37 +++++---------- quicktex/Decoder.h | 2 +- quicktex/Encoder.h | 2 +- quicktex/Texture.h | 2 +- quicktex/_bindings.h | 12 +++-- quicktex/s3tc/bc1/BC1Block.h | 28 ++++++------ quicktex/s3tc/bc1/BC1Decoder.cpp | 2 +- quicktex/s3tc/bc1/BC1Decoder.h | 2 +- quicktex/s3tc/bc1/BC1Encoder.cpp | 2 +- quicktex/s3tc/bc1/BC1Encoder.h | 2 +- quicktex/s3tc/bc1/_bindings.cpp | 23 +++++----- quicktex/s3tc/bc3/BC3Block.h | 20 +++++++-- quicktex/s3tc/bc3/BC3Decoder.cpp | 2 +- quicktex/s3tc/bc3/BC3Decoder.h | 2 +- quicktex/s3tc/bc3/BC3Encoder.cpp | 2 +- quicktex/s3tc/bc3/BC3Encoder.h | 2 +- quicktex/s3tc/bc3/_bindings.cpp | 18 +++++++- quicktex/s3tc/bc4/BC4Block.h | 72 +++++++++++++++++------------- quicktex/s3tc/bc4/BC4Decoder.cpp | 8 ++-- quicktex/s3tc/bc4/BC4Decoder.h | 2 +- quicktex/s3tc/bc4/BC4Encoder.cpp | 24 +++++----- quicktex/s3tc/bc4/BC4Encoder.h | 2 +- quicktex/s3tc/bc4/_bindings.cpp | 50 ++++++++++++++++++--- quicktex/s3tc/bc5/BC5Block.h | 19 ++++++-- quicktex/s3tc/bc5/BC5Decoder.cpp | 2 +- quicktex/s3tc/bc5/BC5Decoder.h | 2 +- quicktex/s3tc/bc5/BC5Encoder.cpp | 2 +- quicktex/s3tc/bc5/BC5Encoder.h | 2 +- 28 files changed, 207 insertions(+), 138 deletions(-) rename quicktex/{Block.h => ColorBlock.h} (74%) diff --git a/quicktex/Block.h b/quicktex/ColorBlock.h similarity index 74% rename from quicktex/Block.h rename to quicktex/ColorBlock.h index 4ff34b6..e2f178d 100644 --- a/quicktex/Block.h +++ b/quicktex/ColorBlock.h @@ -31,28 +31,8 @@ namespace quicktex { using Coords = std::tuple; -/** - * Base class for all compressed blocks - * - * IMPORTANT: this class cannot contain any virtual methods or the vtable would add to the derived class size, - * it is only to act as a base class for type checking reasons. As such, it has limited utility on its own. - * - * @tparam N Block width in pixels - * @tparam M Block height in pixels - */ -template class Block { - static_assert(N > 0); - static_assert(M > 0); - - public: - static constexpr int Width = N; - static constexpr int Height = M; - static constexpr Coords Dimensions = Coords(Width, Height); -}; - -template class ColorBlock : public Block { +template class ColorBlock { public: - using Base = Block; struct Metrics { Color min; Color max; @@ -62,9 +42,12 @@ template class ColorBlock : public Block { Vector4Int sums; }; + static constexpr int Width = N; + static constexpr int Height = M; + constexpr Color Get(int x, int y) const { - if (x >= Base::Width || x < 0) throw std::invalid_argument("x value out of range"); - if (y >= Base::Height || y < 0) throw std::invalid_argument("y value out of range"); + if (x >= Width || x < 0) throw std::invalid_argument("x value out of range"); + if (y >= Height || y < 0) throw std::invalid_argument("y value out of range"); return _pixels[x + (N * y)]; } @@ -75,8 +58,8 @@ template class ColorBlock : public Block { } void Set(int x, int y, const Color &value) { - if (x >= Base::Width || x < 0) throw std::invalid_argument("x value out of range"); - if (y >= Base::Height || y < 0) throw std::invalid_argument("y value out of range"); + if (x >= Width || x < 0) throw std::invalid_argument("x value out of range"); + if (y >= Height || y < 0) throw std::invalid_argument("y value out of range"); _pixels[x + (N * y)] = value; } @@ -86,12 +69,12 @@ template class ColorBlock : public Block { } void GetRow(int y, Color *dst) const { - if (y >= Base::Height || y < 0) throw std::invalid_argument("y value out of range"); + if (y >= Height || y < 0) throw std::invalid_argument("y value out of range"); std::memcpy(dst, &_pixels[N * y], N * sizeof(Color)); } void SetRow(int y, const Color *src) { - if (y >= Base::Height || y < 0) throw std::invalid_argument("y value out of range"); + if (y >= Height || y < 0) throw std::invalid_argument("y value out of range"); std::memcpy(&_pixels[N * y], src, N * sizeof(Color)); } diff --git a/quicktex/Decoder.h b/quicktex/Decoder.h index 258def4..47066a3 100644 --- a/quicktex/Decoder.h +++ b/quicktex/Decoder.h @@ -21,7 +21,7 @@ #include -#include "Block.h" +#include "ColorBlock.h" #include "Texture.h" namespace quicktex { diff --git a/quicktex/Encoder.h b/quicktex/Encoder.h index 21db329..8cd7ae1 100644 --- a/quicktex/Encoder.h +++ b/quicktex/Encoder.h @@ -21,7 +21,7 @@ #include -#include "Block.h" +#include "ColorBlock.h" #include "Texture.h" namespace quicktex { diff --git a/quicktex/Texture.h b/quicktex/Texture.h index efe406f..167d984 100644 --- a/quicktex/Texture.h +++ b/quicktex/Texture.h @@ -28,8 +28,8 @@ #include #include -#include "Block.h" #include "Color.h" +#include "ColorBlock.h" namespace quicktex { diff --git a/quicktex/_bindings.h b/quicktex/_bindings.h index bab7bea..0eff842 100644 --- a/quicktex/_bindings.h +++ b/quicktex/_bindings.h @@ -27,15 +27,11 @@ #include #include -#include "Block.h" #include "Color.h" +#include "ColorBlock.h" #include "Texture.h" #include "util.h" -/*namespace pybind11::detail { -extern template struct type_caster; -} // namespace pybind11::detail*/ - namespace pybind11::detail { using namespace quicktex; /// Type caster for color class to allow it to be converted to and from a python tuple @@ -189,8 +185,10 @@ template py::class_ BindBlock(py::module_& m, const char* name) block.def_readonly_static("width", &B::Width, "The width of the block in pixels."); block.def_readonly_static("height", &B::Height, "The height of the block in pixels."); - block.def_readonly_static("dimensions", &B::Dimensions, "The dimensions of the block in pixels."); - block.def_property_readonly_static("size", [](py::object) { return sizeof(B); }, "The size of the block in bytes."); + block.def_property_readonly_static( + "dimensions", [](py::object) { return std::make_tuple(B::Width, B::Height); }, "The dimensions of the block in pixels."); + block.def_property_readonly_static( + "size", [](py::object) { return sizeof(B); }, "The size of the block in bytes."); block.def_buffer([](B& b) { return py::buffer_info(reinterpret_cast(&b), sizeof(B)); }); block.def( diff --git a/quicktex/s3tc/bc1/BC1Block.h b/quicktex/s3tc/bc1/BC1Block.h index 228793b..19f53e9 100644 --- a/quicktex/s3tc/bc1/BC1Block.h +++ b/quicktex/s3tc/bc1/BC1Block.h @@ -24,19 +24,22 @@ #include #include -#include "../../Block.h" #include "../../Color.h" #include "../../util.h" namespace quicktex::s3tc { -#pragma pack(push, 1) -class BC1Block : public Block<4, 4> { +class alignas(8) BC1Block { public: + static constexpr int Width = 4; + static constexpr int Height = 4; + using SelectorArray = std::array, Height>; using ColorPair = std::tuple; constexpr BC1Block() { + static_assert(sizeof(BC1Block) == 8); + static_assert(sizeof(std::array) == 8 * 10); SetColor0Raw(0); SetColor1Raw(0); SetSelectorsSolid(0); @@ -80,12 +83,12 @@ class BC1Block : public Block<4, 4> { SelectorArray GetSelectors() const { SelectorArray unpacked; - for (unsigned i = 0; i < 4; i++) { unpacked[i] = Unpack(selectors[i]); } + for (int i = 0; i < Height; i++) { unpacked[i] = Unpack(_selectors[i]); } return unpacked; } - void SetSelectors(const SelectorArray& unpacked, uint8_t mask = 0) { - for (unsigned i = 0; i < 4; i++) { selectors[i] = mask ^ Pack(unpacked[i]); } + void SetSelectors(const SelectorArray& unpacked) { + for (int i = 0; i < Height; i++) { _selectors[i] = Pack(unpacked[i]); } } /** @@ -93,19 +96,16 @@ class BC1Block : public Block<4, 4> { * @param mask the 8-bit mask to use for each row */ void SetSelectorsSolid(uint8_t mask) { - for (unsigned i = 0; i < 4; i++) selectors[i] = mask; + for (int i = 0; i < Height; i++) _selectors[i] = mask; } - constexpr static inline size_t EndpointSize = 2; - constexpr static inline size_t SelectorSize = 4; - constexpr static inline uint8_t SelectorBits = 2; - constexpr static inline uint8_t SelectorValues = 1 << SelectorBits; - constexpr static inline uint8_t SelectorMask = SelectorValues - 1; + constexpr static inline size_t EndpointSize = 2; // in bytes + constexpr static inline size_t SelectorSize = 4; // in bytes + constexpr static inline uint8_t SelectorBits = 2; // in bits private: std::array _color_0; std::array _color_1; - std::array selectors; + std::array _selectors; }; -#pragma pack(pop) } // namespace quicktex::s3tc \ No newline at end of file diff --git a/quicktex/s3tc/bc1/BC1Decoder.cpp b/quicktex/s3tc/bc1/BC1Decoder.cpp index f84cacc..772ffd2 100644 --- a/quicktex/s3tc/bc1/BC1Decoder.cpp +++ b/quicktex/s3tc/bc1/BC1Decoder.cpp @@ -23,8 +23,8 @@ #include #include -#include "../../Block.h" #include "../../Color.h" +#include "../../ColorBlock.h" #include "BC1Block.h" namespace quicktex::s3tc { diff --git a/quicktex/s3tc/bc1/BC1Decoder.h b/quicktex/s3tc/bc1/BC1Decoder.h index 68a9463..7e72e1d 100644 --- a/quicktex/s3tc/bc1/BC1Decoder.h +++ b/quicktex/s3tc/bc1/BC1Decoder.h @@ -21,7 +21,7 @@ #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Decoder.h" #include "../../Texture.h" #include "../interpolator/Interpolator.h" diff --git a/quicktex/s3tc/bc1/BC1Encoder.cpp b/quicktex/s3tc/bc1/BC1Encoder.cpp index 98c723e..742ccde 100644 --- a/quicktex/s3tc/bc1/BC1Encoder.cpp +++ b/quicktex/s3tc/bc1/BC1Encoder.cpp @@ -29,8 +29,8 @@ #include #include -#include "../../Block.h" #include "../../Color.h" +#include "../../ColorBlock.h" #include "../../Matrix4x4.h" #include "../../Texture.h" #include "../../Vector4.h" diff --git a/quicktex/s3tc/bc1/BC1Encoder.h b/quicktex/s3tc/bc1/BC1Encoder.h index f7e7102..8c4e565 100644 --- a/quicktex/s3tc/bc1/BC1Encoder.h +++ b/quicktex/s3tc/bc1/BC1Encoder.h @@ -26,8 +26,8 @@ #include #include -#include "../../Block.h" #include "../../Color.h" +#include "../../ColorBlock.h" #include "../../Encoder.h" #include "../../Texture.h" #include "../interpolator/Interpolator.h" diff --git a/quicktex/s3tc/bc1/_bindings.cpp b/quicktex/s3tc/bc1/_bindings.cpp index 397cd6b..17ac3dc 100644 --- a/quicktex/s3tc/bc1/_bindings.cpp +++ b/quicktex/s3tc/bc1/_bindings.cpp @@ -54,7 +54,7 @@ void InitBC1(py::module_ &s3tc) { bc1_block.def(py::init<>()); bc1_block.def(py::init(), "color0"_a, "color1"_a, "selectors"_a, R"doc( - __init__(self, color0, color1) -> None + __init__(self, color0, color1, selectors: List[List[int]]) -> None Create a new BC1Block with the specified endpoints and selectors @@ -63,26 +63,29 @@ void InitBC1(py::module_ &s3tc) { :param selectors: the selectors as a 4x4 list of integers, between 0 and 3 inclusive. )doc"); - bc1_block.def_property("colors", &BC1Block::GetColors, &BC1Block::SetColors, "The block's endpoint colors as a 2-tuple."); + bc1_block.def_property("endpoints", &BC1Block::GetColors, &BC1Block::SetColors, "The block's endpoint colors as a 2-tuple."); bc1_block.def_property("selectors", &BC1Block::GetSelectors, &BC1Block::SetSelectors, R"doc( The block's selectors as a 4x4 list of integers between 0 and 3 inclusive. .. note:: This is a property, so directly modifying its value will not propogate back to the block. - Instead you must read, modify, then write the new value back to the property, like so:: + Instead you must read, modify, then write the new list back to the property, like so:: selectors = block.selectors selectors[0,0] = 0 block.selectors = selectors )doc"); + bc1_block.def_property_readonly("is_3color", &BC1Block::Is3Color, R"doc( + "True if the block uses 3-color interpolation, i.e. color0 <= color1. This value should be ignored when decoding as part of a BC3 block. Readonly. + )doc"); // endregion - //region BC1Texture + // region BC1Texture auto bc1_texture = BindBlockTexture(bc1, "BC1Texture"); bc1_texture.doc() = "A texture comprised of BC1 blocks."; - //endregion + // endregion - //region BC1Encoder + // region BC1Encoder py::class_ bc1_encoder(bc1, "BC1Encoder", "Encodes RGB textures to BC1."); py::enum_(bc1_encoder, "EndpointMode", "Enum representing various methods of finding endpoints in a block.") @@ -162,12 +165,10 @@ void InitBC1(py::module_ &s3tc) { bc1_encoder.def_property("power_iterations", &BC1Encoder::GetPowerIterations, &BC1Encoder::SetPowerIterations, "Number of power iterations used with the PCA endpoint mode. Value should be around 4 to 6. " "Automatically clamped to between :py:const:`BC1Encoder.min_power_iterations` and :py:const:`BC1Encoder.max_power_iterations`"); - //endregion + // endregion - //region BC1Decoder + // region BC1Decoder py::class_ bc1_decoder(bc1, "BC1Decoder", R"doc( - Base: :py:class:`~quicktex.BlockDecoder` - Decodes BC1 textures to RGB )doc"); @@ -183,6 +184,6 @@ void InitBC1(py::module_ &s3tc) { bc1_decoder.def_property_readonly("interpolator", &BC1Decoder::GetInterpolator, "The interpolator used by this decoder. This is a readonly property."); bc1_decoder.def_readwrite("write_alpha", &BC1Decoder::write_alpha, "Determines if the alpha channel of the output is written to."); - //endregion + // endregion } } // namespace quicktex::bindings \ No newline at end of file diff --git a/quicktex/s3tc/bc3/BC3Block.h b/quicktex/s3tc/bc3/BC3Block.h index 7f741e6..e4be502 100644 --- a/quicktex/s3tc/bc3/BC3Block.h +++ b/quicktex/s3tc/bc3/BC3Block.h @@ -19,17 +19,29 @@ #pragma once -#include "../../Block.h" #include "../bc1/BC1Block.h" #include "../bc4/BC4Block.h" namespace quicktex::s3tc { -#pragma pack(push, 1) -class BC3Block : public Block<4, 4> { +class alignas(8) BC3Block { public: + static constexpr int Width = 4; + static constexpr int Height = 4; + + constexpr BC3Block() { + static_assert(sizeof(BC3Block) == 16); + static_assert(sizeof(std::array) == 16 * 10); + alpha_block = BC4Block(); + color_block = BC1Block(); + } + + constexpr BC3Block(const BC4Block &alpha, const BC1Block &color) { + alpha_block = alpha; + color_block = color; + } + BC4Block alpha_block; BC1Block color_block; }; -#pragma pack(pop) } // namespace quicktex::s3tc \ No newline at end of file diff --git a/quicktex/s3tc/bc3/BC3Decoder.cpp b/quicktex/s3tc/bc3/BC3Decoder.cpp index dbeac80..6dc8e63 100644 --- a/quicktex/s3tc/bc3/BC3Decoder.cpp +++ b/quicktex/s3tc/bc3/BC3Decoder.cpp @@ -19,7 +19,7 @@ #include "BC3Decoder.h" -#include "../../Block.h" +#include "../../ColorBlock.h" #include "BC3Block.h" namespace quicktex::s3tc { diff --git a/quicktex/s3tc/bc3/BC3Decoder.h b/quicktex/s3tc/bc3/BC3Decoder.h index 66f1c2f..c72de41 100644 --- a/quicktex/s3tc/bc3/BC3Decoder.h +++ b/quicktex/s3tc/bc3/BC3Decoder.h @@ -21,7 +21,7 @@ #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Decoder.h" #include "../../Texture.h" #include "../bc1/BC1Decoder.h" diff --git a/quicktex/s3tc/bc3/BC3Encoder.cpp b/quicktex/s3tc/bc3/BC3Encoder.cpp index 0e13b58..4fdddfd 100644 --- a/quicktex/s3tc/bc3/BC3Encoder.cpp +++ b/quicktex/s3tc/bc3/BC3Encoder.cpp @@ -19,7 +19,7 @@ #include "BC3Encoder.h" -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../bc1/BC1Block.h" #include "../bc4/BC4Block.h" #include "BC3Block.h" diff --git a/quicktex/s3tc/bc3/BC3Encoder.h b/quicktex/s3tc/bc3/BC3Encoder.h index f26d979..98fe648 100644 --- a/quicktex/s3tc/bc3/BC3Encoder.h +++ b/quicktex/s3tc/bc3/BC3Encoder.h @@ -21,7 +21,7 @@ #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Encoder.h" #include "../../Texture.h" #include "../bc1/BC1Encoder.h" diff --git a/quicktex/s3tc/bc3/_bindings.cpp b/quicktex/s3tc/bc3/_bindings.cpp index 6c45c75..dff8a4d 100644 --- a/quicktex/s3tc/bc3/_bindings.cpp +++ b/quicktex/s3tc/bc3/_bindings.cpp @@ -17,6 +17,8 @@ along with this program. If not, see . */ +#include "../../_bindings.h" + #include #include @@ -45,7 +47,17 @@ void InitBC3(py::module_ &s3tc) { py::options options; options.disable_function_signatures(); - // BC3Encoder + // region BC3Block + auto bc3_block = BindBlock(bc3, "BC3Block"); + bc3_block.def(py::init<>()); + bc3_block.def(py::init(), "alpha_block"_a, "color_block"_a); + + bc3_block.def_readwrite("alpha_block", &BC3Block::alpha_block); + bc3_block.def_readwrite("color_block", &BC3Block::color_block); + + // endregion + + // region BC3Encoder py::class_ bc3_encoder(bc3, "BC3Encoder", R"doc( Base: :py:class:`~quicktex.BlockEncoder` @@ -67,8 +79,9 @@ void InitBC3(py::module_ &s3tc) { "Internal :py:class:`~quicktex.s3tc.bc1.BC1Encoder` used for RGB data. Readonly."); bc3_encoder.def_property_readonly("bc4_encoder", &BC3Encoder::GetBC4Encoder, "Internal :py:class:`~quicktex.s3tc.bc4.BC4Encoder` used for alpha data. Readonly."); + // endregion - // BC3Decoder + // region BC3Decoder py::class_ bc3_decoder(bc3, "BC3Decoder", R"doc( Base: :py:class:`~quicktex.BlockDecoder` @@ -88,5 +101,6 @@ void InitBC3(py::module_ &s3tc) { "Internal :py:class:`~quicktex.s3tc.bc1.BC1Decoder` used for RGB data. Readonly."); bc3_decoder.def_property_readonly("bc4_decoder", &BC3Decoder::GetBC4Decoder, "Internal :py:class:`~quicktex.s3tc.bc4.BC4Decoder` used for alpha data. Readonly."); + // endregion }; } // namespace quicktex::bindings \ No newline at end of file diff --git a/quicktex/s3tc/bc4/BC4Block.h b/quicktex/s3tc/bc4/BC4Block.h index 49defbf..c589232 100644 --- a/quicktex/s3tc/bc4/BC4Block.h +++ b/quicktex/s3tc/bc4/BC4Block.h @@ -30,54 +30,65 @@ namespace quicktex::s3tc { -#pragma pack(push, 1) -class BC4Block : public Block<4, 4> { +class alignas(8) BC4Block { public: - using UnpackedSelectors = std::array, 4>; + static constexpr int Width = 4; + static constexpr int Height = 4; - inline uint32_t GetLowAlpha() const { return low_alpha; } - inline uint32_t GetHighAlpha() const { return high_alpha; } - inline bool Is6Alpha() const { return GetLowAlpha() <= GetHighAlpha(); } + using SelectorArray = std::array, Height>; + using AlphaPair = std::pair; + + constexpr BC4Block() { + static_assert(sizeof(BC4Block) == 8); + static_assert(sizeof(std::array) == 8 * 10); + alpha0 = alpha1 = 0; + SetSelectorBits(0); + } + + constexpr BC4Block(uint8_t valpha0, uint8_t valpha1, const SelectorArray& selectors) { + alpha0 = valpha0; + alpha1 = valpha1; + SetSelectors(selectors); + } + + inline bool Is6Value() const { return alpha0 <= alpha1; } + + AlphaPair GetAlphas() const { return AlphaPair(alpha0, alpha1); } + + void SetAlphas(AlphaPair as) { + alpha0 = as.first; + alpha1 = as.second; + } inline uint64_t GetSelectorBits() const { - auto packed = Pack(selectors); + auto packed = Pack(selectors); assert(packed <= SelectorBitsMax); return packed; } void SetSelectorBits(uint64_t packed) { assert(packed <= SelectorBitsMax); - selectors = Unpack(packed); + selectors = Unpack(packed); } - UnpackedSelectors UnpackSelectors() const { - UnpackedSelectors unpacked; - auto rows = Unpack(GetSelectorBits()); - for (unsigned i = 0; i < 4; i++) { - auto row = Unpack(rows[i]); + SelectorArray GetSelectors() const { + SelectorArray unpacked; + auto rows = Unpack(GetSelectorBits()); + for (unsigned i = 0; i < Height; i++) { + auto row = Unpack(rows[i]); unpacked[i] = row; } return unpacked; } - void PackSelectors(const UnpackedSelectors& unpacked) { - std::array rows; - for (unsigned i = 0; i < 4; i++) { rows[i] = Pack(unpacked[i]); } - auto packed = Pack(rows); - SetSelectorBits(packed); - } - - void PackSelectors(const std::array& unpacked) { - auto packed = Pack(unpacked); + void SetSelectors(const SelectorArray& unpacked) { + std::array rows; + for (int i = 0; i < Height; i++) { rows[i] = Pack(unpacked[i]); } + auto packed = Pack(rows); SetSelectorBits(packed); } - inline uint32_t GetSelector(uint32_t x, uint32_t y, uint64_t selector_bits) const { - assert((x < 4U) && (y < 4U)); - return (selector_bits >> (((y * 4) + x) * SelectorBits)) & (SelectorMask); - } - static inline std::array GetValues6(uint32_t l, uint32_t h) { return {static_cast(l), static_cast(h), @@ -114,9 +125,10 @@ class BC4Block : public Block<4, 4> { constexpr static inline uint8_t SelectorMask = SelectorValues - 1; constexpr static inline uint64_t SelectorBitsMax = (1ULL << (8U * SelectorSize)) - 1U; - uint8_t low_alpha; - uint8_t high_alpha; + uint8_t alpha0; + uint8_t alpha1; + + private: std::array selectors; }; -#pragma pack(pop) } // namespace quicktex::s3tc diff --git a/quicktex/s3tc/bc4/BC4Decoder.cpp b/quicktex/s3tc/bc4/BC4Decoder.cpp index bf615d5..67e8312 100644 --- a/quicktex/s3tc/bc4/BC4Decoder.cpp +++ b/quicktex/s3tc/bc4/BC4Decoder.cpp @@ -22,17 +22,17 @@ #include // for array #include // for assert -#include "../../Block.h" #include "../../Color.h" +#include "../../ColorBlock.h" #include "BC4Block.h" namespace quicktex::s3tc { void BC4Decoder::DecodeInto(ColorBlock<4, 4> &dest, const BC4Block &block) const { - auto l = block.GetLowAlpha(); - auto h = block.GetHighAlpha(); + auto l = block.alpha0; + auto h = block.alpha1; auto values = BC4Block::GetValues(l, h); - auto selectors = block.UnpackSelectors(); + auto selectors = block.GetSelectors(); for (unsigned y = 0; y < 4; y++) { for (unsigned x = 0; x < 4; x++) { diff --git a/quicktex/s3tc/bc4/BC4Decoder.h b/quicktex/s3tc/bc4/BC4Decoder.h index 32ff501..6e815aa 100644 --- a/quicktex/s3tc/bc4/BC4Decoder.h +++ b/quicktex/s3tc/bc4/BC4Decoder.h @@ -22,7 +22,7 @@ #include #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Decoder.h" #include "../../Texture.h" #include "BC4Block.h" diff --git a/quicktex/s3tc/bc4/BC4Encoder.cpp b/quicktex/s3tc/bc4/BC4Encoder.cpp index 29b533a..af45921 100644 --- a/quicktex/s3tc/bc4/BC4Encoder.cpp +++ b/quicktex/s3tc/bc4/BC4Encoder.cpp @@ -24,7 +24,7 @@ #include #include "../../Color.h" -#include "../../Block.h" +#include "../../ColorBlock.h" #include "BC4Block.h" namespace quicktex::s3tc { @@ -40,15 +40,15 @@ BC4Block BC4Encoder::EncodeBlock(const ColorBlock<4, 4> &pixels) const { max = std::max(max, value); } - output.high_alpha = min; - output.low_alpha = max; + output.alpha1 = min; + output.alpha0 = max; if (max == min) { output.SetSelectorBits(0); return output; } - std::array selectors = {}; + auto selectors = BC4Block::SelectorArray(); const static std::array Levels = {1U, 7U, 6U, 5U, 4U, 3U, 2U, 0U}; // selector value options in linear order // BC4 floors in its divisions, which we compensate for with the 4 bias. @@ -62,17 +62,19 @@ BC4Block BC4Encoder::EncodeBlock(const ColorBlock<4, 4> &pixels) const { for (unsigned i = 0; i < 7; i++) thresholds[i] = delta * (1 + (2 * (int)i)) - bias; // iterate over all values and calculate selectors - for (int i = 0; i < 16; i++) { - int value = (int)pixels.Get(i)[_channel] * 14; // multiply by demonimator + for (int y = 0; y < 4; y++) { + for (int x = 0; x < 4; x++) { + int value = (int)pixels.Get(x, y)[_channel] * 14; // multiply by demonimator - // level = number of thresholds this value is greater than - unsigned level = 0; - for (unsigned c = 0; c < 7; c++) level += value >= thresholds[c]; + // level = number of thresholds this value is greater than + unsigned level = 0; + for (unsigned c = 0; c < 7; c++) level += value >= thresholds[c]; - selectors[(unsigned)i] = Levels[level]; + selectors[(unsigned)y][(unsigned)x] = Levels[level]; + } } - output.PackSelectors(selectors); + output.SetSelectors(selectors); return output; } diff --git a/quicktex/s3tc/bc4/BC4Encoder.h b/quicktex/s3tc/bc4/BC4Encoder.h index 989691e..5ab87c2 100644 --- a/quicktex/s3tc/bc4/BC4Encoder.h +++ b/quicktex/s3tc/bc4/BC4Encoder.h @@ -22,7 +22,7 @@ #include #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Encoder.h" #include "../../Texture.h" #include "BC4Block.h" diff --git a/quicktex/s3tc/bc4/_bindings.cpp b/quicktex/s3tc/bc4/_bindings.cpp index 5314111..3c39dd8 100644 --- a/quicktex/s3tc/bc4/_bindings.cpp +++ b/quicktex/s3tc/bc4/_bindings.cpp @@ -17,6 +17,8 @@ along with this program. If not, see . */ +#include "../../_bindings.h" + #include #include @@ -33,7 +35,6 @@ namespace py = pybind11; namespace quicktex::bindings { -using namespace quicktex::s3tc; using namespace quicktex::s3tc; void InitBC4(py::module_ &s3tc) { @@ -41,10 +42,45 @@ void InitBC4(py::module_ &s3tc) { py::options options; options.disable_function_signatures(); - // BC4Encoder - py::class_ bc4_encoder(bc4, "BC4Encoder", R"doc( - Base: :py:class:`~quicktex.BlockEncoder` + // region BC4Block + auto bc4_block = BindBlock(bc4, "BC4Block"); + bc4_block.doc() = "A single BC4 block."; + + bc4_block.def(py::init<>()); + bc4_block.def(py::init(), "endpoint0"_a, "endpoint1"_a, "selectors"_a, R"doc( + __init__(self, endpoint0: int, endpoint1: int, selectors: List[List[int]]) -> None + + Create a new BC4Block with the specified endpoints and selectors. + + :param int endpoint0: The first endpoint. + :param int endpoint1: The second endpoint. + :param selectors: the selectors as a 4x4 list of integers, between 0 and 7 inclusive. + )doc"); + bc4_block.def_property("endpoints", &BC4Block::GetAlphas, &BC4Block::SetAlphas, "The block's endpoint values as a 2-tuple."); + bc4_block.def_property("selectors", &BC4Block::GetSelectors, &BC4Block::SetSelectors, R"doc( + The block's selectors as a 4x4 list of integers between 0 and 7 inclusive. + + .. note:: + This is a property, so directly modifying its value will not propogate back to the block. + Instead you must read, modify, then write the new list back to the property, like so:: + + selectors = block.selectors + selectors[0,0] = 0 + block.selectors = selectors + )doc"); + bc4_block.def_property_readonly("is_6value", &BC4Block::Is6Value, R"doc( + "True if the block uses 6-value interpolation, i.e. endpoint0 <= endpoint1. Readonly. + )doc"); + // endregion + + // region BC4Texture + auto bc4_texture = BindBlockTexture(bc4, "BC4Texture"); + bc4_texture.doc() = "A texture comprised of BC4 blocks."; + // endregion + + // region BC4Encoder + py::class_ bc4_encoder(bc4, "BC4Encoder", R"doc( Encodes single-channel textures to BC4. )doc"); @@ -56,11 +92,10 @@ void InitBC4(py::module_ &s3tc) { :param int channel: the channel that will be read from. 0 to 3 inclusive. Default: 3 (alpha). )doc"); bc4_encoder.def_property_readonly("channel", &BC4Encoder::GetChannel, "The channel that will be read from. 0 to 3 inclusive. Readonly."); + // endregion - // BC4Decoder + // region BC4Decoder py::class_ bc4_decoder(bc4, "BC4Decoder", R"doc( - Base: :py:class:`~quicktex.BlockDecoder` - Decodes BC4 textures to a single-channel. )doc"); @@ -72,6 +107,7 @@ void InitBC4(py::module_ &s3tc) { :param int channel: The channel that will be written to. 0 to 3 inclusive. Default: 3 (alpha). )doc"); bc4_decoder.def_property_readonly("channel", &BC4Decoder::GetChannel, "The channel that will be written to. 0 to 3 inclusive. Readonly."); + // endregion } } // namespace quicktex::bindings \ No newline at end of file diff --git a/quicktex/s3tc/bc5/BC5Block.h b/quicktex/s3tc/bc5/BC5Block.h index 6e51901..c350194 100644 --- a/quicktex/s3tc/bc5/BC5Block.h +++ b/quicktex/s3tc/bc5/BC5Block.h @@ -19,16 +19,27 @@ #pragma once -#include "../../Block.h" #include "../bc4/BC4Block.h" namespace quicktex::s3tc { -#pragma pack(push, 1) -class BC5Block : public Block<4, 4> { +class alignas(8) BC5Block { public: + static constexpr int Width = 4; + static constexpr int Height = 4; + + constexpr BC5Block() { + static_assert(sizeof(BC5Block) == 16); + static_assert(sizeof(std::array) == 16 * 10); + chan0_block = chan1_block = BC4Block(); + } + + constexpr BC5Block(const BC4Block &chan0, const BC4Block &chan1) { + chan0_block = chan0; + chan1_block = chan1; + } + BC4Block chan0_block; BC4Block chan1_block; }; -#pragma pack(pop) } // namespace quicktex::s3tc \ No newline at end of file diff --git a/quicktex/s3tc/bc5/BC5Decoder.cpp b/quicktex/s3tc/bc5/BC5Decoder.cpp index 0a45aef..1ebb103 100644 --- a/quicktex/s3tc/bc5/BC5Decoder.cpp +++ b/quicktex/s3tc/bc5/BC5Decoder.cpp @@ -19,7 +19,7 @@ #include "BC5Decoder.h" -#include "../../Block.h" +#include "../../ColorBlock.h" #include "BC5Block.h" namespace quicktex::s3tc { diff --git a/quicktex/s3tc/bc5/BC5Decoder.h b/quicktex/s3tc/bc5/BC5Decoder.h index 992457b..4c6599a 100644 --- a/quicktex/s3tc/bc5/BC5Decoder.h +++ b/quicktex/s3tc/bc5/BC5Decoder.h @@ -24,7 +24,7 @@ #include #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Decoder.h" #include "../../Texture.h" #include "../bc4/BC4Decoder.h" diff --git a/quicktex/s3tc/bc5/BC5Encoder.cpp b/quicktex/s3tc/bc5/BC5Encoder.cpp index 20742c4..0c96247 100644 --- a/quicktex/s3tc/bc5/BC5Encoder.cpp +++ b/quicktex/s3tc/bc5/BC5Encoder.cpp @@ -19,7 +19,7 @@ #include "BC5Encoder.h" -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../bc4/BC4Block.h" namespace quicktex::s3tc { diff --git a/quicktex/s3tc/bc5/BC5Encoder.h b/quicktex/s3tc/bc5/BC5Encoder.h index 95bbfb3..c0c027d 100644 --- a/quicktex/s3tc/bc5/BC5Encoder.h +++ b/quicktex/s3tc/bc5/BC5Encoder.h @@ -24,7 +24,7 @@ #include #include -#include "../../Block.h" +#include "../../ColorBlock.h" #include "../../Encoder.h" #include "../../Texture.h" #include "../bc4/BC4Encoder.h"