diff --git a/src/BC1/BC1Encoder.cpp b/src/BC1/BC1Encoder.cpp index b45bbb6..fd699cd 100644 --- a/src/BC1/BC1Encoder.cpp +++ b/src/BC1/BC1Encoder.cpp @@ -39,6 +39,8 @@ #include "SingleColorTable.h" namespace rgbcx { +using namespace BC1; + using InterpolatorPtr = std::shared_ptr; using Hash = uint16_t; using BlockMetrics = Color4x4::BlockMetrics; @@ -47,7 +49,8 @@ using ColorMode = BC1Encoder::ColorMode; // constructors BC1Encoder::BC1Encoder(InterpolatorPtr interpolator) : _interpolator(interpolator) { - _flags = Flags::UseFullMSEEval | Flags::TwoLeastSquaresPasses | Flags::UseLikelyTotalOrderings | Flags::Use3ColorBlocks; + _flags = + Flags::UseFullMSEEval | Flags::TwoLeastSquaresPasses | Flags::UseLikelyTotalOrderings | Flags::Use3ColorBlocks | Flags::Use3ColorBlocksForBlackPixels; _error_mode = ErrorMode::Full; _endpoint_mode = EndpointMode::PCA; _orderings4 = 16; @@ -123,7 +126,20 @@ void BC1Encoder::EncodeBlock(Color4x4 pixels, BC1Block *dest) const { } } - if (trial_result.error < result.error) { result = trial_result; }; + if (trial_result.error < result.error) { result = trial_result; } + } + + // try for 3-color block with black + if (result.error > 0 && (bool)(_flags & Flags::Use3ColorBlocksForBlackPixels) && metrics.has_black && !metrics.max.IsBlack()) { + EncodeResults trial_result; + BlockMetrics metrics_no_black = pixels.GetMetrics(true); + + FindEndpoints(pixels, trial_result, metrics_no_black, EndpointMode::PCA, true); + FindSelectors(pixels, trial_result, ErrorMode::Full); + RefineBlockLS(pixels, trial_result, metrics_no_black, ErrorMode::Full, total_ls_passes); + + if (trial_result.error < result.error) { + result = trial_result; } } WriteBlock(result, dest); @@ -230,8 +246,6 @@ void BC1Encoder::WriteBlock(EncodeResults &block, BC1Block *dest) const { if (block.color_mode == ColorMode::ThreeColor) { assert(selectors[y][x] != 3); } } - // if (block.color_mode != ColorMode::ThreeColor) return; - dest->SetLowColor(color0); dest->SetHighColor(color1); dest->PackSelectors(selectors); @@ -267,7 +281,7 @@ void BC1Encoder::FindEndpointsSingleColor(EncodeResults &block, Color4x4 &pixels } } -void BC1Encoder::FindEndpoints(Color4x4 pixels, EncodeResults &block, const BlockMetrics &metrics, EndpointMode endpoint_mode) const { +void BC1Encoder::FindEndpoints(Color4x4 pixels, EncodeResults &block, const BlockMetrics &metrics, EndpointMode endpoint_mode, bool ignore_black) const { if (metrics.is_greyscale) { // specialized greyscale case const unsigned fr = pixels.Get(0).r; @@ -407,15 +421,16 @@ void BC1Encoder::FindEndpoints(Color4x4 pixels, EncodeResults &block, const Bloc auto max = Vector4::FromColorRGB(metrics.max); auto avg = Vector4::FromColorRGB(metrics.avg); - std::array colors; - Vector4 axis = {306, 601, 117}; // Luma vector Matrix4x4 covariance = Matrix4x4::Identity(); const unsigned total_power_iters = (_flags & Flags::Use6PowerIters) != Flags::None ? 6 : 4; for (unsigned i = 0; i < 16; i++) { - colors[i] = Vector4::FromColorRGB(pixels.Get(i)); - Vector4 diff = colors[i] - avg; + auto val = pixels.Get(i); + if (ignore_black && val.IsBlack()) continue; + + auto colorVec = Vector4::FromColorRGB(val); + Vector4 diff = colorVec - avg; for (unsigned c1 = 0; c1 < 3; c1++) { for (unsigned c2 = c1; c2 < 3; c2++) { covariance[c1][c2] += (diff[c1] * diff[c2]); @@ -449,9 +464,13 @@ void BC1Encoder::FindEndpoints(Color4x4 pixels, EncodeResults &block, const Bloc unsigned min_index = 0, max_index = 0; for (unsigned i = 0; i < 16; i++) { + auto val = pixels.Get(i); + if (ignore_black && val.IsBlack()) continue; + + auto colorVec = Vector4::FromColorRGB(val); // since axis is constant here, I dont think its magnitude actually matters, // since we only care about the min or max dot product - float dot = colors[i].Dot(axis); + float dot = colorVec.Dot(axis); if (dot > max_dot) { max_dot = dot; max_index = i; @@ -479,9 +498,11 @@ template void BC1Encoder::FindSelectors(Color4x4 &pixels, EncodeRe std::array color_vectors; if (color_count == 4) { - color_vectors = {(Vector4Int)colors[0], (Vector4Int)colors[2], (Vector4Int)colors[3], (Vector4Int)colors[1]}; + color_vectors = {Vector4Int::FromColorRGB(colors[0]), Vector4Int::FromColorRGB(colors[2]), Vector4Int::FromColorRGB(colors[3]), + Vector4Int::FromColorRGB(colors[1])}; } else { - color_vectors = {(Vector4Int)colors[0], (Vector4Int)colors[2], (Vector4Int)colors[1], (Vector4Int)colors[3]}; + color_vectors = {Vector4Int::FromColorRGB(colors[0]), Vector4Int::FromColorRGB(colors[2]), Vector4Int::FromColorRGB(colors[1]), + Vector4Int::FromColorRGB(colors[3])}; } unsigned total_error = 0; @@ -545,7 +566,7 @@ template void BC1Encoder::FindSelectors(Color4x4 &pixels, EncodeRe for (unsigned i = 0; i < 16; i++) { unsigned best_error = UINT_MAX; uint8_t best_sel = 0; - Vector4Int pixel_vector = (Vector4Int)pixels.Get(i); + Vector4Int pixel_vector = Vector4Int::FromColorRGB(pixels.Get(i)); // exhasustively check every pixel's distance from each color, and calculate the error for (uint8_t j = 0; j < max_sel; j++) { diff --git a/src/BC1/BC1Encoder.h b/src/BC1/BC1Encoder.h index 40b5f70..ecc466e 100644 --- a/src/BC1/BC1Encoder.h +++ b/src/BC1/BC1Encoder.h @@ -134,10 +134,10 @@ class BC1Encoder final : 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 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); + const BC1::MatchListPtr _single_match5 = BC1::SingleColorTable<5, 4>(_interpolator); + const BC1::MatchListPtr _single_match6 = BC1::SingleColorTable<6, 4>(_interpolator); + const BC1::MatchListPtr _single_match5_half = BC1::SingleColorTable<5, 3>(_interpolator); + const BC1::MatchListPtr _single_match6_half = BC1::SingleColorTable<6, 3>(_interpolator); Flags _flags; ErrorMode _error_mode; @@ -149,7 +149,7 @@ class BC1Encoder final : public BlockEncoder { void WriteBlockSolid(Color color, BC1Block *dest) const; void WriteBlock(EncodeResults &block, BC1Block *dest) const; - void FindEndpoints(Color4x4 pixels, EncodeResults &block, const BlockMetrics &metrics, EndpointMode endpoint_mode) const; + void FindEndpoints(Color4x4 pixels, EncodeResults &block, const BlockMetrics &metrics, EndpointMode endpoint_mode, bool ignore_black = false) const; void FindEndpointsSingleColor(EncodeResults &block, Color color, bool is_3color = false) const; void FindEndpointsSingleColor(EncodeResults &block, Color4x4 &pixels, Color color, bool is_3color) const; diff --git a/src/BC1/ClusterFit.h b/src/BC1/ClusterFit.h deleted file mode 100644 index 691bf89..0000000 --- a/src/BC1/ClusterFit.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Python-rgbcx Texture Compression Library - Copyright (C) 2021 Andrew Cassidy - Partially derived from rgbcx.h written by Richard Geldreich - 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 . - */ - -#pragma once - -namespace rgbcx { - -void ComputeEndpoints() - -} // namespace rgbcx::ClusterFit \ No newline at end of file diff --git a/src/BC1/Histogram.h b/src/BC1/Histogram.h index 613fd68..410d553 100644 --- a/src/BC1/Histogram.h +++ b/src/BC1/Histogram.h @@ -30,7 +30,7 @@ #include "../Vector4.h" #include "../util.h" -namespace rgbcx { +namespace rgbcx::BC1 { template class Histogram { public: using Hash = uint16_t; diff --git a/src/BC1/OrderTable.cpp b/src/BC1/OrderTable.cpp index 1388836..1bfcdb7 100644 --- a/src/BC1/OrderTable.cpp +++ b/src/BC1/OrderTable.cpp @@ -23,7 +23,7 @@ #include "../Vector4.h" -namespace rgbcx { +namespace rgbcx::BC1 { using Hash = uint16_t; template <> std::atomic OrderTable<3>::generated = false; diff --git a/src/BC1/OrderTable.h b/src/BC1/OrderTable.h index b94c9a3..c5d6e8c 100644 --- a/src/BC1/OrderTable.h +++ b/src/BC1/OrderTable.h @@ -29,7 +29,7 @@ #include "../Vector4.h" #include "Histogram.h" -namespace rgbcx { +namespace rgbcx::BC1 { template class OrderTable { public: static constexpr unsigned HashCount = 1 << ((N - 1) * 4); // 16**(N-1) diff --git a/src/BC1/SingleColorTable.h b/src/BC1/SingleColorTable.h index 63200df..ae85507 100644 --- a/src/BC1/SingleColorTable.h +++ b/src/BC1/SingleColorTable.h @@ -26,7 +26,7 @@ #include "../Interpolator.h" #include "../util.h" -namespace rgbcx { +namespace rgbcx::BC1 { struct BC1MatchEntry { uint8_t high; diff --git a/src/BlockEncoder.h b/src/BlockEncoder.h index bf78fab..5a0710a 100644 --- a/src/BlockEncoder.h +++ b/src/BlockEncoder.h @@ -61,6 +61,8 @@ template class BlockEncoder { unsigned top_left = pixel_x + (pixel_y * image_width); auto src = DecodedBlock(&decoded[top_left], (int)image_width); +// if (pixel_x != 684 || pixel_y != 492) continue; + EncodeBlock(src, &blocks[x + block_width * y]); } }