mirror of
https://github.com/drewcassidy/quicktex.git
synced 2024-09-13 06:37:34 +00:00
In hindsight, SingleColorTable doesnt need to be a class at all
This commit is contained in:
parent
b57a3d2561
commit
ab752e51b6
@ -187,15 +187,14 @@ void BC1Encoder::EncodeBlockSingleColor(Color color, BC1Block *dest) const {
|
|||||||
bool using_3color = false;
|
bool using_3color = false;
|
||||||
|
|
||||||
// why is there no subscript operator for shared_ptr<array>
|
// why is there no subscript operator for shared_ptr<array>
|
||||||
|
BC1MatchEntry match_r = _single_match5->at(color.r);
|
||||||
auto match_r = _single_match5[color.r];
|
BC1MatchEntry match_g = _single_match6->at(color.g);
|
||||||
auto match_g = _single_match6[color.g];
|
BC1MatchEntry match_b = _single_match5->at(color.b);
|
||||||
auto match_b = _single_match5[color.b];
|
|
||||||
|
|
||||||
if ((_flags & (Flags::Use3ColorBlocks | Flags::Use3ColorBlocksForBlackPixels)) != Flags::None) {
|
if ((_flags & (Flags::Use3ColorBlocks | Flags::Use3ColorBlocksForBlackPixels)) != Flags::None) {
|
||||||
auto match_r_half = _single_match5_half[color.r];
|
BC1MatchEntry match_r_half = _single_match5_half->at(color.r);
|
||||||
auto match_g_half = _single_match6_half[color.g];
|
BC1MatchEntry match_g_half = _single_match6_half->at(color.g);
|
||||||
auto match_b_half = _single_match5_half[color.b];
|
BC1MatchEntry match_b_half = _single_match5_half->at(color.b);
|
||||||
|
|
||||||
const unsigned err4 = match_r.error + match_g.error + match_b.error;
|
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;
|
const unsigned err3 = match_r_half.error + match_g_half.error + match_b_half.error;
|
||||||
|
@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
namespace rgbcx {
|
namespace rgbcx {
|
||||||
|
|
||||||
class BC1Encoder : public BlockEncoder<BC1Block, 4, 4> {
|
class BC1Encoder final : public BlockEncoder<BC1Block, 4, 4> {
|
||||||
public:
|
public:
|
||||||
using InterpolatorPtr = std::shared_ptr<Interpolator>;
|
using InterpolatorPtr = std::shared_ptr<Interpolator>;
|
||||||
|
|
||||||
@ -99,11 +99,6 @@ class BC1Encoder : public BlockEncoder<BC1Block, 4, 4> {
|
|||||||
EndpointSearchRoundsMask = 1023U << EndpointSearchRoundsShift,
|
EndpointSearchRoundsMask = 1023U << EndpointSearchRoundsShift,
|
||||||
};
|
};
|
||||||
|
|
||||||
BC1Encoder(InterpolatorPtr interpolator);
|
|
||||||
|
|
||||||
void EncodeBlock(Color4x4 pixels, BC1Block *dest) const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Unpacked BC1 block with metadata
|
// Unpacked BC1 block with metadata
|
||||||
struct EncodeResults {
|
struct EncodeResults {
|
||||||
Color low;
|
Color low;
|
||||||
@ -114,6 +109,11 @@ class BC1Encoder : public BlockEncoder<BC1Block, 4, 4> {
|
|||||||
unsigned error = UINT_MAX;
|
unsigned error = UINT_MAX;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
BC1Encoder(InterpolatorPtr interpolator);
|
||||||
|
|
||||||
|
void EncodeBlock(Color4x4 pixels, BC1Block *dest) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
using Hash = uint16_t;
|
using Hash = uint16_t;
|
||||||
using BlockMetrics = Color4x4::BlockMetrics;
|
using BlockMetrics = Color4x4::BlockMetrics;
|
||||||
|
|
||||||
@ -123,10 +123,10 @@ class BC1Encoder : public BlockEncoder<BC1Block, 4, 4> {
|
|||||||
// Each entry includes a high and low pair that best reproduces the 8-bit index as well as possible,
|
// Each entry includes a high and low pair that best reproduces the 8-bit index as well as possible,
|
||||||
// with an included error value
|
// with an included error value
|
||||||
// these depend on the interpolator
|
// these depend on the interpolator
|
||||||
const SingleColorTable<5, 4> _single_match5 = SingleColorTable<5, 4>(_interpolator);
|
const MatchListPtr _single_match5 = SingleColorTable<5, 4>(_interpolator);
|
||||||
const SingleColorTable<6, 4> _single_match6 = SingleColorTable<6, 4>(_interpolator);
|
const MatchListPtr _single_match6 = SingleColorTable<6, 4>(_interpolator);
|
||||||
const SingleColorTable<5, 3> _single_match5_half = SingleColorTable<5, 3>(_interpolator);
|
const MatchListPtr _single_match5_half = SingleColorTable<5, 3>(_interpolator);
|
||||||
const SingleColorTable<6, 3> _single_match6_half = SingleColorTable<6, 3>(_interpolator);
|
const MatchListPtr _single_match6_half = SingleColorTable<6, 3>(_interpolator);
|
||||||
|
|
||||||
Flags _flags;
|
Flags _flags;
|
||||||
unsigned _search_rounds;
|
unsigned _search_rounds;
|
||||||
@ -145,7 +145,7 @@ class BC1Encoder : public BlockEncoder<BC1Block, 4, 4> {
|
|||||||
unsigned FindSelectors4(Color4x4 pixels, BC1Encoder::EncodeResults &block, bool use_err) const;
|
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, bool is_3color, bool use_black) const;
|
||||||
/* bool ComputeEndpointsLS(Color4x4 pixels, EncodeResults &block, BlockMetrics metrics, Hash hash, Vector4 &matrix, std::array<Vector4, 17> &sums,
|
/* bool ComputeEndpointsLS(Color4x4 pixels, EncodeResults &block, BlockMetrics metrics, Hash hash, Vector4 &matrix, std::array<Vector4, 17> &sums,
|
||||||
bool is_3color, bool use_black) const;*/
|
bool is_3color, bool use_black) const;*/
|
||||||
};
|
};
|
||||||
} // namespace rgbcx
|
} // namespace rgbcx
|
||||||
|
@ -33,75 +33,60 @@ namespace rgbcx {
|
|||||||
* @tparam B Number of bits (5 or 6)
|
* @tparam B Number of bits (5 or 6)
|
||||||
* @tparam N Number of colors (3 or 4)
|
* @tparam N Number of colors (3 or 4)
|
||||||
*/
|
*/
|
||||||
template <size_t B, size_t N> class SingleColorTable {
|
struct BC1MatchEntry {
|
||||||
public:
|
uint8_t high;
|
||||||
struct MatchEntry {
|
uint8_t low;
|
||||||
uint8_t high;
|
uint8_t error;
|
||||||
uint8_t low;
|
};
|
||||||
uint8_t error;
|
|
||||||
};
|
|
||||||
|
|
||||||
using MatchList = std::array<MatchEntry, 256>;
|
using MatchList = std::array<BC1MatchEntry, 256>;
|
||||||
using MatchListPtr = std::shared_ptr<MatchList>;
|
using MatchListPtr = std::shared_ptr<MatchList>;
|
||||||
using InterpolatorPtr = std::shared_ptr<Interpolator>;
|
using InterpolatorPtr = std::shared_ptr<Interpolator>;
|
||||||
|
|
||||||
SingleColorTable(InterpolatorPtr interpolator) {
|
template <size_t B, size_t N> MatchListPtr SingleColorTable(InterpolatorPtr interpolator) {
|
||||||
static_assert((B == 5 && Size == 32) || (B == 6 && Size == 64));
|
constexpr size_t Size = 1 << B;
|
||||||
static_assert(N == 4 || N == 3);
|
MatchListPtr _matches = std::make_shared<MatchList>();
|
||||||
|
|
||||||
bool ideal = interpolator->IsIdeal();
|
static_assert((B == 5 && Size == 32) || (B == 6 && Size == 64));
|
||||||
bool use_8bit = interpolator->CanInterpolate8Bit();
|
static_assert(N == 4 || N == 3);
|
||||||
|
|
||||||
for (unsigned i = 0; i < 256; i++) {
|
bool ideal = interpolator->IsIdeal();
|
||||||
unsigned error = 256;
|
bool use_8bit = interpolator->CanInterpolate8Bit();
|
||||||
|
|
||||||
// TODO: Can probably avoid testing for values that definitely wont yield good results,
|
for (unsigned i = 0; i < 256; i++) {
|
||||||
// e.g. low8 and high8 both much smaller or larger than index
|
unsigned error = 256;
|
||||||
for (uint8_t low = 0; low < Size; low++) {
|
|
||||||
uint8_t low8 = (B == 5) ? scale5To8(low) : scale6To8(low);
|
|
||||||
|
|
||||||
for (uint8_t high = 0; high < Size; high++) {
|
// TODO: Can probably avoid testing for values that definitely wont yield good results,
|
||||||
uint8_t high8 = (B == 5) ? scale5To8(high) : scale6To8(high);
|
// e.g. low8 and high8 both much smaller or larger than index
|
||||||
uint8_t value;
|
for (uint8_t low = 0; low < Size; low++) {
|
||||||
|
uint8_t low8 = (B == 5) ? scale5To8(low) : scale6To8(low);
|
||||||
|
|
||||||
if (use_8bit) {
|
for (uint8_t high = 0; high < Size; high++) {
|
||||||
value = interpolator->Interpolate8(high8, low8);
|
uint8_t high8 = (B == 5) ? scale5To8(high) : scale6To8(high);
|
||||||
} else {
|
uint8_t value;
|
||||||
value = (B == 5) ? interpolator->Interpolate5(high, low) : interpolator->Interpolate6(high, low);
|
|
||||||
}
|
|
||||||
|
|
||||||
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.
|
unsigned new_error = iabs(value - (int)i);
|
||||||
if (ideal) new_error += (iabs(high8 - (int)low8) * 3) / 100;
|
|
||||||
|
|
||||||
if ((new_error < error) || (new_error == error && low == high)) {
|
// We only need to factor in 3% error in BC1 ideal mode.
|
||||||
assert(new_error <= UINT8_MAX);
|
if (ideal) new_error += (iabs(high8 - (int)low8) * 3) / 100;
|
||||||
|
|
||||||
(*_matches)[i].low = (uint8_t)low;
|
if ((new_error < error) || (new_error == error && low == high)) {
|
||||||
(*_matches)[i].high = (uint8_t)high;
|
assert(new_error <= UINT8_MAX);
|
||||||
(*_matches)[i].error = (uint8_t)new_error;
|
|
||||||
|
|
||||||
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<MatchList>();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace rgbcx
|
} // namespace rgbcx
|
Loading…
Reference in New Issue
Block a user