Header file reorganization

This commit is contained in:
Andrew Cassidy 2022-06-01 23:50:35 -07:00
parent f097f71ba9
commit abfe0b8d10
39 changed files with 566 additions and 350 deletions

View File

@ -12,10 +12,12 @@ find_package(OpenMP)
add_subdirectory(external/xsimd)
include_directories(external/utest)
include_directories(quicktex) # include source root for project-relative includes
# Collect source files
file(GLOB SOURCE_FILES
"quicktex/*.cpp"
"quicktex/util/*.cpp"
"quicktex/ctests/*.cpp"
"quicktex/s3tc/*.cpp"
"quicktex/s3tc/bc1/*.cpp"
@ -27,6 +29,7 @@ file(GLOB SOURCE_FILES
file(GLOB HEADER_FILES
"quicktex/*.h"
"quicktex/util/*.h"
"quicktex/ctests/*.h"
"quicktex/s3tc/*.h"
"quicktex/s3tc/bc1/*.h"
@ -65,7 +68,7 @@ set_simd_flags(_quicktex)
if (MSVC)
target_compile_options(_quicktex PUBLIC /DWIN32_LEAN_AND_MEAN=1 /DNOMINMAX=1) # prevent windows macros from stepping on everything
endif()
endif ()
message("RELEASE FLAGS=${CMAKE_CXX_FLAGS}")

View File

@ -19,6 +19,7 @@
#pragma once
#include "Vec.h"
#include "bitbash.h"
namespace quicktex::color {

View File

@ -23,10 +23,13 @@
#include "Vector4.h"
#include "Vector4Int.h"
#include "util.h" // for scale_to_8<5>, scale_from_8<5>, assert5bit, scale_to_8<6>
#include "util/bitbash.h"
#include "util/math.h" // for scale_to_8<5>, scale_from_8<5>, assert5bit, scale_to_8<6>
namespace quicktex {
using namespace quicktex::util;
OldColor::OldColor(Vector4Int v) {
if (v.MaxAbs() > 0xFF) throw std::invalid_argument("Vector members out of range");
for (int i = 0; i < 4; i++) {

View File

@ -24,7 +24,8 @@
#include <numeric>
#include <xsimd/xsimd.hpp>
#include "util.h"
#include "util/math.h"
#include "util/types.h"
namespace quicktex {

View File

@ -24,14 +24,16 @@
#include <cstdint>
#include <cstring>
#include <memory>
#include <stdexcept>
#include <string>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
#include "ColorBlock.h"
#include "OldColor.h"
#include "Texture.h"
#include "util.h"
#include "util/math.h"
namespace pybind11::detail {
using namespace quicktex;
@ -85,8 +87,27 @@ template <> struct type_caster<OldColor> {
namespace py = pybind11;
namespace quicktex::bindings {
using namespace pybind11::literals;
template <typename... Args> std::string Format(const char* str, const Args&... args) {
auto output = std::string(str);
std::vector<std::string> values = {{args...}};
for (unsigned i = 0; i < values.size(); i++) {
auto key = "{" + std::to_string(i) + "}";
auto value = values[i];
while (true) {
size_t where = output.find(key);
if (where == output.npos) break;
output.replace(where, key.length(), value);
}
}
return output;
}
template <typename T> T BufferToTexture(py::buffer buf, int width, int height) {
static_assert(std::is_base_of<Texture, T>::value);
static_assert(std::is_constructible<T, int, int>::value);
@ -95,11 +116,15 @@ template <typename T> T BufferToTexture(py::buffer buf, int width, int height) {
auto output = T(width, height);
auto dst_size = output.NBytes();
if (info.format != py::format_descriptor<uint8_t>::format()) throw std::runtime_error("Incompatible format in python buffer: expected a byte array.");
if (info.size < (Py_ssize_t)dst_size) std::runtime_error("Incompatible format in python buffer: Input data is smaller than texture size.");
if (info.format != py::format_descriptor<uint8_t>::format())
throw std::runtime_error("Incompatible format in python buffer: expected a byte array.");
if (info.size < (Py_ssize_t)dst_size)
std::runtime_error("Incompatible format in python buffer: Input data is smaller than texture size.");
if (info.ndim == 1) {
if (info.shape[0] < (Py_ssize_t)dst_size) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer has incorrect length.");
if (info.strides[0] != 1) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer is not contiguous.");
if (info.shape[0] < (Py_ssize_t)dst_size)
throw std::runtime_error("Incompatible format in python buffer: 1-D buffer has incorrect length.");
if (info.strides[0] != 1)
throw std::runtime_error("Incompatible format in python buffer: 1-D buffer is not contiguous.");
} else {
throw std::runtime_error("Incompatible format in python buffer: Incorrect number of dimensions.");
}
@ -114,11 +139,15 @@ template <typename T> T BufferToPOD(py::buffer buf) {
auto info = buf.request(false);
if (info.format != py::format_descriptor<uint8_t>::format()) throw std::runtime_error("Incompatible format in python buffer: expected a byte array.");
if (info.size < (Py_ssize_t)sizeof(T)) std::runtime_error("Incompatible format in python buffer: Input data is smaller than texture size.");
if (info.format != py::format_descriptor<uint8_t>::format())
throw std::runtime_error("Incompatible format in python buffer: expected a byte array.");
if (info.size < (Py_ssize_t)sizeof(T))
std::runtime_error("Incompatible format in python buffer: Input data is smaller than texture size.");
if (info.ndim == 1) {
if (info.shape[0] < (Py_ssize_t)sizeof(T)) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer has incorrect length.");
if (info.strides[0] != 1) throw std::runtime_error("Incompatible format in python buffer: 1-D buffer is not contiguous.");
if (info.shape[0] < (Py_ssize_t)sizeof(T))
throw std::runtime_error("Incompatible format in python buffer: 1-D buffer has incorrect length.");
if (info.strides[0] != 1)
throw std::runtime_error("Incompatible format in python buffer: 1-D buffer is not contiguous.");
} else {
throw std::runtime_error("Incompatible format in python buffer: Incorrect number of dimensions.");
}
@ -133,15 +162,18 @@ inline int PyIndex(int val, int size, std::string name = "index") {
return val;
}
template <typename T, typename Getter, typename Setter, typename Extent> void DefSubscript(py::class_<T> t, Getter&& get, Setter&& set, Extent&& ext) {
template <typename T, typename Getter, typename Setter, typename Extent>
void DefSubscript(py::class_<T> t, Getter&& get, Setter&& set, Extent&& ext) {
using V = typename std::invoke_result<Getter, T*, int>::type;
t.def(
"__getitem__", [get, ext](T& self, int index) { return (self.*get)(PyIndex(index, (self.*ext)())); }, "key"_a);
t.def(
"__setitem__", [set, ext](T& self, int index, V val) { (self.*set)(PyIndex(index, (self.*ext)()), val); }, "key"_a, "value"_a);
"__setitem__", [set, ext](T& self, int index, V val) { (self.*set)(PyIndex(index, (self.*ext)()), val); },
"key"_a, "value"_a);
}
template <typename Tpy, typename Getter, typename Setter, typename Extent> void DefSubscript2D(Tpy t, Getter&& get, Setter&& set, Extent&& ext) {
template <typename Tpy, typename Getter, typename Setter, typename Extent>
void DefSubscript2D(Tpy t, Getter&& get, Setter&& set, Extent&& ext) {
using T = typename Tpy::type;
using V = typename std::invoke_result<Getter, T*, int, int>::type;
using Coords = std::tuple<int, int>;
@ -184,7 +216,8 @@ 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_property_readonly_static(
"size", [](py::object) { return std::make_tuple(B::Width, B::Height); }, "The dimensions of the block in pixels.");
"size", [](py::object) { return std::make_tuple(B::Width, B::Height); },
"The dimensions of the block in pixels.");
block.def_property_readonly_static(
"nbytes", [](py::object) { return sizeof(B); }, "The size of the block in bytes.");
@ -223,7 +256,8 @@ template <typename B> py::class_<BlockTexture<B>> BindBlockTexture(py::module_&
py::class_<BTex, Texture> block_texture(m, name);
block_texture.def(py::init<int, int>(), "width"_a, "height"_a, Format(constructor_str, name).c_str());
block_texture.def_static("from_bytes", &BufferToTexture<BTex>, "data"_a, "width"_a, "height"_a, Format(from_bytes_str, name).c_str());
block_texture.def_static("from_bytes", &BufferToTexture<BTex>, "data"_a, "width"_a, "height"_a,
Format(from_bytes_str, name).c_str());
block_texture.def_property_readonly("width_blocks", &BTex::BlocksX, "The width of the texture in blocks.");
block_texture.def_property_readonly("height_blocks", &BTex::BlocksY, "The height of the texture in blocks.");

View File

@ -26,11 +26,14 @@
#include <vector>
#include <xsimd/xsimd.hpp>
#include "../VecUtil.h"
#include "../util.h"
#include "util/math.h"
#include "util/simd.h"
#include "util/types.h"
namespace quicktex::tests {
using namespace quicktex::util;
template <typename T> constexpr auto make_arrays() {
std::vector<std::array<T, xsimd::batch<T>::size>> arrays;
std::array<T, xsimd::batch<T>::size> buffer;

View File

@ -23,7 +23,7 @@
#include <array> // for operator==
#include "../Vec.h" // for Vec, ope...
#include "../util.h" // for abs
#include "util/math.h" // for abs
namespace quicktex::tests {

View File

@ -19,12 +19,16 @@
#include "BC1Block.h"
#include <algorithm>
#include <stdexcept>
#include "../../util.h"
#include "util/ranges.h"
#include "util/bitbash.h"
#include "util/math.h"
namespace quicktex::s3tc {
using namespace quicktex::util;
uint16_t BC1Block::GetColor0Raw() const { return pack<uint16_t>(_color0, 8); }
uint16_t BC1Block::GetColor1Raw() const { return pack<uint16_t>(_color1, 8); }
@ -32,7 +36,7 @@ void BC1Block::SetColor0Raw(uint16_t c) { _color0 = unpack<uint8_t, EndpointSize
void BC1Block::SetColor1Raw(uint16_t c) { _color1 = unpack<uint8_t, EndpointSize>(c, 8); }
BC1Block::SelectorArray BC1Block::GetSelectors() const {
return MapArray(_selectors, [](auto row) { return unpack<uint8_t, Width>(row, SelectorBits); });
return map(_selectors, [](auto row) { return unpack<uint8_t, Width>(row, SelectorBits); });
}
void BC1Block::SetSelectors(const BC1Block::SelectorArray& unpacked) {
@ -40,7 +44,7 @@ void BC1Block::SetSelectors(const BC1Block::SelectorArray& unpacked) {
// if (std::any_of(unpacked[y].begin(), unpacked[y].end(), [](uint8_t i) { return i > SelectorMax; }))
// throw std::invalid_argument("Selector value out of bounds.");
// }
_selectors = MapArray(unpacked, [](auto row) { return pack<uint8_t>(row, SelectorBits, true); });
_selectors = map(unpacked, [](auto row) { return pack<uint8_t>(row, SelectorBits, true); });
}
bool BC1Block::operator==(const BC1Block& Rhs) const {

View File

@ -24,7 +24,7 @@
#include <cstdlib>
#include <utility>
#include "../../OldColor.h"
#include "OldColor.h"
namespace quicktex::s3tc {

View File

@ -23,9 +23,9 @@
#include <cassert>
#include <cstdint>
#include "../../ColorBlock.h"
#include "../../OldColor.h"
#include "BC1Block.h"
#include "ColorBlock.h"
#include "OldColor.h"
#include "s3tc/bc1/BC1Block.h"
namespace quicktex::s3tc {

View File

@ -21,18 +21,19 @@
#include <memory>
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../interpolator/Interpolator.h"
#include "BC1Block.h"
#include "ColorBlock.h"
#include "Decoder.h"
#include "Texture.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/interpolator/Interpolator.h"
namespace quicktex::s3tc {
class BC1Decoder final : public BlockDecoder<BlockTexture<BC1Block>> {
public:
using InterpolatorPtr = std::shared_ptr<Interpolator>;
BC1Decoder(bool vwrite_alpha, InterpolatorPtr interpolator) : write_alpha(vwrite_alpha), _interpolator(interpolator) {}
BC1Decoder(bool vwrite_alpha, InterpolatorPtr interpolator)
: write_alpha(vwrite_alpha), _interpolator(interpolator) {}
BC1Decoder(bool vwrite_alpha = false) : BC1Decoder(vwrite_alpha, std::make_shared<Interpolator>()) {}

View File

@ -29,21 +29,24 @@
#include <stdexcept>
#include <type_traits>
#include "../../ColorBlock.h"
#include "../../Matrix4x4.h"
#include "../../OldColor.h"
#include "../../Texture.h"
#include "../../VecUtil.h"
#include "../../Vector4.h"
#include "../../Vector4Int.h"
#include "../../bitwiseEnums.h"
#include "../../util.h"
#include "ColorBlock.h"
#include "Histogram.h"
#include "OrderTable.h"
#include "SingleColorTable.h"
#include "Matrix4x4.h"
#include "OldColor.h"
#include "Texture.h"
#include "Vector4.h"
#include "Vector4Int.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/bc1/OrderTable.h"
#include "s3tc/bc1/SingleColorTable.h"
#include "util/bitbash.h"
#include "util/bitwiseEnums.h"
#include "util/math.h"
namespace quicktex::s3tc {
using namespace quicktex::util;
// constructors
BC1Encoder::BC1Encoder(unsigned int level, ColorMode color_mode, InterpolatorPtr interpolator)

View File

@ -26,13 +26,13 @@
#include <memory>
#include <tuple>
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../OldColor.h"
#include "../../Texture.h"
#include "../interpolator/Interpolator.h"
#include "BC1Block.h"
#include "SingleColorTable.h"
#include "ColorBlock.h"
#include "Encoder.h"
#include "OldColor.h"
#include "Texture.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/bc1/SingleColorTable.h"
#include "s3tc/interpolator/Interpolator.h"
namespace quicktex {
class Vector4;
@ -79,7 +79,8 @@ class BC1Encoder final : public BlockEncoder<BlockTexture<BC1Block>> {
};
enum class EndpointMode {
// Use 2D least squares+inset+optimal rounding (the method used in Humus's GPU texture encoding demo), instead of PCA.
// Use 2D least squares+inset+optimal rounding (the method used in Humus's GPU texture encoding demo), instead
// of PCA.
// Around 18% faster, very slightly lower average quality to better (depends on the content).
LeastSquares,
@ -101,7 +102,8 @@ class BC1Encoder final : public BlockEncoder<BlockTexture<BC1Block>> {
BC1Encoder(unsigned level, ColorMode color_mode, InterpolatorPtr interpolator);
BC1Encoder(unsigned int level = 5, ColorMode color_mode = ColorMode::FourColor) : BC1Encoder(level, color_mode, std::make_shared<Interpolator>()) {}
BC1Encoder(unsigned int level = 5, ColorMode color_mode = ColorMode::FourColor)
: BC1Encoder(level, color_mode, std::make_shared<Interpolator>()) {}
// Getters and Setters
void SetLevel(unsigned level);
@ -172,21 +174,26 @@ class BC1Encoder final : public BlockEncoder<BlockTexture<BC1Block>> {
BC1Block WriteBlockSolid(OldColor color) const;
BC1Block WriteBlock(EncodeResults &result) const;
void FindEndpoints(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics, EndpointMode endpoint_mode, bool ignore_black = false) const;
void FindEndpoints(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics,
EndpointMode endpoint_mode, bool ignore_black = false) const;
void FindEndpointsSingleColor(EncodeResults &result, OldColor color, bool is_3color = false) const;
void FindEndpointsSingleColor(EncodeResults &result, const CBlock &pixels, OldColor color, bool is_3color) const;
template <ColorMode M> void FindSelectors(EncodeResults &result, const CBlock &pixels, ErrorMode error_mode) const;
template <ColorMode M> bool RefineEndpointsLS(EncodeResults &result, const CBlock &pixels, BlockMetrics metrics) const;
template <ColorMode M> void RefineEndpointsLS(EncodeResults &result, std::array<Vector4, 17> &sums, Vector4 &matrix, Hash hash) const;
template <ColorMode M>
bool RefineEndpointsLS(EncodeResults &result, const CBlock &pixels, BlockMetrics metrics) const;
template <ColorMode M>
void RefineBlockLS(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics, ErrorMode error_mode, unsigned passes) const;
void RefineEndpointsLS(EncodeResults &result, std::array<Vector4, 17> &sums, Vector4 &matrix, Hash hash) const;
template <ColorMode M>
void RefineBlockCF(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics, ErrorMode error_mode, unsigned orderings) const;
void RefineBlockLS(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics, ErrorMode error_mode,
unsigned passes) const;
template <ColorMode M>
void RefineBlockCF(EncodeResults &result, const CBlock &pixels, const BlockMetrics &metrics, ErrorMode error_mode,
unsigned orderings) const;
void EndpointSearch(EncodeResults &result, const CBlock &pixels) const;
};

View File

@ -27,10 +27,10 @@
#include <mutex>
#include <numeric>
#include "../../Vector4.h"
#include "../../util.h"
#include "Vector4.h"
#include "util/math.h"
namespace quicktex::s3tc {
namespace quicktex::s3tc {
template <size_t N> class Histogram {
public:
using Hash = uint16_t;
@ -71,7 +71,7 @@ template <size_t N> class Histogram {
unsigned GetPacked() const {
Hash packed = 0;
for (unsigned i = 0; i < (N-1); i++) {
for (unsigned i = 0; i < (N - 1); i++) {
assert(_bins[i] <= (1U << 4) - 1U);
packed |= static_cast<uint16_t>(_bins[i]) << (i * 4U);
}

View File

@ -21,7 +21,7 @@
#include <array>
#include "../../Vector4.h"
#include "Vector4.h"
namespace quicktex::s3tc {
using Hash = uint16_t;

View File

@ -29,8 +29,8 @@
#include <mutex>
#include <type_traits>
#include "../../Vector4.h"
#include "Histogram.h"
#include "Vector4.h"
namespace quicktex::s3tc {
template <size_t N> class OrderTable {
@ -113,7 +113,9 @@ template <size_t N> class OrderTable {
return factors->at(hash);
}
static bool IsSingleColor(Hash hash) { return (std::find(SingleColorHashes.begin(), SingleColorHashes.end(), hash) != SingleColorHashes.end()); }
static bool IsSingleColor(Hash hash) {
return (std::find(SingleColorHashes.begin(), SingleColorHashes.end(), hash) != SingleColorHashes.end());
}
private:
static std::mutex table_mutex;

View File

@ -23,11 +23,14 @@
#include <cstdint>
#include <memory>
#include "../../util.h"
#include "../interpolator/Interpolator.h"
#include "s3tc/interpolator/Interpolator.h"
#include "util/bitbash.h"
#include "util/math.h"
namespace quicktex::s3tc {
using namespace quicktex::util;
struct BC1MatchEntry {
uint8_t high;
uint8_t low;

View File

@ -23,16 +23,12 @@
#include <pybind11/stl.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <memory>
#include "../../Decoder.h"
#include "../../Encoder.h"
#include "../interpolator/Interpolator.h"
#include "BC1Decoder.h"
#include "BC1Encoder.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/bc1/BC1Decoder.h"
#include "s3tc/bc1/BC1Encoder.h"
#include "s3tc/interpolator/Interpolator.h"
namespace py = pybind11;
namespace quicktex::bindings {
@ -58,7 +54,8 @@ 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("endpoints", &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.
@ -83,27 +80,42 @@ void InitBC1(py::module_ &s3tc) {
// 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.")
.value("LeastSquares", BC1Encoder::EndpointMode::LeastSquares, "Find endpoints using a 2D least squares approach.")
.value("BoundingBox", BC1Encoder::EndpointMode::BoundingBox, "Find endpoints using a simple bounding box. Fast but inaccurate.")
.value("BoundingBoxInt", BC1Encoder::EndpointMode::BoundingBoxInt, "Same as BoundingBox but using integers, slightly faster.")
.value("PCA", BC1Encoder::EndpointMode::PCA, "Find endpoints using Principle Component Analysis. Slowest but highest quality method.");
py::enum_<BC1Encoder::EndpointMode>(bc1_encoder, "EndpointMode",
"Enum representing various methods of finding endpoints in a block.")
.value("LeastSquares", BC1Encoder::EndpointMode::LeastSquares,
"Find endpoints using a 2D least squares approach.")
.value("BoundingBox", BC1Encoder::EndpointMode::BoundingBox,
"Find endpoints using a simple bounding box. Fast but inaccurate.")
.value("BoundingBoxInt", BC1Encoder::EndpointMode::BoundingBoxInt,
"Same as BoundingBox but using integers, slightly faster.")
.value("PCA", BC1Encoder::EndpointMode::PCA,
"Find endpoints using Principle Component Analysis. Slowest but highest quality method.");
py::enum_<BC1Encoder::ErrorMode>(bc1_encoder, "ErrorMode", "Enum representing various methods of finding selectors in a block.")
.value("None", BC1Encoder::ErrorMode::None, "The same as Faster but error is not calculated. This disables any cluster-fit options")
.value("Faster", BC1Encoder::ErrorMode::Faster, "Use a slightly lower quality, but ~30% faster MSE evaluation function for 4-color blocks.")
py::enum_<BC1Encoder::ErrorMode>(bc1_encoder, "ErrorMode",
"Enum representing various methods of finding selectors in a block.")
.value("None", BC1Encoder::ErrorMode::None,
"The same as Faster but error is not calculated. This disables any cluster-fit options")
.value("Faster", BC1Encoder::ErrorMode::Faster,
"Use a slightly lower quality, but ~30% faster MSE evaluation function for 4-color blocks.")
.value("Check2", BC1Encoder::ErrorMode::Check2, "Default error-checking method.")
.value("Full", BC1Encoder::ErrorMode::Full, "Examine all colors to compute selectors/MSE. Slower but slightly higher quality.");
.value("Full", BC1Encoder::ErrorMode::Full,
"Examine all colors to compute selectors/MSE. Slower but slightly higher quality.");
py::enum_<BC1Encoder::ColorMode>(bc1_encoder, "ColorMode", "Enum representing various methods of writing BC1 blocks.")
.value("FourColor", BC1Encoder::ColorMode::FourColor, "Default color mode. Only 4-color blocks will be output, where color0 > color1")
.value("ThreeColor", BC1Encoder::ColorMode::ThreeColor, "Additionally use 3-color blocks when they have a lower error, where color0 <= color1")
py::enum_<BC1Encoder::ColorMode>(bc1_encoder, "ColorMode",
"Enum representing various methods of writing BC1 blocks.")
.value("FourColor", BC1Encoder::ColorMode::FourColor,
"Default color mode. Only 4-color blocks will be output, where color0 > color1")
.value("ThreeColor", BC1Encoder::ColorMode::ThreeColor,
"Additionally use 3-color blocks when they have a lower error, where color0 <= color1")
.value("ThreeColorBlack", BC1Encoder::ColorMode::ThreeColorBlack,
"Additionally use 3-color blocks with black pixels (selector 3). Note that this requires your shader/engine to not sample the alpha channel "
"Additionally use 3-color blocks with black pixels (selector 3). Note that this requires your "
"shader/engine to not sample the alpha channel "
"when using a BC1 texture.");
bc1_encoder.def(py::init<unsigned, BC1Encoder::ColorMode>(), "level"_a = 5, "color_mode"_a = BC1Encoder::ColorMode::FourColor);
bc1_encoder.def(py::init<unsigned, BC1Encoder::ColorMode, InterpolatorPtr>(), "level"_a, "color_mode"_a, "interpolator"_a, R"doc(
bc1_encoder.def(py::init<unsigned, BC1Encoder::ColorMode>(), "level"_a = 5,
"color_mode"_a = BC1Encoder::ColorMode::FourColor);
bc1_encoder.def(py::init<unsigned, BC1Encoder::ColorMode, InterpolatorPtr>(), "level"_a, "color_mode"_a,
"interpolator"_a, R"doc(
Create a new BC1 encoder with the specified preset level, color mode, and interpolator.
:param int level: The preset level of the resulting encoder, between 0 and 18 inclusive. See :py:meth:`set_level` for more information. Default: 5.
@ -125,44 +137,56 @@ void InitBC1(py::module_ &s3tc) {
:param int level: The preset level of the resulting encoder, between 0 and 18 inclusive. Default: 5.
)doc");
bc1_encoder.def_property_readonly("interpolator", &BC1Encoder::GetInterpolator,
"The :py:class:`~quicktex.s3tc.interpolator.Interpolator` used by this encoder. This is a readonly property.");
bc1_encoder.def_property_readonly("color_mode", &BC1Encoder::GetColorMode,
"The :py:class:`~quicktex.s3tc.bc1.BC1Encoder.ColorMode` used by this encoder. This is a readonly property.");
bc1_encoder.def_property_readonly(
"interpolator", &BC1Encoder::GetInterpolator,
"The :py:class:`~quicktex.s3tc.interpolator.Interpolator` used by this encoder. This is a readonly property.");
bc1_encoder.def_property_readonly(
"color_mode", &BC1Encoder::GetColorMode,
"The :py:class:`~quicktex.s3tc.bc1.BC1Encoder.ColorMode` used by this encoder. This is a readonly property.");
// Advanced API
bc1_encoder.def_property("error_mode", &BC1Encoder::GetErrorMode, &BC1Encoder::SetErrorMode, "The error mode used by this encoder for finding selectors.");
bc1_encoder.def_property("endpoint_mode", &BC1Encoder::GetEndpointMode, &BC1Encoder::SetEndpointMode, "The endpoint mode used by this encoder.");
bc1_encoder.def_property("error_mode", &BC1Encoder::GetErrorMode, &BC1Encoder::SetErrorMode,
"The error mode used by this encoder for finding selectors.");
bc1_encoder.def_property("endpoint_mode", &BC1Encoder::GetEndpointMode, &BC1Encoder::SetEndpointMode,
"The endpoint mode used by this encoder.");
bc1_encoder.def_readwrite("two_ls_passes", &BC1Encoder::two_ls_passes,
"Use 2 least squares pass, instead of one (same as stb_dxt's HIGHQUAL option).\n"
"Recommended if you're setting the orderings settings greater than 0.");
bc1_encoder.def_readwrite("two_ep_passes", &BC1Encoder::two_ep_passes, "Try 2 different ways of choosing the initial endpoints.");
bc1_encoder.def_readwrite("two_ep_passes", &BC1Encoder::two_ep_passes,
"Try 2 different ways of choosing the initial endpoints.");
bc1_encoder.def_readwrite("two_cf_passes", &BC1Encoder::two_cf_passes,
"Greatly increase encode time, with very slightly higher quality.\n"
"Same as squish's iterative cluster fit option. Not really worth the tiny boost in quality, "
"unless you just don't care about performance at all.");
bc1_encoder.def_readwrite(
"two_cf_passes", &BC1Encoder::two_cf_passes,
"Greatly increase encode time, with very slightly higher quality.\n"
"Same as squish's iterative cluster fit option. Not really worth the tiny boost in quality, "
"unless you just don't care about performance at all.");
bc1_encoder.def_readwrite("exhaustive", &BC1Encoder::exhaustive,
"Check all total orderings - *very* slow. The encoder is not designed to be used in this way");
bc1_encoder.def_readwrite(
"exhaustive", &BC1Encoder::exhaustive,
"Check all total orderings - *very* slow. The encoder is not designed to be used in this way");
bc1_encoder.def_property("search_rounds", &BC1Encoder::GetSearchRounds, &BC1Encoder::SetSearchRounds,
"Setting search rounds > 0 enables refining the final endpoints by examining nearby colors. A higher value has a higher quality "
"Setting search rounds > 0 enables refining the final endpoints by examining nearby "
"colors. A higher value has a higher quality "
"at the expense of performance.");
bc1_encoder.def_property("orderings", &BC1Encoder::GetOrderings, &BC1Encoder::SetOrderings,
"setting the orderings > 0 enables ordered cluster fit using a lookup table of similar blocks. Value is a tuple of (4 color "
"orders, 3 color orders), where higher values have a higher quality at the expense of performance.");
bc1_encoder.def_property(
"orderings", &BC1Encoder::GetOrderings, &BC1Encoder::SetOrderings,
"setting the orderings > 0 enables ordered cluster fit using a lookup table of similar blocks. Value is a "
"tuple of (4 color "
"orders, 3 color orders), where higher values have a higher quality at the expense of performance.");
bc1_encoder.def_readonly_static("max_power_iterations", &BC1Encoder::max_power_iterations);
bc1_encoder.def_readonly_static("min_power_iterations", &BC1Encoder::min_power_iterations);
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`");
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
// region BC1Decoder
@ -185,8 +209,10 @@ void InitBC1(py::module_ &s3tc) {
:returns: A new RawTexture with the same dimensions as the input
)doc");
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.");
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
}
} // namespace quicktex::bindings

View File

@ -21,8 +21,8 @@
#include <utility>
#include "../bc1/BC1Block.h"
#include "../bc4/BC4Block.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/bc4/BC4Block.h"
namespace quicktex::s3tc {
@ -54,7 +54,9 @@ class alignas(8) BC3Block {
color_block = blocks.second;
}
bool operator==(const BC3Block &Rhs) const { return alpha_block == Rhs.alpha_block && color_block == Rhs.color_block; }
bool operator==(const BC3Block &Rhs) const {
return alpha_block == Rhs.alpha_block && color_block == Rhs.color_block;
}
bool operator!=(const BC3Block &Rhs) const { return !(Rhs == *this); }
};
} // namespace quicktex::s3tc

View File

@ -21,13 +21,13 @@
#include <memory>
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../bc1/BC1Decoder.h"
#include "../bc4/BC4Decoder.h"
#include "../interpolator/Interpolator.h"
#include "BC3Block.h"
#include "ColorBlock.h"
#include "Decoder.h"
#include "Texture.h"
#include "s3tc/bc1/BC1Decoder.h"
#include "s3tc/bc3/BC3Block.h"
#include "s3tc/bc4/BC4Decoder.h"
#include "s3tc/interpolator/Interpolator.h"
namespace quicktex::s3tc {
@ -37,7 +37,8 @@ class BC3Decoder : public BlockDecoder<BlockTexture<BC3Block>> {
using BC4DecoderPtr = std::shared_ptr<BC4Decoder>;
using InterpolatorPtr = std::shared_ptr<Interpolator>;
BC3Decoder(InterpolatorPtr interpolator) : _bc1_decoder(std::make_shared<BC1Decoder>(interpolator)), _bc4_decoder(std::make_shared<BC4Decoder>(3)) {}
BC3Decoder(InterpolatorPtr interpolator)
: _bc1_decoder(std::make_shared<BC1Decoder>(interpolator)), _bc4_decoder(std::make_shared<BC4Decoder>(3)) {}
BC3Decoder() : BC3Decoder(std::make_shared<Interpolator>()) {}

View File

@ -19,10 +19,8 @@
#include "BC3Encoder.h"
#include "../../ColorBlock.h"
#include "../bc1/BC1Block.h"
#include "../bc4/BC4Block.h"
#include "BC3Block.h"
#include "ColorBlock.h"
#include "s3tc/bc3/BC3Block.h"
namespace quicktex::s3tc {
BC3Block BC3Encoder::EncodeBlock(const ColorBlock<4, 4> &pixels) const {

View File

@ -21,13 +21,13 @@
#include <memory>
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "../bc1/BC1Encoder.h"
#include "../bc4/BC4Encoder.h"
#include "../interpolator/Interpolator.h"
#include "BC3Block.h"
#include "ColorBlock.h"
#include "Encoder.h"
#include "Texture.h"
#include "s3tc/bc1/BC1Encoder.h"
#include "s3tc/bc3/BC3Block.h"
#include "s3tc/bc4/BC4Encoder.h"
#include "s3tc/interpolator/Interpolator.h"
namespace quicktex::s3tc {
@ -38,7 +38,8 @@ class BC3Encoder : public BlockEncoder<BlockTexture<BC3Block>> {
using InterpolatorPtr = std::shared_ptr<Interpolator>;
BC3Encoder(unsigned level, InterpolatorPtr interpolator)
: _bc1_encoder(std::make_shared<BC1Encoder>(level, BC1Encoder::ColorMode::FourColor, interpolator)), _bc4_encoder(std::make_shared<BC4Encoder>(3)) {}
: _bc1_encoder(std::make_shared<BC1Encoder>(level, BC1Encoder::ColorMode::FourColor, interpolator)),
_bc4_encoder(std::make_shared<BC4Encoder>(3)) {}
BC3Encoder(unsigned level = 5) : BC3Encoder(level, std::make_shared<Interpolator>()) {}

View File

@ -22,16 +22,14 @@
#include <pybind11/pybind11.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>
#include <memory>
#include "../../Decoder.h"
#include "../../Encoder.h"
#include "../interpolator/Interpolator.h"
#include "BC3Decoder.h"
#include "BC3Encoder.h"
#include "s3tc/bc1/BC1Block.h"
#include "s3tc/bc3/BC3Block.h"
#include "s3tc/bc3/BC3Decoder.h"
#include "s3tc/bc3/BC3Encoder.h"
#include "s3tc/bc4/BC4Block.h"
#include "s3tc/interpolator/Interpolator.h"
namespace py = pybind11;
namespace quicktex::bindings {
@ -59,7 +57,8 @@ void InitBC3(py::module_ &s3tc) {
bc3_block.def_readwrite("alpha_block", &BC3Block::alpha_block, "The BC4 block used for alpha data.");
bc3_block.def_readwrite("color_block", &BC3Block::color_block, "The BC1 block used for rgb data.");
bc3_block.def_property("blocks", &BC3Block::GetBlocks, &BC3Block::SetBlocks, "The BC4 and BC1 blocks that make up this block as a 2-tuple.");
bc3_block.def_property("blocks", &BC3Block::GetBlocks, &BC3Block::SetBlocks,
"The BC4 and BC1 blocks that make up this block as a 2-tuple.");
// endregion
// region BC3Texture
@ -88,10 +87,12 @@ void InitBC3(py::module_ &s3tc) {
:returns: A new BC3Texture with the same dimension as the input.
)doc");
bc3_encoder.def_property_readonly("bc1_encoder", &BC3Encoder::GetBC1Encoder,
"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.");
bc3_encoder.def_property_readonly(
"bc1_encoder", &BC3Encoder::GetBC1Encoder,
"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
// region BC3Decoder
@ -113,10 +114,12 @@ void InitBC3(py::module_ &s3tc) {
:returns: A new RawTexture with the same dimensions as the input
)doc");
bc3_decoder.def_property_readonly("bc1_decoder", &BC3Decoder::GetBC1Decoder,
"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.");
bc3_decoder.def_property_readonly(
"bc1_decoder", &BC3Decoder::GetBC1Decoder,
"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

View File

@ -22,14 +22,18 @@
#include <algorithm>
#include <stdexcept>
#include "../../util.h"
#include "util/ranges.h"
#include "util/bitbash.h"
#include "util/math.h"
namespace quicktex::s3tc {
using namespace quicktex::util;
BC4Block::SelectorArray BC4Block::GetSelectors() const {
auto packed = pack<uint64_t>(_selectors, 8);
auto rows = unpack<uint16_t, Height>(packed, SelectorBits * Width);
return MapArray(rows, [](auto row) { return unpack<uint8_t, Width>(row, SelectorBits); });
return map(rows, [](auto row) { return unpack<uint8_t, Width>(row, SelectorBits); });
}
void BC4Block::SetSelectors(const BC4Block::SelectorArray& unpacked) {
@ -37,7 +41,7 @@ void BC4Block::SetSelectors(const BC4Block::SelectorArray& unpacked) {
if (std::any_of(unpacked[y].begin(), unpacked[y].end(), [](uint8_t i) { return i > SelectorMax; }))
throw std::invalid_argument("Selector value out of bounds.");
}
auto rows = MapArray(unpacked, [](auto r) { return pack<uint16_t>(r, SelectorBits); });
auto rows = map(unpacked, [](auto r) { return pack<uint16_t>(r, SelectorBits); });
auto packed = pack<uint64_t>(rows, SelectorBits * Width);
_selectors = unpack<uint8_t, SelectorSize>(packed, 8);
}

View File

@ -23,15 +23,11 @@
#include <pybind11/stl.h>
#include <array>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <string>
#include "../../Decoder.h"
#include "../../Encoder.h"
#include "BC4Decoder.h"
#include "BC4Encoder.h"
#include "s3tc/bc4/BC4Block.h"
#include "s3tc/bc4/BC4Decoder.h"
#include "s3tc/bc4/BC4Encoder.h"
namespace py = pybind11;
namespace quicktex::bindings {
@ -46,7 +42,8 @@ void InitBC4(py::module_ &s3tc) {
bc4_block.doc() = "A single BC4 block.";
bc4_block.def(py::init<>());
bc4_block.def(py::init<uint8_t, uint8_t, BC4Block::SelectorArray>(), "endpoint0"_a, "endpoint1"_a, "selectors"_a, R"doc(
bc4_block.def(py::init<uint8_t, uint8_t, BC4Block::SelectorArray>(), "endpoint0"_a, "endpoint1"_a, "selectors"_a,
R"doc(
Create a new BC4Block with the specified endpoints and selectors.
:param int endpoint0: The first endpoint.
@ -54,7 +51,8 @@ void InitBC4(py::module_ &s3tc) {
: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("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.
@ -96,8 +94,9 @@ void InitBC4(py::module_ &s3tc) {
:param RawTexture texture: Input texture to encode.
:returns: A new BC4Texture with the same dimension as the input.
)doc");
bc4_encoder.def_property_readonly("channel", &BC4Encoder::GetChannel, "The channel that will be read from. 0 to 3 inclusive. Readonly.");
bc4_encoder.def_property_readonly("channel", &BC4Encoder::GetChannel,
"The channel that will be read from. 0 to 3 inclusive. Readonly.");
// endregion
// region BC4Decoder
@ -117,8 +116,9 @@ void InitBC4(py::module_ &s3tc) {
:param RawTexture texture: Input texture to encode.
:returns: A new RawTexture with the same dimensions as the input
)doc");
bc4_decoder.def_property_readonly("channel", &BC4Decoder::GetChannel, "The channel that will be written to. 0 to 3 inclusive. Readonly.");
bc4_decoder.def_property_readonly("channel", &BC4Decoder::GetChannel,
"The channel that will be written to. 0 to 3 inclusive. Readonly.");
// endregion
}

View File

@ -19,9 +19,7 @@
#pragma once
#include <utility>
#include "../bc4/BC4Block.h"
#include "s3tc/bc4/BC4Block.h"
namespace quicktex::s3tc {
@ -53,7 +51,9 @@ class alignas(8) BC5Block {
chan1_block = pair.second;
}
bool operator==(const BC5Block &Rhs) const { return chan0_block == Rhs.chan0_block && chan1_block == Rhs.chan1_block; }
bool operator==(const BC5Block &Rhs) const {
return chan0_block == Rhs.chan0_block && chan1_block == Rhs.chan1_block;
}
bool operator!=(const BC5Block &Rhs) const { return !(Rhs == *this); }
};
} // namespace quicktex::s3tc

View File

@ -19,8 +19,8 @@
#include "BC5Decoder.h"
#include "../../ColorBlock.h"
#include "BC5Block.h"
#include "ColorBlock.h"
#include "s3tc/bc5/BC5Block.h"
namespace quicktex::s3tc {
ColorBlock<4, 4> BC5Decoder::DecodeBlock(const BC5Block &block) const {

View File

@ -24,11 +24,11 @@
#include <tuple>
#include <type_traits>
#include "../../ColorBlock.h"
#include "../../Decoder.h"
#include "../../Texture.h"
#include "../bc4/BC4Decoder.h"
#include "BC5Block.h"
#include "ColorBlock.h"
#include "Decoder.h"
#include "Texture.h"
#include "s3tc/bc4/BC4Decoder.h"
#include "s3tc/bc5/BC5Block.h"
namespace quicktex::s3tc {
@ -38,8 +38,10 @@ class BC5Decoder : public BlockDecoder<BlockTexture<BC5Block>> {
using BC4DecoderPtr = std::shared_ptr<BC4Decoder>;
using BC4DecoderPair = std::tuple<BC4DecoderPtr, BC4DecoderPtr>;
BC5Decoder(uint8_t chan0 = 0, uint8_t chan1 = 1) : BC5Decoder(std::make_shared<BC4Decoder>(chan0), std::make_shared<BC4Decoder>(chan1)) {}
BC5Decoder(BC4DecoderPtr chan0_decoder, BC4DecoderPtr chan1_decoder) : _chan0_decoder(chan0_decoder), _chan1_decoder(chan1_decoder) {}
BC5Decoder(uint8_t chan0 = 0, uint8_t chan1 = 1)
: BC5Decoder(std::make_shared<BC4Decoder>(chan0), std::make_shared<BC4Decoder>(chan1)) {}
BC5Decoder(BC4DecoderPtr chan0_decoder, BC4DecoderPtr chan1_decoder)
: _chan0_decoder(chan0_decoder), _chan1_decoder(chan1_decoder) {}
ColorBlock<4, 4> DecodeBlock(const BC5Block &block) const override;

View File

@ -19,8 +19,8 @@
#include "BC5Encoder.h"
#include "../../ColorBlock.h"
#include "../bc4/BC4Block.h"
#include "ColorBlock.h"
#include "s3tc/bc4/BC4Block.h"
namespace quicktex::s3tc {
BC5Block BC5Encoder::EncodeBlock(const ColorBlock<4, 4> &pixels) const {

View File

@ -24,11 +24,11 @@
#include <tuple>
#include <type_traits>
#include "../../ColorBlock.h"
#include "../../Encoder.h"
#include "../../Texture.h"
#include "../bc4/BC4Encoder.h"
#include "BC5Block.h"
#include "ColorBlock.h"
#include "Encoder.h"
#include "Texture.h"
#include "s3tc/bc4/BC4Encoder.h"
#include "s3tc/bc5/BC5Block.h"
namespace quicktex::s3tc {
class BC5Encoder : public BlockEncoder<BlockTexture<BC5Block>> {
@ -37,8 +37,10 @@ class BC5Encoder : public BlockEncoder<BlockTexture<BC5Block>> {
using BC4EncoderPtr = std::shared_ptr<BC4Encoder>;
using BC4EncoderPair = std::tuple<BC4EncoderPtr, BC4EncoderPtr>;
BC5Encoder(uint8_t chan0 = 0, uint8_t chan1 = 1) : BC5Encoder(std::make_shared<BC4Encoder>(chan0), std::make_shared<BC4Encoder>(chan1)) {}
BC5Encoder(BC4EncoderPtr chan0_encoder, BC4EncoderPtr chan1_encoder) : _chan0_encoder(chan0_encoder), _chan1_encoder(chan1_encoder) {}
BC5Encoder(uint8_t chan0 = 0, uint8_t chan1 = 1)
: BC5Encoder(std::make_shared<BC4Encoder>(chan0), std::make_shared<BC4Encoder>(chan1)) {}
BC5Encoder(BC4EncoderPtr chan0_encoder, BC4EncoderPtr chan1_encoder)
: _chan0_encoder(chan0_encoder), _chan1_encoder(chan1_encoder) {}
BC5Block EncodeBlock(const ColorBlock<4, 4> &pixels) const override;

View File

@ -24,10 +24,10 @@
#include <array>
#include <cstdint>
#include "../../Decoder.h"
#include "../../Encoder.h"
#include "BC5Decoder.h"
#include "BC5Encoder.h"
#include "s3tc/bc4/BC4Block.h"
#include "s3tc/bc5/BC5Block.h"
#include "s3tc/bc5/BC5Decoder.h"
#include "s3tc/bc5/BC5Encoder.h"
namespace py = pybind11;
namespace quicktex::bindings {
@ -52,7 +52,8 @@ void InitBC5(py::module_ &s3tc) {
bc5_block.def_readwrite("chan0_block", &BC5Block::chan0_block, "The BC4 block used for the first channel.");
bc5_block.def_readwrite("chan1_block", &BC5Block::chan1_block, "The BC4 block used for the second channel.");
bc5_block.def_property("blocks", &BC5Block::GetBlocks, &BC5Block::SetBlocks, "The BC4 and BC1 blocks that make up this block as a 2-tuple.");
bc5_block.def_property("blocks", &BC5Block::GetBlocks, &BC5Block::SetBlocks,
"The BC4 and BC1 blocks that make up this block as a 2-tuple.");
// endregion
// region BC5Texture
@ -79,9 +80,11 @@ void InitBC5(py::module_ &s3tc) {
:returns: A new BC5Texture with the same dimension as the input.
)doc");
bc5_encoder.def_property_readonly("channels", &BC5Encoder::GetChannels, "A 2-tuple of channels that will be read from. 0 to 3 inclusive. Readonly.");
bc5_encoder.def_property_readonly("bc4_encoders", &BC5Encoder::GetBC4Encoders,
"2-tuple of internal :py:class:`~quicktex.s3tc.bc4.BC4Encoder` s used for each channel. Readonly.");
bc5_encoder.def_property_readonly("channels", &BC5Encoder::GetChannels,
"A 2-tuple of channels that will be read from. 0 to 3 inclusive. Readonly.");
bc5_encoder.def_property_readonly(
"bc4_encoders", &BC5Encoder::GetBC4Encoders,
"2-tuple of internal :py:class:`~quicktex.s3tc.bc4.BC4Encoder` s used for each channel. Readonly.");
// endregion
// region BC5Decoder
@ -103,9 +106,11 @@ void InitBC5(py::module_ &s3tc) {
:returns: A new RawTexture with the same dimensions as the input
)doc");
bc5_decoder.def_property_readonly("channels", &BC5Decoder::GetChannels, "A 2-tuple of channels that will be written to. 0 to 3 inclusive. Readonly.");
bc5_decoder.def_property_readonly("bc4_decoders", &BC5Decoder::GetBC4Decoders,
"2-tuple of internal :py:class:`~quicktex.s3tc.bc4.BC4Decoder` s used for each channel. Readonly.");
bc5_decoder.def_property_readonly("channels", &BC5Decoder::GetChannels,
"A 2-tuple of channels that will be written to. 0 to 3 inclusive. Readonly.");
bc5_decoder.def_property_readonly(
"bc4_decoders", &BC5Decoder::GetBC4Decoders,
"2-tuple of internal :py:class:`~quicktex.s3tc.bc4.BC4Decoder` s used for each channel. Readonly.");
// endregion
}
} // namespace quicktex::bindings

View File

@ -24,11 +24,13 @@
#include <cstdint>
#include <stdexcept>
#include "../../OldColor.h"
#include "../../util.h"
#include "OldColor.h"
#include "util/bitbash.h"
namespace quicktex::s3tc {
using namespace quicktex::util;
// region Interpolator implementation
std::unique_ptr<Interpolator> Interpolator::MakeInterpolator(Interpolator::Type type) {
switch (type) {
@ -45,10 +47,18 @@ std::unique_ptr<Interpolator> Interpolator::MakeInterpolator(Interpolator::Type
}
}
uint8_t Interpolator::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1)); }
uint8_t Interpolator::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1)); }
uint8_t Interpolator::InterpolateHalf5(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale_to_8<5>(v0), scale_to_8<5>(v1)); }
uint8_t Interpolator::InterpolateHalf6(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale_to_8<6>(v0), scale_to_8<6>(v1)); }
uint8_t Interpolator::Interpolate5(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1));
}
uint8_t Interpolator::Interpolate6(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1));
}
uint8_t Interpolator::InterpolateHalf5(uint8_t v0, uint8_t v1) const {
return InterpolateHalf8(scale_to_8<5>(v0), scale_to_8<5>(v1));
}
uint8_t Interpolator::InterpolateHalf6(uint8_t v0, uint8_t v1) const {
return InterpolateHalf8(scale_to_8<6>(v0), scale_to_8<6>(v1));
}
std::array<OldColor, 4> Interpolator::Interpolate565BC1(uint16_t low, uint16_t high, bool allow_3color) const {
bool use_3color = allow_3color && (high >= low);
@ -79,8 +89,12 @@ uint8_t Interpolator::InterpolateHalf8(uint8_t v0, uint8_t v1) const { return (v
// endregion
// region InterpolatorRound implementation
uint8_t InterpolatorRound::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1)); }
uint8_t InterpolatorRound::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1)); }
uint8_t InterpolatorRound::Interpolate5(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1));
}
uint8_t InterpolatorRound::Interpolate6(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1));
}
uint8_t InterpolatorRound::Interpolate8(uint8_t v0, uint8_t v1) const { return (v0 * 2 + v1 + 1) / 3; }
// endregion
@ -129,10 +143,18 @@ std::array<OldColor, 4> InterpolatorNvidia::InterpolateBC1(OldColor low, OldColo
// endregion
// region InterpolatorAMD implementation
uint8_t InterpolatorAMD::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1)); }
uint8_t InterpolatorAMD::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1)); }
uint8_t InterpolatorAMD::InterpolateHalf5(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale_to_8<5>(v0), scale_to_8<5>(v1)); }
uint8_t InterpolatorAMD::InterpolateHalf6(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale_to_8<6>(v0), scale_to_8<6>(v1)); }
uint8_t InterpolatorAMD::Interpolate5(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<5>(v0), scale_to_8<5>(v1));
}
uint8_t InterpolatorAMD::Interpolate6(uint8_t v0, uint8_t v1) const {
return Interpolate8(scale_to_8<6>(v0), scale_to_8<6>(v1));
}
uint8_t InterpolatorAMD::InterpolateHalf5(uint8_t v0, uint8_t v1) const {
return InterpolateHalf8(scale_to_8<5>(v0), scale_to_8<5>(v1));
}
uint8_t InterpolatorAMD::InterpolateHalf6(uint8_t v0, uint8_t v1) const {
return InterpolateHalf8(scale_to_8<6>(v0), scale_to_8<6>(v1));
}
uint8_t InterpolatorAMD::Interpolate8(uint8_t v0, uint8_t v1) const { return (v0 * 43 + v1 * 21 + 32) >> 6; }

View File

@ -22,7 +22,7 @@
#include <cstdint> // for uint8_t, uint16_t
#include <memory> // for unique_ptr
#include "../../OldColor.h" // for Color
#include "OldColor.h" // for Color
namespace quicktex::s3tc {

View File

@ -1,5 +1,5 @@
/* Quicktex Texture Compression Library
Copyright (C) 2021-2022 Andrew Cassidy <drewcassidy@me.com>
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich <richgel99@gmail.com>
and licenced under the public domain
@ -18,15 +18,16 @@
*/
#pragma once
#include <array>
#include <cassert>
#include <cstdint>
#include <functional>
#include <concepts>
#include <limits>
#include <numeric>
#include <string>
#include <type_traits>
#include <vector>
#include <xsimd/xsimd.hpp>
#include "util/math.h"
#include "util/ranges.h"
#define UINT5_MAX 0x1FU // 31
#define UINT6_MAX 0x3FU // 63
@ -34,65 +35,7 @@
#define assert5bit(x) assert(x <= UINT5_MAX)
#define assert6bit(x) assert(x <= UINT6_MAX)
namespace quicktex {
// std::ranges::range is currently not usable by default in libc++
template <class T>
concept range = requires(T &t) {
std::begin(t);
std::end(t);
};
template <class T>
concept sized_range = range<T> && requires(T &t) { std::size(t); };
template <class T>
requires range<T>
size_t distance(T range) {
return std::distance(range.begin(), range.end());
}
template <typename T> class const_iterator {
public:
typedef long long difference_type;
typedef T value_type;
const_iterator() : _value(T{}), _index(0) {}
const_iterator(T value, size_t index = 0) : _value(value), _index(index) {}
const_iterator &operator++() {
_index++;
return *this;
}
const_iterator operator++(int) {
const_iterator old = *this;
_index++;
return old;
}
const_iterator &operator--() {
_index++;
return *this;
}
const_iterator operator--(int) {
const_iterator old = *this;
_index++;
return old;
}
T operator*() const { return _value; }
difference_type operator-(const_iterator rhs) const { return (difference_type)_index - rhs._index; }
const_iterator operator+(size_t rhs) const { return const_iterator(rhs + _index); }
const_iterator operator-(size_t rhs) const { return const_iterator(rhs - _index); }
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) {
return (lhs._value == rhs._value) && (lhs._index == rhs._index);
}
private:
T _value;
size_t _index;
};
namespace quicktex::util {
template <size_t N, typename S> S scale_from_8(S v) {
static_assert(N < 8);
@ -366,55 +309,4 @@ template <typename P, typename IR>
inline constexpr P pack(IR r, size_t width, bool little_endian = true) {
return pack<P>(r.begin(), r.end(), const_iterator(width), little_endian);
}
template <typename Seq, typename Fn> constexpr auto MapArray(const Seq &input, Fn op) {
using I = typename Seq::value_type;
using O = decltype(op(I{}));
constexpr size_t N = std::tuple_size<Seq>::value;
std::array<O, N> output;
for (unsigned i = 0; i < N; i++) { output[i] = op(input[i]); }
return output;
}
template <typename S> constexpr S clamp(S value, S low, S high) {
assert(low <= high);
if (value < low) return low;
if (value > high) return high;
return value;
}
using std::abs; // abs overload for builtin types
using xsimd::abs; // provides overload for abs<xsimd::batch>
template <typename... Args> std::string Format(const char *str, const Args &...args) {
auto output = std::string(str);
std::vector<std::string> values = {{args...}};
for (unsigned i = 0; i < values.size(); i++) {
auto key = "{" + std::to_string(i) + "}";
auto value = values[i];
while (true) {
size_t where = output.find(key);
if (where == output.npos) break;
output.replace(where, key.length(), value);
}
}
return output;
}
template <class> struct next_size;
template <class T> using next_size_t = typename next_size<T>::type;
template <class T> struct Tag { using type = T; };
template <> struct next_size<int8_t> : Tag<int16_t> {};
template <> struct next_size<int16_t> : Tag<int32_t> {};
template <> struct next_size<int32_t> : Tag<int64_t> {};
template <> struct next_size<uint8_t> : Tag<uint16_t> {};
template <> struct next_size<uint16_t> : Tag<uint32_t> {};
template <> struct next_size<uint32_t> : Tag<uint64_t> {};
} // namespace quicktex
} // namespace quicktex::util

View File

@ -21,38 +21,48 @@
#include <type_traits>
namespace quicktex::util {
// Thanks dkavolis
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator~(E a) noexcept -> E {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator~(E a) noexcept -> E {
using Base = std::underlying_type_t<E>;
return static_cast<E>(~static_cast<Base>(a));
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator|(E a, E b) noexcept -> E {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator|(E a, E b) noexcept -> E {
using Base = std::underlying_type_t<E>;
return static_cast<E>(static_cast<Base>(a) | static_cast<Base>(b));
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator&(E a, E b) noexcept -> E {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator&(E a, E b) noexcept -> E {
using Base = std::underlying_type_t<E>;
return static_cast<E>(static_cast<Base>(a) & static_cast<Base>(b));
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator^(E a, E b) noexcept -> E {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator^(E a, E b) noexcept -> E {
using Base = std::underlying_type_t<E>;
return static_cast<E>(static_cast<Base>(a) ^ static_cast<Base>(b));
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator|=(E& a, E b) noexcept -> E& {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator|=(E& a, E b) noexcept -> E& {
a = a | b;
return a;
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator&=(E& a, E b) noexcept -> E& {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator&=(E& a, E b) noexcept -> E& {
a = a & b;
return a;
}
template <typename E, typename = std::enable_if_t<std::is_enum_v<E>>> constexpr inline auto operator^=(E& a, E b) noexcept -> E& {
template <typename E> requires std::is_enum_v<E>
constexpr inline auto operator^=(E& a, E b) noexcept -> E& {
a = a ^ b;
return a;
}
}
} // namespace quicktex::util

43
quicktex/util/math.h Normal file
View File

@ -0,0 +1,43 @@
/* Quicktex Texture Compression Library
Copyright (C) 2021-2022 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich <richgel99@gmail.com>
and licenced under the public domain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cassert>
#include <cstdint>
#include <functional>
#include <limits>
#include <numeric>
#include <string>
#include <type_traits>
#include <vector>
#include "xsimd/xsimd.hpp"
namespace quicktex {
using std::abs; // abs overload for builtin types
using xsimd::abs; // abs overload for xsimd buffers
template <typename S> constexpr S clamp(S value, S low, S high) {
assert(low <= high);
if (value < low) return low;
if (value > high) return high;
return value;
}
} // namespace quicktex

104
quicktex/util/ranges.h Normal file
View File

@ -0,0 +1,104 @@
/* Quicktex Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich <richgel99@gmail.com>
and licenced under the public domain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <numeric>
#include <string>
#include <type_traits>
#include <vector>
#include "xsimd/xsimd.hpp"
namespace quicktex::util {
// std::ranges::range is currently not usable by default in libc++
template <class T>
concept range = requires(T &t) {
std::begin(t);
std::end(t);
};
template <class T>
concept sized_range = range<T> && requires(T &t) { std::size(t); };
template <class T>
requires range<T>
size_t distance(T range) {
return std::distance(range.begin(), range.end());
}
template <typename T> class const_iterator {
public:
typedef long long difference_type;
typedef T value_type;
const_iterator() : _value(T{}), _index(0) {}
const_iterator(T value, size_t index = 0) : _value(value), _index(index) {}
const_iterator &operator++() {
_index++;
return *this;
}
const_iterator operator++(int) {
const_iterator old = *this;
_index++;
return old;
}
const_iterator &operator--() {
_index++;
return *this;
}
const_iterator operator--(int) {
const_iterator old = *this;
_index++;
return old;
}
T operator*() const { return _value; }
difference_type operator-(const_iterator rhs) const { return (difference_type)_index - rhs._index; }
const_iterator operator+(size_t rhs) const { return const_iterator(rhs + _index); }
const_iterator operator-(size_t rhs) const { return const_iterator(rhs - _index); }
friend bool operator==(const const_iterator &lhs, const const_iterator &rhs) {
return (lhs._value == rhs._value) && (lhs._index == rhs._index);
}
private:
T _value;
size_t _index;
};
template <typename Seq, typename Fn> constexpr auto map(const Seq &input, Fn op) {
using I = typename Seq::value_type;
using O = decltype(op(I{}));
constexpr size_t N = std::tuple_size<Seq>::value;
std::array<O, N> output;
for (unsigned i = 0; i < N; i++) { output[i] = op(input[i]); }
return output;
}
} // namespace quicktex::util

View File

@ -21,13 +21,14 @@
#include <array>
#include <type_traits>
#include <xsimd/xsimd.hpp>
#include "util.h"
#include "util/math.h"
#include "util/types.h"
#include "xsimd/xsimd.hpp"
template <typename T> using requires_arch = xsimd::kernel::requires_arch<T>;
namespace quicktex::simd {
namespace quicktex::util::simd {
namespace kernel {
@ -93,4 +94,4 @@ template <class A, class T> inline next_size_t<T> whadd(xsimd::batch<T, A> const
return kernel::whadd(arg, A{});
}
} // namespace quicktex::simd
} // namespace quicktex::util::simd

35
quicktex/util/types.h Normal file
View File

@ -0,0 +1,35 @@
/* Quicktex Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich <richgel99@gmail.com>
and licenced under the public domain
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <cstdint>
namespace quicktex::util {
template <class> struct next_size;
template <class T> using next_size_t = typename next_size<T>::type;
template <class T> struct next_size_tag { using type = T; };
template <> struct next_size<int8_t> : next_size_tag<int16_t> {};
template <> struct next_size<int16_t> : next_size_tag<int32_t> {};
template <> struct next_size<int32_t> : next_size_tag<int64_t> {};
template <> struct next_size<uint8_t> : next_size_tag<uint16_t> {};
template <> struct next_size<uint16_t> : next_size_tag<uint32_t> {};
template <> struct next_size<uint32_t> : next_size_tag<uint64_t> {};
} // namespace quicktex::util