Block refactor

hotfix/mipmap-alpha-fix
Andrew Cassidy 3 years ago
parent 3852da6249
commit fa3fab4ca0

@ -31,28 +31,8 @@
namespace quicktex {
using Coords = std::tuple<int, int>;
/**
* 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 <int N, int M> 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 <int N, int M> class ColorBlock : public Block<N, M> {
template <int N, int M> class ColorBlock {
public:
using Base = Block<N, M>;
struct Metrics {
Color min;
Color max;
@ -62,9 +42,12 @@ template <int N, int M> class ColorBlock : public Block<N, M> {
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 <int N, int M> class ColorBlock : public Block<N, M> {
}
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 <int N, int M> class ColorBlock : public Block<N, M> {
}
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));
}

@ -21,7 +21,7 @@
#include <memory>
#include "Block.h"
#include "ColorBlock.h"
#include "Texture.h"
namespace quicktex {

@ -21,7 +21,7 @@
#include <memory>
#include "Block.h"
#include "ColorBlock.h"
#include "Texture.h"
namespace quicktex {

@ -28,8 +28,8 @@
#include <tuple>
#include <type_traits>
#include "Block.h"
#include "Color.h"
#include "ColorBlock.h"
namespace quicktex {

@ -27,15 +27,11 @@
#include <stdexcept>
#include <type_traits>
#include "Block.h"
#include "Color.h"
#include "ColorBlock.h"
#include "Texture.h"
#include "util.h"
/*namespace pybind11::detail {
extern template struct type_caster<quicktex::Color>;
} // 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 <typename B> py::class_<B> 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<uint8_t*>(&b), sizeof(B)); });
block.def(

@ -24,19 +24,22 @@
#include <cstdint>
#include <cstdlib>
#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<std::array<uint8_t, Width>, Height>;
using ColorPair = std::tuple<Color, Color>;
constexpr BC1Block() {
static_assert(sizeof(BC1Block) == 8);
static_assert(sizeof(std::array<BC1Block, 10>) == 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<uint8_t, uint8_t, 2, 4>(selectors[i]); }
for (int i = 0; i < Height; i++) { unpacked[i] = Unpack<uint8_t, uint8_t, SelectorBits, Width>(_selectors[i]); }
return unpacked;
}
void SetSelectors(const SelectorArray& unpacked, uint8_t mask = 0) {
for (unsigned i = 0; i < 4; i++) { selectors[i] = mask ^ Pack<uint8_t, uint8_t, 2, 4>(unpacked[i]); }
void SetSelectors(const SelectorArray& unpacked) {
for (int i = 0; i < Height; i++) { _selectors[i] = Pack<uint8_t, uint8_t, SelectorBits, Width>(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<uint8_t, EndpointSize> _color_0;
std::array<uint8_t, EndpointSize> _color_1;
std::array<uint8_t, 4> selectors;
std::array<uint8_t, SelectorSize> _selectors;
};
#pragma pack(pop)
} // namespace quicktex::s3tc

@ -23,8 +23,8 @@
#include <cassert>
#include <cstdint>
#include "../../Block.h"
#include "../../Color.h"
#include "../../ColorBlock.h"
#include "BC1Block.h"
namespace quicktex::s3tc {

@ -21,7 +21,7 @@
#include <memory>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../interpolator/Interpolator.h"

@ -29,8 +29,8 @@
#include <stdexcept>
#include <type_traits>
#include "../../Block.h"
#include "../../Color.h"
#include "../../ColorBlock.h"
#include "../../Matrix4x4.h"
#include "../../Texture.h"
#include "../../Vector4.h"

@ -26,8 +26,8 @@
#include <memory>
#include <tuple>
#include "../../Block.h"
#include "../../Color.h"
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "../interpolator/Interpolator.h"

@ -54,7 +54,7 @@ void InitBC1(py::module_ &s3tc) {
bc1_block.def(py::init<>());
bc1_block.def(py::init<Color, Color, BC1Block::SelectorArray>(), "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<BC1Block>(bc1, "BC1Texture");
bc1_texture.doc() = "A texture comprised of BC1 blocks.";
//endregion
// endregion
//region BC1Encoder
// region BC1Encoder
py::class_<BC1Encoder> bc1_encoder(bc1, "BC1Encoder", "Encodes RGB textures to BC1.");
py::enum_<BC1Encoder::EndpointMode>(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_<BC1Decoder> 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

@ -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<BC3Block, 10>) == 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

@ -19,7 +19,7 @@
#include "BC3Decoder.h"
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "BC3Block.h"
namespace quicktex::s3tc {

@ -21,7 +21,7 @@
#include <memory>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../bc1/BC1Decoder.h"

@ -19,7 +19,7 @@
#include "BC3Encoder.h"
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../bc1/BC1Block.h"
#include "../bc4/BC4Block.h"
#include "BC3Block.h"

@ -21,7 +21,7 @@
#include <memory>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "../bc1/BC1Encoder.h"

@ -17,6 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../_bindings.h"
#include <pybind11/pybind11.h>
#include <array>
@ -45,7 +47,17 @@ void InitBC3(py::module_ &s3tc) {
py::options options;
options.disable_function_signatures();
// BC3Encoder
// region BC3Block
auto bc3_block = BindBlock<BC3Block>(bc3, "BC3Block");
bc3_block.def(py::init<>());
bc3_block.def(py::init<BC4Block, BC1Block>(), "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_<BC3Encoder> 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_<BC3Decoder> 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

@ -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<std::array<uint8_t, 4>, 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<std::array<uint8_t, Width>, Height>;
using AlphaPair = std::pair<uint8_t, uint8_t>;
constexpr BC4Block() {
static_assert(sizeof(BC4Block) == 8);
static_assert(sizeof(std::array<BC4Block, 10>) == 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<uint8_t, uint64_t, 8, 6>(selectors);
auto packed = Pack<uint8_t, uint64_t, 8, SelectorSize>(selectors);
assert(packed <= SelectorBitsMax);
return packed;
}
void SetSelectorBits(uint64_t packed) {
assert(packed <= SelectorBitsMax);
selectors = Unpack<uint64_t, uint8_t, 8, 6>(packed);
selectors = Unpack<uint64_t, uint8_t, 8, SelectorSize>(packed);
}
UnpackedSelectors UnpackSelectors() const {
UnpackedSelectors unpacked;
auto rows = Unpack<uint64_t, uint16_t, 12, 4>(GetSelectorBits());
for (unsigned i = 0; i < 4; i++) {
auto row = Unpack<uint16_t, uint8_t, SelectorBits, 4>(rows[i]);
SelectorArray GetSelectors() const {
SelectorArray unpacked;
auto rows = Unpack<uint64_t, uint16_t, 12, Width>(GetSelectorBits());
for (unsigned i = 0; i < Height; i++) {
auto row = Unpack<uint16_t, uint8_t, SelectorBits, Width>(rows[i]);
unpacked[i] = row;
}
return unpacked;
}
void PackSelectors(const UnpackedSelectors& unpacked) {
std::array<uint16_t, 4> rows;
for (unsigned i = 0; i < 4; i++) { rows[i] = Pack<uint8_t, uint16_t, SelectorBits, 4>(unpacked[i]); }
auto packed = Pack<uint16_t, uint64_t, 12, 4>(rows);
SetSelectorBits(packed);
}
void PackSelectors(const std::array<uint8_t, 16>& unpacked) {
auto packed = Pack<uint8_t, uint64_t, 3, 16>(unpacked);
void SetSelectors(const SelectorArray& unpacked) {
std::array<uint16_t, Height> rows;
for (int i = 0; i < Height; i++) { rows[i] = Pack<uint8_t, uint16_t, SelectorBits, Width>(unpacked[i]); }
auto packed = Pack<uint16_t, uint64_t, 12, Height>(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<uint8_t, 8> GetValues6(uint32_t l, uint32_t h) {
return {static_cast<uint8_t>(l),
static_cast<uint8_t>(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<uint8_t, SelectorSize> selectors;
};
#pragma pack(pop)
} // namespace quicktex::s3tc

@ -22,17 +22,17 @@
#include <array> // for array
#include <cassert> // 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++) {

@ -22,7 +22,7 @@
#include <cstdint>
#include <stdexcept>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "BC4Block.h"

@ -24,7 +24,7 @@
#include <cstdint>
#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<uint8_t, 16> selectors = {};
auto selectors = BC4Block::SelectorArray();
const static std::array<uint8_t, 8> 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;
}

@ -22,7 +22,7 @@
#include <cstdint>
#include <stdexcept>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "BC4Block.h"

@ -17,6 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../../_bindings.h"
#include <pybind11/pybind11.h>
#include <array>
@ -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_<BC4Encoder> bc4_encoder(bc4, "BC4Encoder", R"doc(
Base: :py:class:`~quicktex.BlockEncoder`
// region BC4Block
auto bc4_block = BindBlock<BC4Block>(bc4, "BC4Block");
bc4_block.doc() = "A single BC4 block.";
bc4_block.def(py::init<>());
bc4_block.def(py::init<uint8_t, uint8_t, BC1Block::SelectorArray>(), "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<BC4Block>(bc4, "BC4Texture");
bc4_texture.doc() = "A texture comprised of BC4 blocks.";
// endregion
// region BC4Encoder
py::class_<BC4Encoder> 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_<BC4Decoder> 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

@ -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<BC5Block, 10>) == 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

@ -19,7 +19,7 @@
#include "BC5Decoder.h"
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "BC5Block.h"
namespace quicktex::s3tc {

@ -24,7 +24,7 @@
#include <tuple>
#include <type_traits>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../bc4/BC4Decoder.h"

@ -19,7 +19,7 @@
#include "BC5Encoder.h"
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../bc4/BC4Block.h"
namespace quicktex::s3tc {

@ -24,7 +24,7 @@
#include <tuple>
#include <type_traits>
#include "../../Block.h"
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "../bc4/BC4Encoder.h"

Loading…
Cancel
Save