diff --git a/src/BC1/BC1Encoder.cpp b/src/BC1/BC1Encoder.cpp index d9c302b..afbbfdf 100644 --- a/src/BC1/BC1Encoder.cpp +++ b/src/BC1/BC1Encoder.cpp @@ -187,15 +187,14 @@ void BC1Encoder::EncodeBlockSingleColor(Color color, BC1Block *dest) const { bool using_3color = false; // why is there no subscript operator for shared_ptr - - auto match_r = _single_match5[color.r]; - auto match_g = _single_match6[color.g]; - auto match_b = _single_match5[color.b]; + BC1MatchEntry match_r = _single_match5->at(color.r); + BC1MatchEntry match_g = _single_match6->at(color.g); + BC1MatchEntry match_b = _single_match5->at(color.b); if ((_flags & (Flags::Use3ColorBlocks | Flags::Use3ColorBlocksForBlackPixels)) != Flags::None) { - auto match_r_half = _single_match5_half[color.r]; - auto match_g_half = _single_match6_half[color.g]; - auto match_b_half = _single_match5_half[color.b]; + BC1MatchEntry match_r_half = _single_match5_half->at(color.r); + BC1MatchEntry match_g_half = _single_match6_half->at(color.g); + BC1MatchEntry match_b_half = _single_match5_half->at(color.b); const unsigned err4 = match_r.error + match_g.error + match_b.error; const unsigned err3 = match_r_half.error + match_g_half.error + match_b_half.error; diff --git a/src/BC1/BC1Encoder.h b/src/BC1/BC1Encoder.h index b301df7..0cca648 100644 --- a/src/BC1/BC1Encoder.h +++ b/src/BC1/BC1Encoder.h @@ -36,7 +36,7 @@ namespace rgbcx { -class BC1Encoder : public BlockEncoder { +class BC1Encoder final : public BlockEncoder { public: using InterpolatorPtr = std::shared_ptr; @@ -99,11 +99,6 @@ class BC1Encoder : public BlockEncoder { EndpointSearchRoundsMask = 1023U << EndpointSearchRoundsShift, }; - BC1Encoder(InterpolatorPtr interpolator); - - void EncodeBlock(Color4x4 pixels, BC1Block *dest) const override; - - private: // Unpacked BC1 block with metadata struct EncodeResults { Color low; @@ -114,6 +109,11 @@ class BC1Encoder : public BlockEncoder { unsigned error = UINT_MAX; }; + BC1Encoder(InterpolatorPtr interpolator); + + void EncodeBlock(Color4x4 pixels, BC1Block *dest) const override; + + private: using Hash = uint16_t; using BlockMetrics = Color4x4::BlockMetrics; @@ -123,10 +123,10 @@ class BC1Encoder : public BlockEncoder { // Each entry includes a high and low pair that best reproduces the 8-bit index as well as possible, // with an included error value // these depend on the interpolator - const SingleColorTable<5, 4> _single_match5 = SingleColorTable<5, 4>(_interpolator); - const SingleColorTable<6, 4> _single_match6 = SingleColorTable<6, 4>(_interpolator); - const SingleColorTable<5, 3> _single_match5_half = SingleColorTable<5, 3>(_interpolator); - const SingleColorTable<6, 3> _single_match6_half = SingleColorTable<6, 3>(_interpolator); + const MatchListPtr _single_match5 = SingleColorTable<5, 4>(_interpolator); + const MatchListPtr _single_match6 = SingleColorTable<6, 4>(_interpolator); + const MatchListPtr _single_match5_half = SingleColorTable<5, 3>(_interpolator); + const MatchListPtr _single_match6_half = SingleColorTable<6, 3>(_interpolator); Flags _flags; unsigned _search_rounds; @@ -145,7 +145,7 @@ class BC1Encoder : public BlockEncoder { unsigned FindSelectors4(Color4x4 pixels, BC1Encoder::EncodeResults &block, bool use_err) const; bool ComputeEndpointsLS(Color4x4 pixels, EncodeResults &block, BlockMetrics metrics, bool is_3color, bool use_black) const; -/* bool ComputeEndpointsLS(Color4x4 pixels, EncodeResults &block, BlockMetrics metrics, Hash hash, Vector4 &matrix, std::array &sums, - bool is_3color, bool use_black) const;*/ + /* bool ComputeEndpointsLS(Color4x4 pixels, EncodeResults &block, BlockMetrics metrics, Hash hash, Vector4 &matrix, std::array &sums, + bool is_3color, bool use_black) const;*/ }; } // namespace rgbcx diff --git a/src/BC1/SingleColorTable.h b/src/BC1/SingleColorTable.h index c0b49af..d439b04 100644 --- a/src/BC1/SingleColorTable.h +++ b/src/BC1/SingleColorTable.h @@ -33,75 +33,60 @@ namespace rgbcx { * @tparam B Number of bits (5 or 6) * @tparam N Number of colors (3 or 4) */ -template class SingleColorTable { - public: - struct MatchEntry { - uint8_t high; - uint8_t low; - uint8_t error; - }; +struct BC1MatchEntry { + uint8_t high; + uint8_t low; + uint8_t error; +}; - using MatchList = std::array; - using MatchListPtr = std::shared_ptr; - using InterpolatorPtr = std::shared_ptr; +using MatchList = std::array; +using MatchListPtr = std::shared_ptr; +using InterpolatorPtr = std::shared_ptr; - SingleColorTable(InterpolatorPtr interpolator) { - static_assert((B == 5 && Size == 32) || (B == 6 && Size == 64)); - static_assert(N == 4 || N == 3); +template MatchListPtr SingleColorTable(InterpolatorPtr interpolator) { + constexpr size_t Size = 1 << B; + MatchListPtr _matches = std::make_shared(); - bool ideal = interpolator->IsIdeal(); - bool use_8bit = interpolator->CanInterpolate8Bit(); + static_assert((B == 5 && Size == 32) || (B == 6 && Size == 64)); + static_assert(N == 4 || N == 3); - for (unsigned i = 0; i < 256; i++) { - unsigned error = 256; + bool ideal = interpolator->IsIdeal(); + bool use_8bit = interpolator->CanInterpolate8Bit(); - // TODO: Can probably avoid testing for values that definitely wont yield good results, - // e.g. low8 and high8 both much smaller or larger than index - for (uint8_t low = 0; low < Size; low++) { - uint8_t low8 = (B == 5) ? scale5To8(low) : scale6To8(low); + for (unsigned i = 0; i < 256; i++) { + unsigned error = 256; - for (uint8_t high = 0; high < Size; high++) { - uint8_t high8 = (B == 5) ? scale5To8(high) : scale6To8(high); - uint8_t value; + // TODO: Can probably avoid testing for values that definitely wont yield good results, + // e.g. low8 and high8 both much smaller or larger than index + for (uint8_t low = 0; low < Size; low++) { + uint8_t low8 = (B == 5) ? scale5To8(low) : scale6To8(low); - if (use_8bit) { - value = interpolator->Interpolate8(high8, low8); - } else { - value = (B == 5) ? interpolator->Interpolate5(high, low) : interpolator->Interpolate6(high, low); - } + for (uint8_t high = 0; high < Size; high++) { + uint8_t high8 = (B == 5) ? scale5To8(high) : scale6To8(high); + uint8_t value; - unsigned new_error = iabs(value - (int)i); + if (use_8bit) { + value = interpolator->Interpolate8(high8, low8); + } else { + value = (B == 5) ? interpolator->Interpolate5(high, low) : interpolator->Interpolate6(high, low); + } - // We only need to factor in 3% error in BC1 ideal mode. - if (ideal) new_error += (iabs(high8 - (int)low8) * 3) / 100; + unsigned new_error = iabs(value - (int)i); - if ((new_error < error) || (new_error == error && low == high)) { - assert(new_error <= UINT8_MAX); + // We only need to factor in 3% error in BC1 ideal mode. + if (ideal) new_error += (iabs(high8 - (int)low8) * 3) / 100; - (*_matches)[i].low = (uint8_t)low; - (*_matches)[i].high = (uint8_t)high; - (*_matches)[i].error = (uint8_t)new_error; + if ((new_error < error) || (new_error == error && low == high)) { + assert(new_error <= UINT8_MAX); - error = new_error; - } + (*_matches)[i].low = (uint8_t)low; + (*_matches)[i].high = (uint8_t)high; + (*_matches)[i].error = (uint8_t)new_error; + + error = new_error; } } } } - - MatchEntry operator[](size_t index) const { - assert(index <= UINT8_MAX); - return (*_matches)[index]; - } - MatchEntry &operator[](size_t index) { - assert(index <= UINT8_MAX); - return (*_matches)[index]; - } - - private: - static inline constexpr size_t Size = 1 << B; - - MatchListPtr _matches = std::make_shared(); -}; - +} } // namespace rgbcx \ No newline at end of file