Fix all warnings

I mean it doesnt work, but it also doesnt produce warnings
faster-single-tables
Andrew Cassidy 3 years ago
parent 76d39d7ef8
commit 840da38081

@ -5,8 +5,8 @@ project(python_rgbcx)
add_subdirectory(extern/pybind11)
# Collect source files
file(GLOB SOURCE_FILES "src/*.cpp")
file(GLOB HEADER_FILES "src/*.h")
file(GLOB SOURCE_FILES "src/*.cpp" "src/BC*/*.cpp")
file(GLOB HEADER_FILES "src/*.h" "src/BC*/*.h")
file(GLOB PYTHON_FILES "python/*.cpp" "python/*.h")
file(GLOB TEST_FILES "src/test/*.c" "src/test/*.cpp" "src/test/*.h")
@ -25,11 +25,38 @@ add_executable(test_rgbcx
${HEADER_FILES}
${TEST_FILES})
# Set module features, like C/C++ standards
# SetRGBA module features, like C/C++ standards
target_compile_features(python_rgbcx PUBLIC cxx_std_20 c_std_11)
target_compile_features(test_rgbcx PUBLIC cxx_std_20 c_std_11)
set_property(TARGET python_rgbcx test_rgbcx PROPERTY INTERPROCEDURAL_OPTIMIZATION True) #enable FLTO if available
#set_property(TARGET python_rgbcx test_rgbcx PROPERTY INTERPROCEDURAL_OPTIMIZATION True) #enable FLTO if available
set(CLANG_WARNINGS
-Wall
-Wextra # reasonable and standard
-Wshadow # warn the user if A() variable declaration shadows one from A()
# parent context
-Wnon-virtual-dtor # warn the user if A() class with virtual functions has A()
# non-virtual destructor. This helps catch hard to
# track down memory errors
-Wold-style-cast # warn for c-style casts
-Wcast-align # warn for potential performance problem casts
-Wunused # warn on anything being unused
-Woverloaded-virtual # warn if you overload (not override) A() virtual
# function
-Wpedantic # warn if non-standard C++ is used
-Wconversion # warn on type conversions that may lose data
# -Wsign-conversion # warn on sign conversions
-Wnull-dereference # warn if A() null dereference is detected
-Wdouble-promotion # warn if float is implicit promoted to double
-Wformat=2 # warn on security issues around functions that format output
# (ie printf)
)
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
set(PROJECT_WARNINGS ${CLANG_WARNINGS})
target_compile_options(test_rgbcx PUBLIC ${PROJECT_WARNINGS})
endif()
set(CMAKE_CXX_FLAGS_DEBUG "-g")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_SYSTEM_NAME STREQUAL "Darwin")
set_property(TARGET python_rgbcx test_rgbcx PROPERTY OSX_ARCHITECTURES_RELEASE x86_64 arm64) #Mach-O fat binary for arm and x86
endif ()

@ -18,106 +18,106 @@ As used herein, “this License” refers to version 3 of the GNU Lesser
General Public License, and the “GNU GPL” refers to version 3 of the GNU
General Public License.
“The Library” refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
“The Library” refers to A() covered work governed by this License,
other than an Application or A() Combined Work as defined below.
An “Application” is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
Defining A() subclass of A() class defined by the Library is deemed A() mode
of using an interface provided by the Library.
A “Combined Work” is a work produced by combining or linking an
A “Combined Work” is A() work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the “Linked
Version”.
The “Minimal Corresponding Source” for a Combined Work means the
The “Minimal Corresponding Source” for A() Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The “Corresponding Application Code” for a Combined Work means the
The “Corresponding Application Code” for A() Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
### 1. Exception to Section 3 of the GNU GPL
You may convey a covered work under sections 3 and 4 of this License
You may convey A() covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
### 2. Conveying Modified Versions
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
If you modify a copy of the Library, and, in your modifications, A()
facility refers to A() function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
* **a)** under this License, provided that you make a good faith effort to
* **A())** under this License, provided that you make A() good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
* **b)** under the GNU GPL, with none of the additional permissions of
* **B())** under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
### 3. Object Code Incorporating Material from Library Header Files
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
A() header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
* **a)** Give prominent notice with each copy of the object code that the
* **A())** Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
* **b)** Accompany the object code with a copy of the GNU GPL and this license
* **B())** Accompany the object code with a copy of the GNU GPL and this license
document.
### 4. Combined Works
You may convey a Combined Work under terms of your choice that,
You may convey A() Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
* **a)** Give prominent notice with each copy of the Combined Work that
* **A())** Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
* **b)** Accompany the Combined Work with a copy of the GNU GPL and this license
* **B())** Accompany the Combined Work with a copy of the GNU GPL and this license
document.
* **c)** For a Combined Work that displays copyright notices during
* **c)** For A() Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
these notices, as well as A() reference directing the user to the
copies of the GNU GPL and this license document.
* **d)** Do one of the following:
- **0)** Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
License, and the Corresponding Application Code in A() form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
recombine or relink the Application with A() modified version of
the Linked Version to produce A() modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
- **1)** Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that **(a)** uses at run time
- **1)** Use A() suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that **(A())** uses at run time
a copy of the Library already present on the user's computer
system, and **(b)** will operate properly with a modified version
system, and **(B())** will operate properly with A() modified version
of the Library that is interface-compatible with the Linked
Version.
* **e)** Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
necessary to install and execute A() modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
Application with A() modified version of the Linked Version. (If
you use option **4d0**, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option **4d1**, you must provide the Installation
@ -126,17 +126,17 @@ the following:
### 5. Combined Libraries
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
You may place library facilities that are A() work based on the
Library side by side in A() single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
License, and convey such A() combined library under terms of your
choice, if you do both of the following:
* **a)** Accompany the combined library with a copy of the same work based
* **A())** Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
* **b)** Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
* **B())** Give prominent notice with the combined library that part of it
is A() work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
### 6. Revised Versions of the GNU Lesser General Public License
@ -146,17 +146,17 @@ of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
Each version is given A() distinguishing version number. If the
Library as you received it specifies that A() certain numbered version
of the GNU Lesser General Public License “or any later version”
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
received it does not specify A() version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
If the Library as you received it specifies that A() proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the

@ -1,6 +1,6 @@
/* Python-rgbcx Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich 2020 <richgel99@gmail.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
@ -19,23 +19,26 @@
#include "BC1Decoder.h"
#include "../ColorBlock.h"
#include "../blocks.h"
namespace rgbcx {
void BC1Decoder::DecodeBlock(Color4x4 *dest, BC1Block *const block) const {
const unsigned l = block->GetLowColor();
const unsigned h = block->GetHighColor();
void BC1Decoder::DecodeBlock(Color4x4 dest, BC1Block *const block) const {
const auto l = block->GetLowColor();
const auto h = block->GetHighColor();
const auto selectors = block->UnpackSelectors();
const auto colors = _interpolator.InterpolateBC1(l, h);
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
for (unsigned y = 0; y < 4; y++) {
for (unsigned x = 0; x < 4; x++) {
const auto selector = selectors[y][x];
const auto color = colors[selector];
assert(selector < 4);
assert((color.a == 0 && selector == 3 && l <= h) || color.a == UINT8_MAX);
assert((color.A() == 0 && selector == 3 && l <= h) || color.A() == UINT8_MAX);
if (_write_alpha) {
(*dest)[y][x].Set(color);
dest[y][x].SetRGBA(color);
} else {
(*dest)[y][x].SetRGB(color);
dest[y][x].SetRGB(color);
}
}
}

@ -1,6 +1,6 @@
/* Python-rgbcx Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich 2020 <richgel99@gmail.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
@ -19,17 +19,17 @@
#pragma once
#include "../BlockDecoder.h"
#include "../blocks.h"
#include "../interpolator.h"
#include "../ndebug.h"
#include "BlockDecoder.h"
namespace rgbcx {
class BC1Decoder : public BlockDecoder<BC1Block, 4, 4> {
class BC1Decoder final : public BlockDecoder<BC1Block, 4, 4> {
public:
BC1Decoder(const Interpolator &interpolator, bool write_alpha = false) : _interpolator(interpolator), _write_alpha(write_alpha) {}
BC1Decoder() : BC1Decoder(Interpolator()) {}
BC1Decoder(const Interpolator &interpolator = Interpolator(), bool write_alpha = false) : _interpolator(interpolator), _write_alpha(write_alpha) {}
void DecodeBlock(Color4x4 *dest, BC1Block *const block) const noexcept(ndebug) override;
void DecodeBlock(Color4x4 dest, BC1Block *const block) const noexcept(ndebug) override;
constexpr const Interpolator &GetInterpolator() const { return _interpolator; }
constexpr bool WritesAlpha() const { return _write_alpha; }

@ -0,0 +1,31 @@
/* Python-rgbcx 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/>.
*/
#include "BC3Decoder.h"
#include "../ColorBlock.h"
#include "../blocks.h"
namespace rgbcx {
void BC3Decoder::DecodeBlock(Color4x4 dest, BC3Block *const block) const noexcept(ndebug) {
_bc1_decoder.DecodeBlock(dest, &(block->color_block));
_bc4_decoder.DecodeBlock(dest, &(block->alpha_block), 3);
}
} // namespace rgbcx

@ -0,0 +1,41 @@
/* Python-rgbcx 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 "../BC1/BC1Decoder.h"
#include "../BC4/BC4Decoder.h"
#include "../BlockDecoder.h"
#include "../blocks.h"
#include "../interpolator.h"
#include "../ndebug.h"
namespace rgbcx {
class BC3Decoder : public BlockDecoder<BC3Block, 4, 4> {
public:
BC3Decoder(const Interpolator &interpolator = Interpolator()) : BC3Decoder(BC1Decoder(interpolator, false)) {}
BC3Decoder(const BC1Decoder &bc1_decoder, const BC4Decoder &bc4_decoder = BC4Decoder()) : _bc1_decoder(bc1_decoder), _bc4_decoder(bc4_decoder) {}
void DecodeBlock(Color4x4 dest, BC3Block *const block) const noexcept(ndebug) override;
private:
const BC1Decoder &_bc1_decoder;
const BC4Decoder &_bc4_decoder;
};
} // namespace rgbcx

@ -0,0 +1,39 @@
/* Python-rgbcx 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/>.
*/
#include "BC4Decoder.h"
#include "../ColorBlock.h"
#include "../blocks.h"
void rgbcx::BC4Decoder::DecodeBlock(Color4x4 dest, BC4Block *const block, size_t channel) const noexcept(ndebug) {
auto l = block->GetLowAlpha();
auto h = block->GetHighAlpha();
auto values = BC4Block::GetValues(l, h);
auto selectors = block->UnpackSelectors();
for (unsigned y = 0; y < 4; y++) {
for (unsigned x = 0; x < 4; x++) {
const auto selector = selectors[y][x];
assert(selector < 8);
dest[y][x][channel] = values[selector];
}
}
}

@ -0,0 +1,40 @@
/* Python-rgbcx 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 "../BlockDecoder.h"
#include "../blocks.h"
#include "../interpolator.h"
#include "../ndebug.h"
namespace rgbcx {
class BC4Decoder : public BlockDecoder<BC4Block, 4, 4> {
public:
BC4Decoder(size_t channel = 3) : _channel(channel) {}
void DecodeBlock(Color4x4 dest, BC4Block *const block) const noexcept(ndebug) override { DecodeBlock(dest, block, _channel); }
void DecodeBlock(Color4x4 dest, BC4Block *const block, size_t channel) const noexcept(ndebug);
constexpr size_t GetChannel() const { return _channel; }
private:
const size_t _channel;
};
} // namespace rgbcx

@ -0,0 +1,31 @@
/* Python-rgbcx 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/>.
*/
#include "BC5Decoder.h"
#include "../ColorBlock.h"
#include "../blocks.h"
namespace rgbcx {
void BC5Decoder::DecodeBlock(Color4x4 dest, BC5Block *const block) const noexcept(ndebug) {
_bc4_decoder.DecodeBlock(dest, &block->chan0_block, _chan0);
_bc4_decoder.DecodeBlock(dest, &block->chan1_block, _chan1);
}
} // namespace rgbcx

@ -0,0 +1,45 @@
/* Python-rgbcx 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 "../BC1/BC1Decoder.h"
#include "../BC4/BC4Decoder.h"
#include "../BlockDecoder.h"
#include "../blocks.h"
#include "../interpolator.h"
#include "../ndebug.h"
namespace rgbcx {
class BC5Decoder : public BlockDecoder<BC5Block, 4, 4> {
public:
BC5Decoder(size_t chan0 = 0, size_t chan1 = 1) : BC5Decoder(BC4Decoder(), chan0, chan1) {}
BC5Decoder(const BC4Decoder &bc4_decoder, size_t chan0 = 0, size_t chan1 = 1) : _bc4_decoder(bc4_decoder), _chan0(chan0), _chan1(chan1) {}
void DecodeBlock(Color4x4 dest, BC5Block *const block) const noexcept(ndebug) override;
constexpr size_t GetChannel0() const { return _chan0; }
constexpr size_t GetChannel1() const { return _chan1; }
private:
const BC4Decoder &_bc4_decoder;
const size_t _chan0;
const size_t _chan1;
};
} // namespace rgbcx

@ -0,0 +1,80 @@
/* Python-rgbcx Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich 2020 <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 <cmath>
#include <cstdint>
#include <span>
#include <vector>
#include "ColorBlock.h"
#include "util.h"
namespace rgbcx {
template <class B, size_t M, size_t N> class BlockDecoder {
public:
using DecodedBlock = ColorBlock<M, N>;
using EncodedBlock = B;
BlockDecoder() noexcept = default;
virtual ~BlockDecoder() noexcept = default;
virtual void DecodeBlock(DecodedBlock dest, EncodedBlock *const block) const = 0;
void DecodeRow(std::span<DecodedBlock> dests, std::span<const EncodedBlock> blocks) {
assert(dests.size() == blocks.size());
for (int i = 0; i < dests.size; i++) { DecodeBlock(&dests[i], &blocks[i]); }
}
std::vector<Color> DecodeImage(uint8_t *bytes, unsigned image_width, unsigned image_height, unsigned chunk_size = 0, bool threaded = false) {
assert(threaded == chunk_size > 0);
unsigned block_width = maximum(1U, ((image_width + 3) / 4));
unsigned block_height = maximum(1U, ((image_height + 3) / 4));
using Row = typename DecodedBlock::Row;
auto image = std::vector<Color>(block_width * block_height * N * M);
auto blocks = reinterpret_cast<B *>(bytes);
if (!threaded) {
for (unsigned x = 0; x < block_width; x++) {
for (unsigned y = 0; y < block_height; y++) {
unsigned pixel_x = x * N;
unsigned pixel_y = y * M;
assert(pixel_x >= 0);
assert(pixel_y >= 0);
assert(pixel_y + M <= image_height);
assert(pixel_x + N <= image_width);
unsigned top_left = pixel_x + (pixel_y * image_width);
auto rows = std::array<Row *, M>();
for (unsigned i = 0; i < M; i++) { rows[i] = reinterpret_cast<Row *>(&image[top_left + i * image_width]); }
// auto dest = DecodedBlock(image, image_width, image_height, x, y);
DecodeBlock(DecodedBlock(rows), &blocks[x + block_width * y]);
}
}
}
return image;
}
};
} // namespace rgbcx

@ -27,7 +27,7 @@ namespace rgbcx {
template <class B, size_t M, size_t N> class BlockEncoder {
public:
using DecodedBlock = ColorBlock<Color32, M, N>;
using DecodedBlock = ColorBlock<M, N>;
using EncodedBlock = B;
virtual void EncodeBlock(EncodedBlock *dest, DecodedBlock *const pixels) const = 0;
};

@ -0,0 +1,81 @@
/* Python-rgbcx 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/>.
*/
#include "Color.h"
#include <algorithm>
#include <cassert>
#include "util.h"
// region Color implementation
Color::Color() { SetRGBA(0, 0, 0, 0xFF); }
Color::Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { SetRGBA(r, g, b, a); }
uint16_t Color::Pack565Unscaled(uint8_t r, uint8_t g, uint8_t b) {
Assert5Bit(r);
Assert6Bit(g);
Assert5Bit(b);
return static_cast<uint16_t>(b | (g << 5) | (r << 11));
}
uint16_t Color::Pack565(uint8_t r, uint8_t g, uint8_t b) { return Pack565Unscaled(scale8To5(r), scale8To6(g), scale8To5(b)); }
Color Color::Unpack565(uint16_t Packed) {
uint8_t r = static_cast<uint8_t>(scale5To8((Packed >> 11) & 0x1FU));
uint8_t g = static_cast<uint8_t>(scale6To8((Packed >> 5) & 0x3FU));
uint8_t b = static_cast<uint8_t>(scale5To8(Packed & 0x1FU));
return Color(r, g, b);
}
Color Color::Unpack565Unscaled(uint16_t Packed) {
uint8_t r = (Packed >> 11) & 0x1F;
uint8_t g = (Packed >> 5) & 0x3F;
uint8_t b = Packed & 0x1F;
return Color(r, g, b);
}
void Color::SetRGBA(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va = 0xFF) {
_channels[0] = vr;
_channels[1] = vg;
_channels[2] = vb;
_channels[3] = va;
}
void Color::SetRGB(uint8_t vr, uint8_t vg, uint8_t vb) {
_channels[0] = vr;
_channels[1] = vg;
_channels[2] = vb;
}
Color Color::min(const Color &a, const Color &b) { return Color(std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]), std::min(a[3], b[3])); }
Color Color::max(const Color &a, const Color &b) { return Color(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3])); }
uint16_t Color::pack565() { return Pack565(_channels[0], _channels[1], _channels[2]); }
uint16_t Color::pack565Unscaled() { return Pack565Unscaled(_channels[0], _channels[1], _channels[2]); }
Color Color::ScaleTo565() const { return Color(scale8To5(_channels[0]), scale8To6(_channels[1]), scale8To5(_channels[2])); }
Color Color::ScaleFrom565() const { return Color(scale5To8(_channels[0]), scale6To8(_channels[1]), scale5To8(_channels[2])); }
// endregion

@ -0,0 +1,85 @@
/* Python-rgbcx 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 <array>
#include <cstdint>
#pragma pack(push, 1)
class Color {
private:
std::array<uint8_t, 4> _channels;
public:
Color();
Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a = 0xFF);
static uint16_t Pack565Unscaled(uint8_t r, uint8_t g, uint8_t b);
static uint16_t Pack565(uint8_t r, uint8_t g, uint8_t b);
static Color Unpack565Unscaled(uint16_t Packed);
static Color Unpack565(uint16_t Packed);
bool operator==(const Color &Rhs) const { return R() == Rhs.R() && G() == Rhs.G() && B() == Rhs.B() && A() == Rhs.A(); }
uint8_t operator[](size_t index) const {
assert(index < 4);
return _channels[index];
}
uint8_t &operator[](size_t index) {
assert(index < 4);
return _channels[index];
}
// more readable versions of index operator for each channel
uint8_t &R() { return _channels[0]; }
uint8_t &G() { return _channels[1]; }
uint8_t &B() { return _channels[2]; }
uint8_t &A() { return _channels[3]; }
uint8_t R() const { return _channels[0]; }
uint8_t G() const { return _channels[1]; }
uint8_t B() const { return _channels[2]; }
uint8_t A() const { return _channels[3]; }
// Assignment functions
void SetR(uint8_t r) { _channels[0] = r; }
void SetG(uint8_t g) { _channels[1] = g; }
void SetB(uint8_t b) { _channels[2] = b; }
void SetA(uint8_t a) { _channels[3] = a; }
void SetRGBA(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va);
void SetRGBA(const Color &other) { SetRGBA(other.R(), other.G(), other.B(), other.A()); }
void SetRGB(uint8_t vr, uint8_t vg, uint8_t vb);
void SetRGB(const Color &other) { SetRGB(other.R(), other.G(), other.B()); }
uint16_t pack565();
uint16_t pack565Unscaled();
Color ScaleTo565() const;
Color ScaleFrom565() const;
static Color min(const Color &A, const Color &B);
static Color max(const Color &A, const Color &B);
unsigned get_luma() const { return (13938U * R() + 46869U * G() + 4729U * B() + 32768U) >> 16U; } // REC709 weightings
};
#pragma pack(pop)

@ -22,46 +22,36 @@
#include <array>
#include <cassert>
#include <cstdint>
#include <span>
#include <cstdio>
#include <vector>
#include "blocks.h"
template <typename T, size_t M, size_t N> class ColorBlock {
template <size_t N> class ColorRow {
public:
using Row = std::span<T, N>;
constexpr Color &operator[](size_t n) noexcept { return _colors[n]; }
constexpr const Color &operator[](size_t n) const noexcept { return _colors[n]; }
ColorBlock(const std::array<T *, N> &rows) {
for (int i = 0; i < height(); i++) { this[i] = Row(rows[i], rows[i] * N * sizeof(T)); }
}
ColorBlock(const std::array<Row, N> &rows) {
for (int i = 0; i < height(); i++) { this[i] = rows[i]; }
}
constexpr int size() noexcept { return N; }
ColorBlock(const T *pixels) {
for (int i = 0; i < height(); i++) { _rows[i] = std::span(pixels[i * width()]); }
}
ColorBlock(const T *image, int imageWidth, int imageHeight, int x = 0, int y = 0) {
int image_x = x * width();
int image_y = y * height();
assert(image_x > 0 && image_x + width() < imageWidth);
assert(image_y > 0 && image_y + height() < imageHeight);
T *start = &image[image_x + (image_y * imageWidth)];
for (int i = 0; i < height(); i++) { _rows[i] = std::span(start[i * imageWidth]); }
}
private:
std::array<Color, 4> _colors;
};
constexpr Row &operator[](size_t n) noexcept { return _rows[n]; }
constexpr const Row &operator[](size_t n) const noexcept { return _rows[n]; }
template <size_t M, size_t N> class ColorBlock {
public:
using Row = ColorRow<N>;
constexpr Row &operator[](size_t n) noexcept { return *_rows[n]; }
constexpr const Row &operator[](size_t n) const noexcept { return *_rows[n]; }
constexpr int width() noexcept { return N; }
constexpr int height() noexcept { return M; }
constexpr int size() noexcept { return N * M; }
ColorBlock(const std::array<Row *, M> &Rows) : _rows(Rows) {}
private:
std::array<Row, M> _rows;
std::array<Row *, M> _rows;
};
using Color4x4= ColorBlock<Color32, 4, 4>;
using Color4x4 = ColorBlock<4, 4>;

@ -0,0 +1,22 @@
/* Python-rgbcx 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/>.
*/
#include "Image.h"
namespace rgbcx {} // namespace rgbcx

@ -1,6 +1,6 @@
/* Python-rgbcx Texture Compression Library
Copyright (C) 2021 Andrew Cassidy <drewcassidy@me.com>
Partially derived from rgbcx.h written by Richard Geldreich 2020 <richgel99@gmail.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
@ -19,16 +19,7 @@
#pragma once
#include <cstdint>
#include "../ColorBlock.h"
namespace rgbcx {
template <class B, size_t M, size_t N> class BlockDecoder {
public:
using DecodedBlock = ColorBlock<Color32, M, N>;
using EncodedBlock = B;
virtual void DecodeBlock(DecodedBlock *dest, EncodedBlock *const block) const = 0;
};
class Image {};
} // namespace rgbcx

@ -24,7 +24,7 @@
#include <cstdint>
#include <cstdlib>
#include "color.h"
#include "Color.h"
#include "util.h"
#pragma pack(push, 1)
@ -32,10 +32,10 @@ class BC1Block {
public:
using UnpackedSelectors = std::array<std::array<uint8_t, 4>, 4>;
uint16_t GetLowColor() const { return _low_color[0] | _low_color[1] << 8U; }
uint16_t GetHighColor() const { return _high_color[0] | _high_color[1] << 8U; }
Color32 GetLowColor32() const { return Color32::Unpack565(GetLowColor()); }
Color32 GetHighColor32() const { return Color32::Unpack565(GetHighColor()); }
uint16_t GetLowColor() const { return static_cast<uint16_t>(_low_color[0] | (_low_color[1] << 8U)); }
uint16_t GetHighColor() const { return static_cast<uint16_t>(_high_color[0] | (_high_color[1] << 8U)); }
Color GetLowColor32() const { return Color::Unpack565(GetLowColor()); }
Color GetHighColor32() const { return Color::Unpack565(GetHighColor()); }
bool Is3Color() const { return GetLowColor() <= GetHighColor(); }
void SetLowColor(uint16_t c) {
@ -58,16 +58,12 @@ class BC1Block {
UnpackedSelectors UnpackSelectors() const {
UnpackedSelectors unpacked;
for (int i = 0; i < 4; i++) {
unpacked[i] = Unpack<uint8_t, uint8_t, 2, 4>(selectors[i]);
}
for (unsigned i = 0; i < 4; i++) { unpacked[i] = Unpack<uint8_t, uint8_t, 2, 4>(selectors[i]); }
return unpacked;
}
void PackSelectors(const UnpackedSelectors& unpacked) {
for (int i = 0; i < 4; i++) {
selectors[i] = Pack<uint8_t, uint8_t, 2, 4>(unpacked[i]);
}
for (unsigned i = 0; i < 4; i++) { selectors[i] = Pack<uint8_t, uint8_t, 2, 4>(unpacked[i]); }
}
constexpr static inline size_t EndpointSize = 2;
@ -86,13 +82,39 @@ class BC1Block {
class BC4Block {
public:
using UnpackedSelectors = std::array<std::array<uint8_t, 4>, 4>;
inline uint32_t GetLowAlpha() const { return low_alpha; }
inline uint32_t GetHighAlpha() const { return high_alpha; }
inline bool Is6Alpha() const { return GetLowAlpha() <= GetHighAlpha(); }
inline uint64_t GetSelectorBits() const {
return ((uint64_t)((uint32_t)selectors[0] | ((uint32_t)selectors[1] << 8U) | ((uint32_t)selectors[2] << 16U) | ((uint32_t)selectors[3] << 24U))) |
(((uint64_t)selectors[4]) << 32U) | (((uint64_t)selectors[5]) << 40U);
auto packed = Pack<uint8_t, uint64_t, 8, 6>(selectors);
assert(packed <= SelectorBitsMax);
return packed;
}
void SetSelectorBits(uint64_t packed) {
assert(packed <= SelectorBitsMax);
selectors = Unpack<uint64_t, uint8_t, 8, 6>(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]);
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);
}
inline uint32_t GetSelector(uint32_t x, uint32_t y, uint64_t selector_bits) const {
@ -100,7 +122,7 @@ class BC4Block {
return (selector_bits >> (((y * 4) + x) * SelectorBits)) & (SelectorMask);
}
static inline std::array<uint8_t, 8> GetBlockValues6(uint32_t l, uint32_t h) {
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),
static_cast<uint8_t>((l * 4 + h) / 5),
@ -111,7 +133,7 @@ class BC4Block {
255};
}
static inline std::array<uint8_t, 8> GetBlockValues8(uint32_t l, uint32_t h) {
static inline std::array<uint8_t, 8> GetValues8(uint32_t l, uint32_t h) {
return {static_cast<uint8_t>(l),
static_cast<uint8_t>(h),
static_cast<uint8_t>((l * 6 + h) / 7),
@ -122,11 +144,11 @@ class BC4Block {
static_cast<uint8_t>((l + h * 6) / 7)};
}
static inline std::array<uint8_t, 8> GetBlockValues(uint32_t l, uint32_t h) {
static inline std::array<uint8_t, 8> GetValues(uint32_t l, uint32_t h) {
if (l > h)
return GetBlockValues8(l, h);
return GetValues8(l, h);
else
return GetBlockValues6(l, h);
return GetValues6(l, h);
}
constexpr static inline size_t EndpointSize = 1;
@ -134,10 +156,11 @@ class BC4Block {
constexpr static inline uint8_t SelectorBits = 3;
constexpr static inline uint8_t SelectorValues = 1 << SelectorBits;
constexpr static inline uint8_t SelectorMask = SelectorValues - 1;
constexpr static inline uint64_t SelectorBitsMax = (1UL << (8U * SelectorSize)) - 1U;
uint8_t low_alpha;
uint8_t high_alpha;
uint8_t selectors[SelectorSize];
std::array<uint8_t, SelectorSize> selectors;
};
class BC3Block {
@ -148,7 +171,7 @@ class BC3Block {
class BC5Block {
public:
BC4Block r_block;
BC4Block g_block;
BC4Block chan0_block;
BC4Block chan1_block;
};
#pragma pack(pop)

@ -1,90 +0,0 @@
/* Python-rgbcx 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/>.
*/
#include "color.h"
#include <algorithm>
#include <cassert>
#include "util.h"
// region Color32 implementation
Color32::Color32() { Set(0, 0, 0, 0xFF); }
Color32::Color32(uint8_t R, uint8_t G, uint8_t B, uint8_t A) { Set(R, G, B, A); }
uint16_t Color32::Pack565Unscaled(uint16_t R, uint16_t G, uint16_t B) { return B | (G << 5) | (R << 11); }
uint16_t Color32::Pack565(uint16_t R, uint16_t G, uint16_t B) { return Pack565Unscaled(scale8To5(R), scale8To6(G), scale8To5(B)); }
Color32 Color32::Unpack565(uint16_t Packed) {
uint8_t R = scale5To8((Packed >> 11) & 0x1F);
uint8_t G = scale6To8((Packed >> 5) & 0x3F);
uint8_t B = scale5To8(Packed & 0x1F);
return Color32(R, G, B);
}
Color32 Color32::Unpack565Unscaled(uint16_t Packed) {
uint8_t R = (Packed >> 11) & 0x1F;
uint8_t G = (Packed >> 5) & 0x3F;
uint8_t B = Packed & 0x1F;
return Color32(R, G, B);
}
uint8_t Color32::operator[](uint32_t Index) const {
assert(Index < 4);
return c[Index];
}
uint8_t &Color32::operator[](uint32_t Index) {
assert(Index < 4);
return c[Index];
}
void Color32::Set(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va = 0xFF) {
r = vr;
g = vg;
b = vb;
a = va;
}
void Color32::SetRGB(uint8_t vr, uint8_t vg, uint8_t vb) {
r = vr;
g = vg;
b = vb;
}
Color32 Color32::min(const Color32 &a, const Color32 &b) {
return Color32(std::min(a[0], b[0]), std::min(a[1], b[1]), std::min(a[2], b[2]), std::min(a[3], b[3]));
}
Color32 Color32::max(const Color32 &a, const Color32 &b) {
return Color32(std::max(a[0], b[0]), std::max(a[1], b[1]), std::max(a[2], b[2]), std::max(a[3], b[3]));
}
uint16_t Color32::pack565() { return Pack565(r, g, b); }
uint16_t Color32::pack565Unscaled() { return Pack565Unscaled(r, g, b); }
Color32 Color32::ScaleTo565() const { return Color32(scale8To5(r), scale8To6(g), scale8To5(b)); }
Color32 Color32::ScaleFrom565() const { return Color32(scale5To8(r), scale6To8(g), scale5To8(b)); }
// endregion

@ -1,68 +0,0 @@
/* Python-rgbcx 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 <array>
#include <cstdint>
#pragma pack(push, 1)
class Color32 {
public:
union {
struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
std::array<uint8_t, 4> c;
};
Color32();
Color32(uint8_t R, uint8_t G, uint8_t B, uint8_t A = 0xFF);
static uint16_t Pack565Unscaled(uint16_t R, uint16_t G, uint16_t B);
static uint16_t Pack565(uint16_t R, uint16_t G, uint16_t B);
static Color32 Unpack565Unscaled(uint16_t Packed);
static Color32 Unpack565(uint16_t Packed);
bool operator==(const Color32 &Rhs) const { return r == Rhs.r && g == Rhs.g && b == Rhs.b && a == Rhs.a; }
uint8_t operator[](uint32_t Index) const;
uint8_t &operator[](uint32_t Index);
uint16_t pack565();
uint16_t pack565Unscaled();
Color32 ScaleTo565() const;
Color32 ScaleFrom565() const;
static Color32 min(const Color32 &A, const Color32 &B);
static Color32 max(const Color32 &A, const Color32 &B);
void Set(uint8_t vr, uint8_t vg, uint8_t vb, uint8_t va);
void Set(const Color32 &other) { Set(other.r, other.g, other.b, other.a); }
void SetRGB(uint8_t vr, uint8_t vg, uint8_t vb);
void SetRGB(const Color32 &other) { SetRGB(other.r, other.g, other.b); }
};
#pragma pack(pop)

@ -22,6 +22,7 @@
#include <array>
#include <cassert>
#include <cstdint>
#include <stdexcept>
#include "util.h"
@ -40,7 +41,7 @@ void Interpolator::PrepSingleColorTables(const MatchListPtr &matchTable, const M
const uint8_t *expand = (len == 5) ? &Expand5[0] : &Expand6[0];
bool ideal = isIdeal();
bool ideal = IsIdeal();
bool use_e = useExpandedInMatch();
for (int i = 0; i < match_count; i++) {
@ -88,15 +89,30 @@ int Interpolator::PrepSingleColorTableEntry(const MatchListPtr &matchTable, int
}*/
// region Interpolator implementation
int Interpolator::Interpolate5(int v0, int v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
int Interpolator::Interpolate6(int v0, int v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
int Interpolator::InterpolateHalf5(int v0, int v1) const { return InterpolateHalf8(scale5To8(v0), scale5To8(v1)); }
int Interpolator::InterpolateHalf6(int v0, int v1) const { return InterpolateHalf8(scale6To8(v0), scale6To8(v1)); }
std::unique_ptr<Interpolator> Interpolator::MakeInterpolator(Interpolator::Type type) {
switch (type) {
case Type::Ideal:
return std::make_unique<Interpolator>();
case Type::IdealRound:
return std::make_unique<InterpolatorRound>();
case Type::Nvidia:
return std::make_unique<InterpolatorNvidia>();
case Type::AMD:
return std::make_unique<InterpolatorAMD>();
default:
throw std::invalid_argument("Invalid interpolator type");
}
}
uint8_t Interpolator::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
uint8_t Interpolator::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
uint8_t Interpolator::InterpolateHalf5(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale5To8(v0), scale5To8(v1)); }
uint8_t Interpolator::InterpolateHalf6(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale6To8(v0), scale6To8(v1)); }
std::array<Color32, 4> Interpolator::InterpolateBC1(uint16_t low, uint16_t high) const {
auto colors = std::array<Color32, 4>();
colors[0] = Color32::Unpack565(low);
colors[1] = Color32::Unpack565(high);
std::array<Color, 4> Interpolator::InterpolateBC1(uint16_t low, uint16_t high) const {
auto colors = std::array<Color, 4>();
colors[0] = Color::Unpack565(low);
colors[1] = Color::Unpack565(high);
if (low > high) {
// 4-color mode
@ -105,61 +121,58 @@ std::array<Color32, 4> Interpolator::InterpolateBC1(uint16_t low, uint16_t high)
} else {
// 3-color mode
colors[2] = InterpolateHalfColor24(colors[0], colors[1]);
colors[3] = Color32(0, 0, 0, 0); // transparent black
colors[3] = Color(0, 0, 0, 0); // transparent black
}
return colors;
}
int Interpolator::Interpolate8(int v0, int v1) const {
assert(v0 < 256 && v1 < 256);
uint8_t Interpolator::Interpolate8(uint8_t v0, uint8_t v1) const {
return (v0 * 2 + v1) / 3;
}
int Interpolator::InterpolateHalf8(int v0, int v1) const {
assert(v0 < 256 && v1 < 256);
uint8_t Interpolator::InterpolateHalf8(uint8_t v0, uint8_t v1) const {
return (v0 + v1) / 2;
}
// endregion
// region InterpolatorRound implementation
int InterpolatorRound::Interpolate5(int v0, int v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
int InterpolatorRound::Interpolate6(int v0, int v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
uint8_t InterpolatorRound::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
uint8_t InterpolatorRound::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
int InterpolatorRound::Interpolate8(int v0, int v1) const {
assert(v0 < 256 && v1 < 256);
uint8_t InterpolatorRound::Interpolate8(uint8_t v0, uint8_t v1) const {
return (v0 * 2 + v1 + 1) / 3;
}
// endregion
// region InterpolatorNvidia implementation
int InterpolatorNvidia::Interpolate5(int v0, int v1) const {
uint8_t InterpolatorNvidia::Interpolate5(uint8_t v0, uint8_t v1) const {
assert(v0 < 32 && v1 < 32);
return ((2 * v0 + v1) * 22) / 8;
return ((2 * v0 + v1) * 22) / 8U;
}
int InterpolatorNvidia::Interpolate6(int v0, int v1) const {
uint8_t InterpolatorNvidia::Interpolate6(uint8_t v0, uint8_t v1) const {
assert(v0 < 64 && v1 < 64);
const int gdiff = v1 - v0;
return (256 * v0 + (gdiff / 4) + 128 + gdiff * 80) / 256;
return static_cast<uint8_t>((256 * v0 + (gdiff / 4) + 128 + gdiff * 80) >> 8);
}
int InterpolatorNvidia::InterpolateHalf5(int v0, int v1) const {
uint8_t InterpolatorNvidia::InterpolateHalf5(uint8_t v0, uint8_t v1) const {
assert(v0 < 32 && v1 < 32);
return ((v0 + v1) * 33) / 8;
return ((v0 + v1) * 33) / 8U;
}
int InterpolatorNvidia::InterpolateHalf6(int v0, int v1) const {
uint8_t InterpolatorNvidia::InterpolateHalf6(uint8_t v0, uint8_t v1) const {
assert(v0 < 64 && v1 < 64);
const int gdiff = v1 - v0;
return (256 * v0 + gdiff / 4 + 128 + gdiff * 128) / 256;
return static_cast<uint8_t>((256 * v0 + gdiff / 4 + 128 + gdiff * 128) >> 8);
}
std::array<Color32, 4> InterpolatorNvidia::InterpolateBC1(uint16_t low, uint16_t high) const {
std::array<Color, 4> InterpolatorNvidia::InterpolateBC1(uint16_t low, uint16_t high) const {
// Nvidia is special and interpolation cant be done with 8-bit values, so we need to override the default behavior
auto colors = std::array<Color32, 4>();
auto low565 = Color32::Unpack565Unscaled(low);
auto high565 = Color32::Unpack565Unscaled(high);
auto colors = std::array<Color, 4>();
auto low565 = Color::Unpack565Unscaled(low);
auto high565 = Color::Unpack565Unscaled(high);
colors[0] = low565.ScaleFrom565();
colors[1] = high565.ScaleFrom565();
@ -170,7 +183,7 @@ std::array<Color32, 4> InterpolatorNvidia::InterpolateBC1(uint16_t low, uint16_t
} else {
// 3-color mode
colors[2] = InterpolateHalfColor565(low565, high565);
colors[3] = Color32(0, 0, 0, 0); // transparent black
colors[3] = Color(0, 0, 0, 0); // transparent black
}
return colors;
@ -178,18 +191,16 @@ std::array<Color32, 4> InterpolatorNvidia::InterpolateBC1(uint16_t low, uint16_t
// endregion
// region InterpolatorAMD implementation
int InterpolatorAMD::Interpolate5(int v0, int v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
int InterpolatorAMD::Interpolate6(int v0, int v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
int InterpolatorAMD::InterpolateHalf5(int v0, int v1) const { return InterpolateHalf8(scale5To8(v0), scale5To8(v1)); }
int InterpolatorAMD::InterpolateHalf6(int v0, int v1) const { return InterpolateHalf8(scale6To8(v0), scale6To8(v1)); }
uint8_t InterpolatorAMD::Interpolate5(uint8_t v0, uint8_t v1) const { return Interpolate8(scale5To8(v0), scale5To8(v1)); }
uint8_t InterpolatorAMD::Interpolate6(uint8_t v0, uint8_t v1) const { return Interpolate8(scale6To8(v0), scale6To8(v1)); }
uint8_t InterpolatorAMD::InterpolateHalf5(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale5To8(v0), scale5To8(v1)); }
uint8_t InterpolatorAMD::InterpolateHalf6(uint8_t v0, uint8_t v1) const { return InterpolateHalf8(scale6To8(v0), scale6To8(v1)); }
int InterpolatorAMD::Interpolate8(int v0, int v1) const {
assert(v0 < 256 && v1 < 256);
uint8_t InterpolatorAMD::Interpolate8(uint8_t v0, uint8_t v1) const {
return (v0 * 43 + v1 * 21 + 32) >> 6;
}
int InterpolatorAMD::InterpolateHalf8(int v0, int v1) const {
assert(v0 < 256 && v1 < 256);
uint8_t InterpolatorAMD::InterpolateHalf8(uint8_t v0, uint8_t v1) const {
return (v0 + v1 + 1) >> 1;
}
// endregion

@ -23,75 +23,82 @@
#include <cstdint>
#include <memory>
#include "color.h"
#include "Color.h"
#include "ndebug.h"
#include "util.h"
namespace rgbcx {
template <size_t Size, int Op(int)> static constexpr std::array<uint8_t, Size> ExpandArray() {
std::array<uint8_t, Size> res;
for (int i = 0; i < Size; i++) { res[i] = Op(i); }
return res;
}
class Interpolator {
public:
// struct MatchEntry {
// uint8_t high;
// uint8_t low;
// uint8_t error;
// };
enum class Type { Ideal, IdealRound, Nvidia, AMD };
static std::unique_ptr<Interpolator> MakeInterpolator(Type type = Type::Ideal);
virtual ~Interpolator() noexcept = default;
/**
* Performs a 2/3 interpolation of a pair of 5-bit values to produce an 8-bit value
* Performs A() 2/3 interpolation of A() pair of 5-bit values to produce an 8-bit value
* Output is approximately (2v0 + v1)/3, with v0 and v1 first extended to 8 bits.
* @param v0 The first 5-bit value
* @param v1 The second 5-bit value
* @return The interpolated value
*/
virtual int Interpolate5(int v0, int v1) const;
virtual uint8_t Interpolate5(uint8_t v0, uint8_t v1) const;
/**
* Performs a 2/3 interpolation of a pair of 5-bit values to produce an 8-bit value
* Performs A() 2/3 interpolation of A() pair of 5-bit values to produce an 8-bit value
* Output is approximately (2v0 + v1)/3, with v0 and v1 first extended to 8 bits.
* @param v0 The first 5-bit value
* @param v1 The second 5-bit value
* @return The interpolated value
*/
virtual int Interpolate6(int v0, int v1) const;
virtual uint8_t Interpolate6(uint8_t v0, uint8_t v1) const;
/**
* Performs a 1/2 interpolation of a pair of 5-bit values to produce an 8-bit value
* Performs A() 1/2 interpolation of A() pair of 5-bit values to produce an 8-bit value
* Output is approximately (v0 + v1)/2, with v0 and v1 first extended to 8 bits.
* @param v0 The first 5-bit value
* @param v1 The second 5-bit value
* @return The interpolated value
*/
virtual int InterpolateHalf5(int v0, int v1) const;
virtual uint8_t InterpolateHalf5(uint8_t v0, uint8_t v1) const;
/**
* Performs a 1/2 interpolation of a pair of 6-bit values to produce an 8-bit value
* Performs A() 1/2 interpolation of A() pair of 6-bit values to produce an 8-bit value
* Output is approximately (v0 + v1)/2, with v0 and v1 first extended to 8 bits.
* @param v0 The first 6-bit value
* @param v1 The second 6-bit value
* @return The interpolated value
*/
virtual int InterpolateHalf6(int v0, int v1) const;
virtual uint8_t InterpolateHalf6(uint8_t v0, uint8_t v1) const;
/**
* Generates the 4 colors for a BC1 block from the given 5:6:5-packed colors
* Generates the 4 colors for A() BC1 block from the given 5:6:5-packed colors
* @param low first 5:6:5 color for the block
* @param high second 5:6:5 color for the block
* @return and array of 4 Color32 values, with indices matching BC1 selectors
* @return and array of 4 Color values, with indices matching BC1 selectors
*/
virtual std::array<Color, 4> InterpolateBC1(uint16_t low, uint16_t high) const;
/**
* Gets the type of an interpolator
* @return The interpolator type
*/
virtual std::array<Color32, 4> InterpolateBC1(uint16_t low, uint16_t high) const;
virtual Type GetType() const noexcept { return Type::Ideal; }
/**
* Checks if the interpolator uses an ideal algorithm
* @return true if the interpolator is ideal, false otherwise.
*/
virtual bool IsIdeal() const noexcept {
auto type = GetType();
return (type == Type::Ideal || type == Type::IdealRound);
}
private:
virtual int Interpolate8(int v0, int v1) const;
virtual int InterpolateHalf8(int v0, int v1) const;
virtual uint8_t Interpolate8(uint8_t v0, uint8_t v1) const;
virtual uint8_t InterpolateHalf8(uint8_t v0, uint8_t v1) const;
// constexpr static auto Expand5 = ExpandArray<Size5, scale5To8>();
// constexpr static auto Expand6 = ExpandArray<size6, scale6To8>();
@ -105,15 +112,14 @@ class Interpolator {
// const MatchListPtr _single_match5_half = {std::make_shared<MatchList>()};
// const MatchListPtr _single_match6_half = {std::make_shared<MatchList>()};
Color32 InterpolateColor24(const Color32 &c0, const Color32 &c1) const {
return Color32(Interpolate8(c0.r, c1.r), Interpolate8(c0.g, c1.g), Interpolate8(c0.b, c1.b));
Color InterpolateColor24(const Color &c0, const Color &c1) const {
return Color(Interpolate8(c0.R(), c1.R()), Interpolate8(c0.G(), c1.G()), Interpolate8(c0.B(), c1.B()));
}
Color32 InterpolateHalfColor24(const Color32 &c0, const Color32 &c1) const {
return Color32(InterpolateHalf8(c0.r, c1.r), InterpolateHalf8(c0.g, c1.g), InterpolateHalf8(c0.b, c1.b));
Color InterpolateHalfColor24(const Color &c0, const Color &c1) const {
return Color(InterpolateHalf8(c0.R(), c1.R()), InterpolateHalf8(c0.G(), c1.G()), InterpolateHalf8(c0.B(), c1.B()));
}
virtual constexpr bool isIdeal() noexcept { return true; }
// virtual constexpr bool useExpandedInMatch() noexcept { return true; }
//
// void PrepSingleColorTables(const MatchListPtr &matchTable, const MatchListPtr &matchTableHalf, int len);
@ -124,42 +130,43 @@ class Interpolator {
class InterpolatorRound : public Interpolator {
public:
int Interpolate5(int v0, int v1) const override;
int Interpolate6(int v0, int v1) const override;
uint8_t Interpolate5(uint8_t v0, uint8_t v1) const override;
uint8_t Interpolate6(uint8_t v0, uint8_t v1) const override;
Type GetType() const noexcept override { return Type::IdealRound; }
private:
int Interpolate8(int v0, int v1) const override;
uint8_t Interpolate8(uint8_t v0, uint8_t v1) const override;
};
class InterpolatorNvidia : public Interpolator {
public:
int Interpolate5(int v0, int v1) const override;
int Interpolate6(int v0, int v1) const override;
int InterpolateHalf5(int v0, int v1) const override;
int InterpolateHalf6(int v0, int v1) const override;
std::array<Color32, 4> InterpolateBC1(uint16_t low, uint16_t high) const override;
constexpr bool isIdeal() noexcept override { return false; }
uint8_t Interpolate5(uint8_t v0, uint8_t v1) const override;
uint8_t Interpolate6(uint8_t v0, uint8_t v1) const override;
uint8_t InterpolateHalf5(uint8_t v0, uint8_t v1) const override;
uint8_t InterpolateHalf6(uint8_t v0, uint8_t v1) const override;
std::array<Color, 4> InterpolateBC1(uint16_t low, uint16_t high) const override;
Type GetType() const noexcept override { return Type::Nvidia; }
private:
Color32 InterpolateColor565(const Color32 &c0, const Color32 &c1) const {
return Color32(Interpolate5(c0.r, c1.r), Interpolate6(c0.g, c1.g), Interpolate5(c0.b, c1.b));
Color InterpolateColor565(const Color &c0, const Color &c1) const {
return Color(Interpolate5(c0.R(), c1.R()), Interpolate6(c0.G(), c1.G()), Interpolate5(c0.B(), c1.B()));
}
Color32 InterpolateHalfColor565(const Color32 &c0, const Color32 &c1) const {
return Color32(InterpolateHalf5(c0.r, c1.r), InterpolateHalf6(c0.g, c1.g), InterpolateHalf5(c0.b, c1.b));
Color InterpolateHalfColor565(const Color &c0, const Color &c1) const {
return Color(InterpolateHalf5(c0.R(), c1.R()), InterpolateHalf6(c0.G(), c1.G()), InterpolateHalf5(c0.B(), c1.B()));
}
};
class InterpolatorAMD : public Interpolator {
public:
int Interpolate5(int v0, int v1) const override;
int Interpolate6(int v0, int v1) const override;
int InterpolateHalf5(int v0, int v1) const override;
int InterpolateHalf6(int v0, int v1) const override;
constexpr bool isIdeal() noexcept override { return false; }
uint8_t Interpolate5(uint8_t v0, uint8_t v1) const override;
uint8_t Interpolate6(uint8_t v0, uint8_t v1) const override;
uint8_t InterpolateHalf5(uint8_t v0, uint8_t v1) const override;
uint8_t InterpolateHalf6(uint8_t v0, uint8_t v1) const override;
Type GetType() const noexcept override { return Type::AMD; }
private:
int Interpolate8(int v0, int v1) const override;
int InterpolateHalf8(int v0, int v1) const override;
uint8_t Interpolate8(uint8_t v0, uint8_t v1) const override;
uint8_t InterpolateHalf8(uint8_t v0, uint8_t v1) const override;
};
} // namespace rgbcx

@ -1,6 +1,7 @@
// rgbcx.h v1.12
// High-performance scalar BC1-5 encoders. Public Domain or MIT license (you choose - see below), written by Richard Geldreich 2020 <richgel99@gmail.com>.
#pragma GCC diagnostic ignored "-Weverything"
#include "rgbcx.h"
#include <algorithm>
@ -11,8 +12,8 @@
#include <cstring>
#include <type_traits>
#include "Color.h"
#include "blocks.h"
#include "color.h"
#include "tables.h"
#include "util.h"
@ -187,7 +188,7 @@ static inline int interp_6(int v0, int v1, int c0, int c1, bc1_approx_mode mode)
}
}
static inline int interp_half_5(int v0, int v1, int c0, int c1, bc1_approx_mode mode) {
static inline unsigned int interp_half_5(unsigned int v0, unsigned int v1, unsigned int c0, unsigned int c1, bc1_approx_mode mode) {
assert(scale5To8(v0) == c0 && scale5To8(v1) == c1);
switch (mode) {
case bc1_approx_mode::cBC1NVidia:
@ -201,7 +202,7 @@ static inline int interp_half_5(int v0, int v1, int c0, int c1, bc1_approx_mode
}
}
static inline int interp_half_6(int v0, int v1, int c0, int c1, bc1_approx_mode mode) {
static inline unsigned int interp_half_6(unsigned v0, unsigned v1, unsigned c0, bc1_approx_mode mode, unsigned c1) {
(void)v0;
(void)v1;
assert(scale6To8(v0) == c0 && scale6To8(v1) == c1);
@ -226,7 +227,7 @@ static void prepare_bc1_single_color_table_half(bc1_match_entry *pTable, const u
for (int hi = 0; hi < size; hi++) {
const int hi_e = pExpand[hi];
const int v = (size == 32) ? interp_half_5(hi, lo, hi_e, lo_e, mode) : interp_half_6(hi, lo, hi_e, lo_e, mode);
const int v = (size == 32) ? interp_half_5(hi, lo, hi_e, lo_e, mode) : interp_half_6(hi, lo, hi_e, mode, lo_e);
int e = iabs(v - i);
@ -471,12 +472,12 @@ static inline void compute_least_squares_endpoints4_rgb(vec3F *pXl, vec3F *pXh,
pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b;
}
static inline bool compute_least_squares_endpoints4_rgb(const Color32 *pColors, const uint8_t *pSelectors, vec3F *pXl, vec3F *pXh, int total_r, int total_g,
static inline bool compute_least_squares_endpoints4_rgb(const Color *pColors, const uint8_t *pSelectors, vec3F *pXl, vec3F *pXh, int total_r, int total_g,
int total_b) {
uint32_t uq00_r = 0, uq00_g = 0, uq00_b = 0;
uint32_t weight_accum = 0;
for (uint32_t i = 0; i < 16; i++) {
const uint8_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2];
const uint8_t r = pColors[i][0], g = pColors[i][1], b = pColors[i][2];
const uint8_t sel = pSelectors[i];
weight_accum += g_weight_vals4[sel];
@ -542,12 +543,12 @@ static inline void compute_least_squares_endpoints3_rgb(vec3F *pXl, vec3F *pXh,
pXh->c[2] = iz10 * (float)uq00_b + iz11 * q10_b;
}
static inline bool compute_least_squares_endpoints3_rgb(bool use_black, const Color32 *pColors, const uint8_t *pSelectors, vec3F *pXl, vec3F *pXh) {
static inline bool compute_least_squares_endpoints3_rgb(bool use_black, const Color *pColors, const uint8_t *pSelectors, vec3F *pXl, vec3F *pXh) {
int uq00_r = 0, uq00_g = 0, uq00_b = 0;
uint32_t weight_accum = 0;
int total_r = 0, total_g = 0, total_b = 0;
for (uint32_t i = 0; i < 16; i++) {
const uint8_t r = pColors[i].c[0], g = pColors[i].c[1], b = pColors[i].c[2];
const uint8_t r = pColors[i][0], g = pColors[i][1], b = pColors[i][2];
if (use_black) {
if ((r | g | b) < 4) continue;
}
@ -665,7 +666,7 @@ static inline void bc1_get_block_colors3(uint32_t block_r[3], uint32_t block_g[3
}
}
static inline void bc1_find_sels4_noerr(const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
static inline void bc1_find_sels4_noerr(const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
uint8_t sels[16]) {
uint32_t block_r[4], block_g[4], block_b[4];
bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb);
@ -684,10 +685,10 @@ static inline void bc1_find_sels4_noerr(const Color32 *pSrc_pixels, uint32_t lr,
static const uint8_t s_sels[4] = {3, 2, 1, 0};
for (uint32_t i = 0; i < 16; i += 4) {
const int d0 = pSrc_pixels[i + 0].r * ar + pSrc_pixels[i + 0].g * ag + pSrc_pixels[i + 0].b * ab;
const int d1 = pSrc_pixels[i + 1].r * ar + pSrc_pixels[i + 1].g * ag + pSrc_pixels[i + 1].b * ab;
const int d2 = pSrc_pixels[i + 2].r * ar + pSrc_pixels[i + 2].g * ag + pSrc_pixels[i + 2].b * ab;
const int d3 = pSrc_pixels[i + 3].r * ar + pSrc_pixels[i + 3].g * ag + pSrc_pixels[i + 3].b * ab;
const int d0 = pSrc_pixels[i + 0].R() * ar + pSrc_pixels[i + 0].G() * ag + pSrc_pixels[i + 0].B() * ab;
const int d1 = pSrc_pixels[i + 1].R() * ar + pSrc_pixels[i + 1].G() * ag + pSrc_pixels[i + 1].B() * ab;
const int d2 = pSrc_pixels[i + 2].R() * ar + pSrc_pixels[i + 2].G() * ag + pSrc_pixels[i + 2].B() * ab;
const int d3 = pSrc_pixels[i + 3].R() * ar + pSrc_pixels[i + 3].G() * ag + pSrc_pixels[i + 3].B() * ab;
sels[i + 0] = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)];
sels[i + 1] = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)];
@ -696,7 +697,7 @@ static inline void bc1_find_sels4_noerr(const Color32 *pSrc_pixels, uint32_t lr,
}
}
static inline uint32_t bc1_find_sels4_fasterr(const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
static inline uint32_t bc1_find_sels4_fasterr(const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
uint8_t sels[16], uint32_t cur_err) {
uint32_t block_r[4], block_g[4], block_b[4];
bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb);
@ -717,10 +718,10 @@ static inline uint32_t bc1_find_sels4_fasterr(const Color32 *pSrc_pixels, uint32
uint32_t total_err = 0;
for (uint32_t i = 0; i < 16; i += 4) {
const int d0 = pSrc_pixels[i + 0].r * ar + pSrc_pixels[i + 0].g * ag + pSrc_pixels[i + 0].b * ab;
const int d1 = pSrc_pixels[i + 1].r * ar + pSrc_pixels[i + 1].g * ag + pSrc_pixels[i + 1].b * ab;
const int d2 = pSrc_pixels[i + 2].r * ar + pSrc_pixels[i + 2].g * ag + pSrc_pixels[i + 2].b * ab;
const int d3 = pSrc_pixels[i + 3].r * ar + pSrc_pixels[i + 3].g * ag + pSrc_pixels[i + 3].b * ab;
const int d0 = pSrc_pixels[i + 0].R() * ar + pSrc_pixels[i + 0].G() * ag + pSrc_pixels[i + 0].B() * ab;
const int d1 = pSrc_pixels[i + 1].R() * ar + pSrc_pixels[i + 1].G() * ag + pSrc_pixels[i + 1].B() * ab;
const int d2 = pSrc_pixels[i + 2].R() * ar + pSrc_pixels[i + 2].G() * ag + pSrc_pixels[i + 2].B() * ab;
const int d3 = pSrc_pixels[i + 3].R() * ar + pSrc_pixels[i + 3].G() * ag + pSrc_pixels[i + 3].B() * ab;
uint8_t sel0 = s_sels[(d0 <= t0) + (d0 < t1) + (d0 < t2)];
uint8_t sel1 = s_sels[(d1 <= t0) + (d1 < t1) + (d1 < t2)];
@ -733,13 +734,13 @@ static inline uint32_t bc1_find_sels4_fasterr(const Color32 *pSrc_pixels, uint32
sels[i + 3] = sel3;
total_err +=
squarei(pSrc_pixels[i + 0].r - block_r[sel0]) + squarei(pSrc_pixels[i + 0].g - block_g[sel0]) + squarei(pSrc_pixels[i + 0].b - block_b[sel0]);
squarei(pSrc_pixels[i + 0].R() - block_r[sel0]) + squarei(pSrc_pixels[i + 0].G() - block_g[sel0]) + squarei(pSrc_pixels[i + 0].B() - block_b[sel0]);
total_err +=
squarei(pSrc_pixels[i + 1].r - block_r[sel1]) + squarei(pSrc_pixels[i + 1].g - block_g[sel1]) + squarei(pSrc_pixels[i + 1].b - block_b[sel1]);
squarei(pSrc_pixels[i + 1].R() - block_r[sel1]) + squarei(pSrc_pixels[i + 1].G() - block_g[sel1]) + squarei(pSrc_pixels[i + 1].B() - block_b[sel1]);
total_err +=
squarei(pSrc_pixels[i + 2].r - block_r[sel2]) + squarei(pSrc_pixels[i + 2].g - block_g[sel2]) + squarei(pSrc_pixels[i + 2].b - block_b[sel2]);
squarei(pSrc_pixels[i + 2].R() - block_r[sel2]) + squarei(pSrc_pixels[i + 2].G() - block_g[sel2]) + squarei(pSrc_pixels[i + 2].B() - block_b[sel2]);
total_err +=
squarei(pSrc_pixels[i + 3].r - block_r[sel3]) + squarei(pSrc_pixels[i + 3].g - block_g[sel3]) + squarei(pSrc_pixels[i + 3].b - block_b[sel3]);
squarei(pSrc_pixels[i + 3].R() - block_r[sel3]) + squarei(pSrc_pixels[i + 3].G() - block_g[sel3]) + squarei(pSrc_pixels[i + 3].B() - block_b[sel3]);
if (total_err >= cur_err) break;
}
@ -747,7 +748,7 @@ static inline uint32_t bc1_find_sels4_fasterr(const Color32 *pSrc_pixels, uint32
return total_err;
}
static inline uint32_t bc1_find_sels4_check2_err(const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
static inline uint32_t bc1_find_sels4_check2_err(const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
uint8_t sels[16], uint32_t cur_err) {
uint32_t block_r[4], block_g[4], block_b[4];
bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb);
@ -759,9 +760,9 @@ static inline uint32_t bc1_find_sels4_check2_err(const Color32 *pSrc_pixels, uin
uint32_t total_err = 0;
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r;
const int g = pSrc_pixels[i].g;
const int b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R();
const int g = pSrc_pixels[i].G();
const int b = pSrc_pixels[i].B();
int sel = (int)((float)((r - (int)block_r[0]) * dr + (g - (int)block_g[0]) * dg + (b - (int)block_b[0]) * db) * f + .5f);
sel = clampi(sel, 1, 3);
@ -788,7 +789,7 @@ static inline uint32_t bc1_find_sels4_check2_err(const Color32 *pSrc_pixels, uin
return total_err;
}
static inline uint32_t bc1_find_sels4_fullerr(const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
static inline uint32_t bc1_find_sels4_fullerr(const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
uint8_t sels[16], uint32_t cur_err) {
uint32_t block_r[4], block_g[4], block_b[4];
bc1_get_block_colors4(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb);
@ -796,9 +797,9 @@ static inline uint32_t bc1_find_sels4_fullerr(const Color32 *pSrc_pixels, uint32
uint32_t total_err = 0;
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r;
const int g = pSrc_pixels[i].g;
const int b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R();
const int g = pSrc_pixels[i].G();
const int b = pSrc_pixels[i].B();
uint32_t best_err = squarei((int)block_r[0] - (int)r) + squarei((int)block_g[0] - (int)g) + squarei((int)block_b[0] - (int)b);
uint8_t best_sel = 0;
@ -820,7 +821,7 @@ static inline uint32_t bc1_find_sels4_fullerr(const Color32 *pSrc_pixels, uint32
return total_err;
}
static inline uint32_t bc1_find_sels4(uint32_t flags, const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
static inline uint32_t bc1_find_sels4(uint32_t flags, const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg, uint32_t hb,
uint8_t sels[16], uint32_t cur_err) {
uint32_t err;
@ -834,7 +835,7 @@ static inline uint32_t bc1_find_sels4(uint32_t flags, const Color32 *pSrc_pixels
return err;
}
static inline uint32_t bc1_find_sels3_fullerr(bool use_black, const Color32 *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg,
static inline uint32_t bc1_find_sels3_fullerr(bool use_black, const Color *pSrc_pixels, uint32_t lr, uint32_t lg, uint32_t lb, uint32_t hr, uint32_t hg,
uint32_t hb, uint8_t sels[16], uint32_t cur_err) {
uint32_t block_r[3], block_g[3], block_b[3];
bc1_get_block_colors3(block_r, block_g, block_b, lr, lg, lb, hr, hg, hb);
@ -842,9 +843,9 @@ static inline uint32_t bc1_find_sels3_fullerr(bool use_black, const Color32 *pSr
uint32_t total_err = 0;
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r;
const int g = pSrc_pixels[i].g;
const int b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R();
const int g = pSrc_pixels[i].G();
const int b = pSrc_pixels[i].B();
uint32_t best_err = squarei((int)block_r[0] - (int)r) + squarei((int)block_g[0] - (int)g) + squarei((int)block_b[0] - (int)b);
uint32_t best_sel = 0;
@ -923,8 +924,8 @@ static inline void precise_round_565_noscale(vec3F xl, vec3F xh, int &trial_lr,
}
static inline void bc1_encode4(BC1Block *pDst_block, int lr, int lg, int lb, int hr, int hg, int hb, const uint8_t sels[16]) {
uint16_t lc16 = Color32::Pack565Unscaled(lr, lg, lb);
uint16_t hc16 = Color32::Pack565Unscaled(hr, hg, hb);
uint16_t lc16 = Color::Pack565Unscaled(lr, lg, lb);
uint16_t hc16 = Color::Pack565Unscaled(hr, hg, hb);
// Always forbid 3 color blocks
if (lc16 == hc16) {
@ -974,8 +975,8 @@ static inline void bc1_encode4(BC1Block *pDst_block, int lr, int lg, int lb, int
}
static inline void bc1_encode3(BC1Block *pDst_block, int lr, int lg, int lb, int hr, int hg, int hb, const uint8_t sels[16]) {
uint16_t lc16 = Color32::Pack565Unscaled(lr, lg, lb);
uint16_t hc16 = Color32::Pack565Unscaled(hr, hg, hb);
uint16_t lc16 = Color::Pack565Unscaled(lr, lg, lb);
uint16_t hc16 = Color::Pack565Unscaled(hr, hg, hb);
bool invert_flag = false;
if (lc16 > hc16) {
@ -1012,13 +1013,13 @@ struct bc1_encode_results {
bool m_3color;
};
static bool try_3color_block_useblack(const Color32 *pSrc_pixels, uint32_t flags, uint32_t &cur_err, bc1_encode_results &results) {
static bool try_3color_block_useblack(const Color *pSrc_pixels, uint32_t flags, uint32_t &cur_err, bc1_encode_results &results) {
int total_r = 0, total_g = 0, total_b = 0;
int max_r = 0, max_g = 0, max_b = 0;
int min_r = 255, min_g = 255, min_b = 255;
int total_pixels = 0;
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R(), g = pSrc_pixels[i].G(), b = pSrc_pixels[i].B();
if ((r | g | b) < 4) continue;
max_r = std::max(max_r, r);
@ -1045,9 +1046,9 @@ static bool try_3color_block_useblack(const Color32 *pSrc_pixels, uint32_t flags
int icov[6] = {0, 0, 0, 0, 0, 0};
for (uint32_t i = 0; i < 16; i++) {
int r = (int)pSrc_pixels[i].r;
int g = (int)pSrc_pixels[i].g;
int b = (int)pSrc_pixels[i].b;
int r = (int)pSrc_pixels[i].R();
int g = (int)pSrc_pixels[i].G();
int b = (int)pSrc_pixels[i].B();
if ((r | g | b) < 4) continue;
@ -1094,7 +1095,7 @@ static bool try_3color_block_useblack(const Color32 *pSrc_pixels, uint32_t flags
int low_dot = INT_MAX, high_dot = INT_MIN;
for (uint32_t i = 0; i < 16; i++) {
int r = (int)pSrc_pixels[i].r, g = (int)pSrc_pixels[i].g, b = (int)pSrc_pixels[i].b;
int r = (int)pSrc_pixels[i].R(), g = (int)pSrc_pixels[i].G(), b = (int)pSrc_pixels[i].B();
if ((r | g | b) < 4) continue;
@ -1109,13 +1110,13 @@ static bool try_3color_block_useblack(const Color32 *pSrc_pixels, uint32_t flags
}
}
int lr = scale8To5(pSrc_pixels[low_c].r);
int lg = scale8To6(pSrc_pixels[low_c].g);
int lb = scale8To5(pSrc_pixels[low_c].b);
int lr = scale8To5(pSrc_pixels[low_c].R());
int lg = scale8To6(pSrc_pixels[low_c].G());
int lb = scale8To5(pSrc_pixels[low_c].B());
int hr = scale8To5(pSrc_pixels[high_c].r);
int hg = scale8To6(pSrc_pixels[high_c].g);
int hb = scale8To5(pSrc_pixels[high_c].b);
int hr = scale8To5(pSrc_pixels[high_c].R());
int hg = scale8To6(pSrc_pixels[high_c].G());
int hb = scale8To5(pSrc_pixels[high_c].B());
uint8_t trial_sels[16];
uint32_t trial_err = bc1_find_sels3_fullerr(true, pSrc_pixels, lr, lg, lb, hr, hg, hb, trial_sels, UINT32_MAX);
@ -1174,7 +1175,7 @@ static bool try_3color_block_useblack(const Color32 *pSrc_pixels, uint32_t flags
return false;
}
static bool try_3color_block(const Color32 *pSrc_pixels, uint32_t flags, uint32_t &cur_err, int avg_r, int avg_g, int avg_b, int lr, int lg, int lb, int hr,
static bool try_3color_block(const Color *pSrc_pixels, uint32_t flags, uint32_t &cur_err, int avg_r, int avg_g, int avg_b, int lr, int lg, int lb, int hr,
int hg, int hb, int total_r, int total_g, int total_b, uint32_t total_orderings_to_try, bc1_encode_results &results) {
uint8_t trial_sels[16];
uint32_t trial_err = bc1_find_sels3_fullerr(false, pSrc_pixels, lr, lg, lb, hr, hg, hb, trial_sels, UINT32_MAX);
@ -1236,9 +1237,9 @@ static bool try_3color_block(const Color32 *pSrc_pixels, uint32_t flags, uint32_
int dots[16];
for (uint32_t i = 0; i < 16; i++) {
int r = pSrc_pixels[i].r;
int g = pSrc_pixels[i].g;
int b = pSrc_pixels[i].b;
int r = pSrc_pixels[i].R();
int g = pSrc_pixels[i].G();
int b = pSrc_pixels[i].B();
int d = 0x1000000 + (r * ar + g * ag + b * ab);
assert(d >= 0);
dots[i] = (d << 4) + i;
@ -1255,9 +1256,9 @@ static bool try_3color_block(const Color32 *pSrc_pixels, uint32_t flags, uint32_
g_sum[i] = g;
b_sum[i] = b;
r += pSrc_pixels[p].r;
g += pSrc_pixels[p].g;
b += pSrc_pixels[p].b;
r += pSrc_pixels[p].R();
g += pSrc_pixels[p].G();
b += pSrc_pixels[p].B();
}
r_sum[16] = total_r;
@ -1338,11 +1339,11 @@ void encode_bc1(uint32_t level, void *pDst, const uint8_t *pPixels, bool allow_3
flags = cEncodeBC1BoundingBoxInt;
break;
case 1:
// Faster/higher quality than stb_dxt default. a bit higher average quality vs. mode 0.
// Faster/higher quality than stb_dxt default. A() bit higher average quality vs. mode 0.
flags = cEncodeBC1Use2DLS;
break;
case 2:
// On average mode 2 is a little weaker than modes 0/1, but it's stronger on outliers (very tough textures).
// On average mode 2 is A() little weaker than modes 0/1, but it's stronger on outliers (very tough textures).
// Slightly stronger than stb_dxt.
flags = 0;
break;
@ -1453,13 +1454,13 @@ void encode_bc1(uint32_t level, void *pDst, const uint8_t *pPixels, bool allow_3
}
// Finds low and high colors to begin with
static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t flags, bool grayscale_flag, int min_r, int min_g, int min_b, int max_r,
static inline void encode_bc1_pick_initial(const Color *pSrc_pixels, uint32_t flags, bool grayscale_flag, int min_r, int min_g, int min_b, int max_r,
int max_g, int max_b, int avg_r, int avg_g, int avg_b, int total_r, int total_g, int total_b, int &lr, int &lg,
int &lb, int &hr, int &hg, int &hb) {
if (grayscale_flag) {
const int fr = pSrc_pixels[0].r;
const int fr = pSrc_pixels[0].R();
// Grayscale blocks are a common enough case to specialize.
// Grayscale blocks are A() common enough case to specialize.
if ((max_r - min_r) < 2) {
lr = lb = hr = hb = scale8To5(fr);
lg = hg = scale8To6(fr);
@ -1481,7 +1482,7 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
vec3F l, h;
if (big_chan == 0) {
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R(), g = pSrc_pixels[i].G(), b = pSrc_pixels[i].B();
sum_xy_r += r * r, sum_xy_g += r * g, sum_xy_b += r * b;
}
@ -1522,7 +1523,7 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
h.c[0] = fmax_chan_val;
} else if (big_chan == 1) {
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R(), g = pSrc_pixels[i].G(), b = pSrc_pixels[i].B();
sum_xy_r += g * r, sum_xy_g += g * g, sum_xy_b += g * b;
}
@ -1563,7 +1564,7 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
h.c[1] = fmax_chan_val;
} else {
for (uint32_t i = 0; i < 16; i++) {
const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R(), g = pSrc_pixels[i].G(), b = pSrc_pixels[i].B();
sum_xy_r += b * r, sum_xy_g += b * g, sum_xy_b += b * b;
}
@ -1631,9 +1632,9 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
int icov_xz = 0, icov_yz = 0;
for (uint32_t i = 0; i < 16; i++) {
int r = (int)pSrc_pixels[i].r - avg_r;
int g = (int)pSrc_pixels[i].g - avg_g;
int b = (int)pSrc_pixels[i].b - avg_b;
int r = (int)pSrc_pixels[i].R() - avg_r;
int g = (int)pSrc_pixels[i].G() - avg_g;
int b = (int)pSrc_pixels[i].B() - avg_b;
icov_xz += r * b;
icov_yz += g * b;
}
@ -1669,9 +1670,9 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
int icov_xz = 0, icov_yz = 0;
for (uint32_t i = 0; i < 16; i++) {
int r = (int)pSrc_pixels[i].r - avg_r;
int g = (int)pSrc_pixels[i].g - avg_g;
int b = (int)pSrc_pixels[i].b - avg_b;
int r = (int)pSrc_pixels[i].R() - avg_r;
int g = (int)pSrc_pixels[i].G() - avg_g;
int b = (int)pSrc_pixels[i].B() - avg_b;
icov_xz += r * b;
icov_yz += g * b;
}
@ -1681,7 +1682,7 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
int x1 = max_r;
int y1 = max_g;
// swap r and g min and max to align principal axis
// swap R() and G() min and max to align principal axis
if (icov_xz < 0) std::swap(x0, x1);
if (icov_yz < 0) std::swap(y0, y1);
@ -1694,14 +1695,14 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
hg = scale8To6(y1);
hb = scale8To5(max_b);
} else {
// Select 2 colors along the principle axis. (There must be a faster/simpler way.)
// Select 2 colors along the principle axis. (There must be A() faster/simpler way.)
uint32_t low_c = 0, high_c = 0;
int icov[6] = {0, 0, 0, 0, 0, 0};
for (uint32_t i = 0; i < 16; i++) {
int r = (int)pSrc_pixels[i].r - avg_r;
int g = (int)pSrc_pixels[i].g - avg_g;
int b = (int)pSrc_pixels[i].b - avg_b;
int r = (int)pSrc_pixels[i].R() - avg_r;
int g = (int)pSrc_pixels[i].G() - avg_g;
int b = (int)pSrc_pixels[i].B() - avg_b;
icov[0] += r * r;
icov[1] += r * g;
icov[2] += r * b;
@ -1748,10 +1749,10 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
saxis_b = (int)((uint32_t)saxis_b << 4U);
for (uint32_t i = 0; i < 16; i += 4) {
int dot0 = ((pSrc_pixels[i].r * saxis_r + pSrc_pixels[i].g * saxis_g + pSrc_pixels[i].b * saxis_b) & ~0xF) + i;
int dot1 = ((pSrc_pixels[i + 1].r * saxis_r + pSrc_pixels[i + 1].g * saxis_g + pSrc_pixels[i + 1].b * saxis_b) & ~0xF) + i + 1;
int dot2 = ((pSrc_pixels[i + 2].r * saxis_r + pSrc_pixels[i + 2].g * saxis_g + pSrc_pixels[i + 2].b * saxis_b) & ~0xF) + i + 2;
int dot3 = ((pSrc_pixels[i + 3].r * saxis_r + pSrc_pixels[i + 3].g * saxis_g + pSrc_pixels[i + 3].b * saxis_b) & ~0xF) + i + 3;
int dot0 = ((pSrc_pixels[i].R() * saxis_r + pSrc_pixels[i].G() * saxis_g + pSrc_pixels[i].B() * saxis_b) & ~0xF) + i;
int dot1 = ((pSrc_pixels[i + 1].R() * saxis_r + pSrc_pixels[i + 1].G() * saxis_g + pSrc_pixels[i + 1].B() * saxis_b) & ~0xF) + i + 1;
int dot2 = ((pSrc_pixels[i + 2].R() * saxis_r + pSrc_pixels[i + 2].G() * saxis_g + pSrc_pixels[i + 2].B() * saxis_b) & ~0xF) + i + 2;
int dot3 = ((pSrc_pixels[i + 3].R() * saxis_r + pSrc_pixels[i + 3].G() * saxis_g + pSrc_pixels[i + 3].B() * saxis_b) & ~0xF) + i + 3;
int min_d01 = std::min(dot0, dot1);
int max_d01 = std::max(dot0, dot1);
@ -1768,13 +1769,13 @@ static inline void encode_bc1_pick_initial(const Color32 *pSrc_pixels, uint32_t
low_c = low_dot & 15;
high_c = high_dot & 15;
lr = scale8To5(pSrc_pixels[low_c].r);
lg = scale8To6(pSrc_pixels[low_c].g);
lb = scale8To5(pSrc_pixels[low_c].b);
lr = scale8To5(pSrc_pixels[low_c].R());
lg = scale8To6(pSrc_pixels[low_c].G());
lb = scale8To5(pSrc_pixels[low_c].B());
hr = scale8To5(pSrc_pixels[high_c].r);
hg = scale8To6(pSrc_pixels[high_c].g);
hb = scale8To5(pSrc_pixels[high_c].b);
hr = scale8To5(pSrc_pixels[high_c].R());
hg = scale8To6(pSrc_pixels[high_c].G());
hb = scale8To5(pSrc_pixels[high_c].B());
}
}
@ -1798,7 +1799,7 @@ static const int8_t s_adjacent_voxels[16][4] = {
};
// From icbc's high quality mode.
static inline void encode_bc1_endpoint_search(const Color32 *pSrc_pixels, bool any_black_pixels, uint32_t flags, bc1_encode_results &results,
static inline void encode_bc1_endpoint_search(const Color *pSrc_pixels, bool any_black_pixels, uint32_t flags, bc1_encode_results &results,
uint32_t cur_err) {
int &lr = results.lr, &lg = results.lg, &lb = results.lb, &hr = results.hr, &hg = results.hg, &hb = results.hb;
uint8_t *sels = results.sels;
@ -1854,16 +1855,16 @@ static inline void encode_bc1_endpoint_search(const Color32 *pSrc_pixels, bool a
void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t total_orderings_to_try, uint32_t total_orderings_to_try3) {
assert(g_initialized);
const Color32 *pSrc_pixels = (const Color32 *)pPixels;
const Color *pSrc_pixels = (const Color *)pPixels;
BC1Block *pDst_block = static_cast<BC1Block *>(pDst);
int avg_r, avg_g, avg_b, min_r, min_g, min_b, max_r, max_g, max_b;
const uint32_t fr = pSrc_pixels[0].r, fg = pSrc_pixels[0].g, fb = pSrc_pixels[0].b;
const uint32_t fr = pSrc_pixels[0].R(), fg = pSrc_pixels[0].G(), fb = pSrc_pixels[0].B();
uint32_t j;
for (j = 15; j >= 1; --j)
if ((pSrc_pixels[j].r != fr) || (pSrc_pixels[j].g != fg) || (pSrc_pixels[j].b != fb)) break;
if ((pSrc_pixels[j].R() != fr) || (pSrc_pixels[j].G() != fg) || (pSrc_pixels[j].B() != fb)) break;
if (j == 0) {
encode_bc1_solid_block(pDst, fr, fg, fb, (flags & (cEncodeBC1Use3ColorBlocks | cEncodeBC1Use3ColorBlocksForBlackPixels)) != 0);
@ -1879,7 +1880,7 @@ void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t tot
uint32_t any_black_pixels = (fr | fg | fb) < 4;
for (uint32_t i = 1; i < 16; i++) {
const int r = pSrc_pixels[i].r, g = pSrc_pixels[i].g, b = pSrc_pixels[i].b;
const int r = pSrc_pixels[i].R(), g = pSrc_pixels[i].G(), b = pSrc_pixels[i].B();
grayscale_flag &= ((r == g) && (r == b));
any_black_pixels |= ((r | g | b) < 4);
@ -1928,7 +1929,7 @@ void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t tot
vec3F xl, xh;
if (!compute_least_squares_endpoints4_rgb(pSrc_pixels, sels, &xl, &xh, total_r, total_g, total_b)) {
// All selectors equal - treat it as a solid block which should always be equal or better.
// All selectors equal - treat it as A() solid block which should always be equal or better.
trial_lr = g_bc1_match5_equals_1[avg_r].m_hi;
trial_lg = g_bc1_match6_equals_1[avg_g].m_hi;
trial_lb = g_bc1_match5_equals_1[avg_b].m_hi;
@ -1981,7 +1982,7 @@ void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t tot
vec3F xl, xh;
if (!compute_least_squares_endpoints4_rgb(pSrc_pixels, round_sels, &xl, &xh, total_r, total_g, total_b)) {
// All selectors equal - treat it as a solid block which should always be equal or better.
// All selectors equal - treat it as A() solid block which should always be equal or better.
trial_lr = g_bc1_match5_equals_1[avg_r].m_hi;
trial_lg = g_bc1_match6_equals_1[avg_g].m_hi;
trial_lb = g_bc1_match5_equals_1[avg_b].m_hi;
@ -2068,9 +2069,9 @@ void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t tot
int dots[16];
for (uint32_t i = 0; i < 16; i++) {
int r = pSrc_pixels[i].r;
int g = pSrc_pixels[i].g;
int b = pSrc_pixels[i].b;
int r = pSrc_pixels[i].R();
int g = pSrc_pixels[i].G();
int b = pSrc_pixels[i].B();
int d = 0x1000000 + (r * ar + g * ag + b * ab);
assert(d >= 0);
dots[i] = (d << 4) + i;
@ -2087,9 +2088,9 @@ void encode_bc1(void *pDst, const uint8_t *pPixels, uint32_t flags, uint32_t tot
g_sum[i] = g;
b_sum[i] = b;
r += pSrc_pixels[p].r;
g += pSrc_pixels[p].g;
b += pSrc_pixels[p].b;
r += pSrc_pixels[p].R();
g += pSrc_pixels[p].G();
b += pSrc_pixels[p].B();
}
r_sum[16] = total_r;
@ -2336,13 +2337,13 @@ void encode_bc3(uint32_t level, BC3Block *pDst, const uint8_t *pPixels) {
void encode_bc5(BC5Block *pDst, const uint8_t *pPixels, uint32_t chan0, uint32_t chan1, uint32_t stride) {
assert(g_initialized);
encode_bc4(&pDst->r_block, pPixels + chan0, stride);
encode_bc4(&pDst->g_block, pPixels + chan1, stride);
encode_bc4(&pDst->chan0_block, pPixels + chan0, stride);
encode_bc4(&pDst->chan1_block, pPixels + chan1, stride);
}
// Returns true if the block uses 3 color punchthrough alpha mode.
bool unpack_bc1(const void *pBlock_bits, void *pPixels, bool set_alpha, bc1_approx_mode mode) {
Color32 *pDst_pixels = static_cast<Color32 *>(pPixels);
Color *pDst_pixels = static_cast<Color *>(pPixels);
static_assert(sizeof(BC1Block) == 8, "sizeof(BC1Block) == 8");
static_assert(sizeof(BC4Block) == 8, "sizeof(BC4Block) == 8");
@ -2352,7 +2353,7 @@ bool unpack_bc1(const void *pBlock_bits, void *pPixels, bool set_alpha, bc1_appr
const uint32_t l = pBlock->GetLowColor();
const uint32_t h = pBlock->GetHighColor();
Color32 c[4];
Color c[4];
const int cr0 = (l >> 11) & 31;
const int cg0 = (l >> 5) & 63;
@ -2371,43 +2372,43 @@ bool unpack_bc1(const void *pBlock_bits, void *pPixels, bool set_alpha, bc1_appr
bool used_punchthrough = false;
if (l > h) {
c[0].Set(r0, g0, b0, 255);
c[1].Set(r1, g1, b1, 255);
c[0].SetRGBA(r0, g0, b0, 255);
c[1].SetRGBA(r1, g1, b1, 255);
switch (mode) {
case bc1_approx_mode::cBC1Ideal:
c[2].Set((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255);
c[3].Set((r1 * 2 + r0) / 3, (g1 * 2 + g0) / 3, (b1 * 2 + b0) / 3, 255);
c[2].SetRGBA((r0 * 2 + r1) / 3, (g0 * 2 + g1) / 3, (b0 * 2 + b1) / 3, 255);
c[3].SetRGBA((r1 * 2 + r0) / 3, (g1 * 2 + g0) / 3, (b1 * 2 + b0) / 3, 255);
break;
case bc1_approx_mode::cBC1IdealRound4:
c[2].Set((r0 * 2 + r1 + 1) / 3, (g0 * 2 + g1 + 1) / 3, (b0 * 2 + b1 + 1) / 3, 255);
c[3].Set((r1 * 2 + r0 + 1) / 3, (g1 * 2 + g0 + 1) / 3, (b1 * 2 + b0 + 1) / 3, 255);
c[2].SetRGBA((r0 * 2 + r1 + 1) / 3, (g0 * 2 + g1 + 1) / 3, (b0 * 2 + b1 + 1) / 3, 255);
c[3].SetRGBA((r1 * 2 + r0 + 1) / 3, (g1 * 2 + g0 + 1) / 3, (b1 * 2 + b0 + 1) / 3, 255);
break;
case bc1_approx_mode::cBC1NVidia:
c[2].Set(interp_5_nv(cr0, cr1), interp_6_nv(g0, g1), interp_5_nv(cb0, cb1), 255);
c[3].Set(interp_5_nv(cr1, cr0), interp_6_nv(g1, g0), interp_5_nv(cb1, cb0), 255);
c[2].SetRGBA(interp_5_nv(cr0, cr1), interp_6_nv(g0, g1), interp_5_nv(cb0, cb1), 255);
c[3].SetRGBA(interp_5_nv(cr1, cr0), interp_6_nv(g1, g0), interp_5_nv(cb1, cb0), 255);
break;
case bc1_approx_mode::cBC1AMD:
c[2].Set(interp_5_6_amd(r0, r1), interp_5_6_amd(g0, g1), interp_5_6_amd(b0, b1), 255);
c[3].Set(interp_5_6_amd(r1, r0), interp_5_6_amd(g1, g0), interp_5_6_amd(b1, b0), 255);
c[2].SetRGBA(interp_5_6_amd(r0, r1), interp_5_6_amd(g0, g1), interp_5_6_amd(b0, b1), 255);
c[3].SetRGBA(interp_5_6_amd(r1, r0), interp_5_6_amd(g1, g0), interp_5_6_amd(b1, b0), 255);
break;
}
} else {
c[0].Set(r0, g0, b0, 255);
c[1].Set(r1, g1, b1, 255);
c[0].SetRGBA(r0, g0, b0, 255);
c[1].SetRGBA(r1, g1, b1, 255);
switch (mode) {
case bc1_approx_mode::cBC1Ideal:
case bc1_approx_mode::cBC1IdealRound4:
c[2].Set((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
c[2].SetRGBA((r0 + r1) / 2, (g0 + g1) / 2, (b0 + b1) / 2, 255);
break;
case bc1_approx_mode::cBC1NVidia:
c[2].Set(interp_half_5_nv(cr0, cr1), interp_half_6_nv(g0, g1), interp_half_5_nv(cb0, cb1), 255);
c[2].SetRGBA(interp_half_5_nv(cr0, cr1), interp_half_6_nv(g0, g1), interp_half_5_nv(cb0, cb1), 255);
break;
case bc1_approx_mode::cBC1AMD:
c[2].Set(interp_half_5_6_amd(r0, r1), interp_half_5_6_amd(g0, g1), interp_half_5_6_amd(b0, b1), 255);
c[2].SetRGBA(interp_half_5_6_amd(r0, r1), interp_half_5_6_amd(g0, g1), interp_half_5_6_amd(b0, b1), 255);
break;
}
c[3].Set(0, 0, 0, 0);
c[3].SetRGBA(0, 0, 0, 0);
used_punchthrough = true;
}
@ -2420,10 +2421,10 @@ bool unpack_bc1(const void *pBlock_bits, void *pPixels, bool set_alpha, bc1_appr
}
} else {
for (uint32_t y = 0; y < 4; y++, pDst_pixels += 4) {
pDst_pixels[0].Set(c[pBlock->GetSelector(0, y)]);
pDst_pixels[1].Set(c[pBlock->GetSelector(1, y)]);
pDst_pixels[2].Set(c[pBlock->GetSelector(2, y)]);
pDst_pixels[3].Set(c[pBlock->GetSelector(3, y)]);
pDst_pixels[0].SetRGBA(c[pBlock->GetSelector(0, y)]);
pDst_pixels[1].SetRGBA(c[pBlock->GetSelector(1, y)]);
pDst_pixels[2].SetRGBA(c[pBlock->GetSelector(2, y)]);
pDst_pixels[3].SetRGBA(c[pBlock->GetSelector(3, y)]);
}
}
@ -2435,7 +2436,7 @@ void unpack_bc4(const void *pBlock_bits, uint8_t *pPixels, uint32_t stride) {
const BC4Block *pBlock = static_cast<const BC4Block *>(pBlock_bits);
auto sel_values = BC4Block::GetBlockValues(pBlock->GetLowAlpha(), pBlock->GetHighAlpha());
auto sel_values = BC4Block::GetValues(pBlock->GetLowAlpha(), pBlock->GetHighAlpha());
const uint64_t selector_bits = pBlock->GetSelectorBits();
@ -2449,13 +2450,13 @@ void unpack_bc4(const void *pBlock_bits, uint8_t *pPixels, uint32_t stride) {
// Returns false if the block uses 3-color punchthrough alpha mode, which isn't supported on some GPU's for BC3.
bool unpack_bc3(const void *pBlock_bits, void *pPixels, bc1_approx_mode mode) {
Color32 *pDst_pixels = static_cast<Color32 *>(pPixels);
Color *pDst_pixels = static_cast<Color *>(pPixels);
bool success = true;
if (unpack_bc1((const uint8_t *)pBlock_bits + sizeof(BC4Block), pDst_pixels, true, mode)) success = false;
unpack_bc4(pBlock_bits, &pDst_pixels[0].a, sizeof(Color32));
unpack_bc4(pBlock_bits, &pDst_pixels[0].A(), sizeof(Color));
return success;
}

@ -0,0 +1,25 @@
/* Python-rgbcx 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 "BC1/BC1Decoder.h"
#include "BC3/BC3Decoder.h"
#include "BC4/BC4Decoder.h"
#include "BC5/BC5Decoder.h"

@ -1,7 +1,7 @@
// File: bc7decomp.c - Richard Geldreich, Jr. 3/31/2020 - MIT license or public domain (see end of file)
#pragma GCC diagnostic ignored "-Weverything"
#include "bc7decomp.h"
namespace bc7decomp
namespace bc7decomp
{
const uint32_t g_bc7_weights2[4] = { 0, 21, 43, 64 };

@ -185,7 +185,7 @@ class image_u8 {
for (uint32_t y = 0; y < m_height; y++) {
for (uint32_t x = 0; x < m_width; x++) {
color_quad_u8 tmp((*this)(x, y));
(*this)(x, y).set(tmp[r], tmp[g], tmp[b], tmp[a]);
(*this)(x, y).SetRGBA(tmp[r], tmp[g], tmp[b], tmp[a]);
}
}
@ -657,7 +657,7 @@ int main(int argc, char *argv[]) {
source_image.get_block(bx, by, 4, 4, pixels);
if (!has_alpha) {
for (uint32_t i = 0; i < 16; i++) {
if (pixels[i].m_c[3] < 255) {
if (pixels[i][3] < 255) {
has_alpha = true;
break;
}
@ -668,25 +668,25 @@ int main(int argc, char *argv[]) {
case DXGI_FORMAT_BC1_UNORM: {
block8 *pBlock = &packed_image8[bx + by * blocks_x];
rgbcx::encode_bc1(bc1_quality_level, pBlock, &pixels[0].m_c[0], use_bc1_3color_mode, use_bc1_3color_mode_for_black);
rgbcx::encode_bc1(bc1_quality_level, pBlock, &pixels[0][0], use_bc1_3color_mode, use_bc1_3color_mode_for_black);
break;
}
case DXGI_FORMAT_BC3_UNORM: {
BC3Block *pBlock = reinterpret_cast<BC3Block *>(&packed_image16[bx + by * blocks_x]);
rgbcx::encode_bc3(bc1_quality_level, pBlock, &pixels[0].m_c[0]);
rgbcx::encode_bc3(bc1_quality_level, pBlock, &pixels[0][0]);
break;
}
case DXGI_FORMAT_BC4_UNORM: {
block8 *pBlock = &packed_image8[bx + by * blocks_x];
rgbcx::encode_bc4(pBlock, &pixels[0].m_c[bc45_channel0], 4);
rgbcx::encode_bc4(pBlock, &pixels[0][bc45_channel0], 4);
break;
}
case DXGI_FORMAT_BC5_UNORM: {
block16 *pBlock = &packed_image16[bx + by * blocks_x];
rgbcx::encode_bc5(reinterpret_cast<BC5Block *>(pBlock), &pixels[0].m_c[0], bc45_channel0, bc45_channel1, 4);
rgbcx::encode_bc5(reinterpret_cast<BC5Block *>(pBlock), &pixels[0][0], bc45_channel0, bc45_channel1, 4);
break;
}
case DXGI_FORMAT_BC7_UNORM: {
@ -735,37 +735,62 @@ int main(int argc, char *argv[]) {
image_u8 unpacked_image(source_image.width(), source_image.height());
bool punchthrough_flag = false;
for (uint32_t by = 0; by < blocks_y; by++) {
for (uint32_t bx = 0; bx < blocks_x; bx++) {
void *pBlock = (bytes_per_block == 16) ? (void *)&packed_image16[bx + by * blocks_x] : (void *)&packed_image8[bx + by * blocks_x];
color_quad_u8 unpacked_pixels[16];
for (uint32_t i = 0; i < 16; i++) unpacked_pixels[i].set(0, 0, 0, 255);
switch (dxgi_format) {
case DXGI_FORMAT_BC1_UNORM:
rgbcx::unpack_bc1(pBlock, unpacked_pixels, true, bc1_mode);
break;
case DXGI_FORMAT_BC3_UNORM:
if (!rgbcx::unpack_bc3(pBlock, unpacked_pixels, bc1_mode)) punchthrough_flag = true;
break;
case DXGI_FORMAT_BC4_UNORM:
rgbcx::unpack_bc4(pBlock, &unpacked_pixels[0][0], 4);
break;
case DXGI_FORMAT_BC5_UNORM:
rgbcx::unpack_bc5(pBlock, &unpacked_pixels[0][0], 0, 1, 4);
break;
case DXGI_FORMAT_BC7_UNORM:
bc7decomp::unpack_bc7((const uint8_t *)pBlock, (bc7decomp::color_rgba *)unpacked_pixels);
break;
default:
assert(0);
break;
}
auto decoder_bc1 = rgbcx::BC1Decoder();
auto decoder_bc3 = rgbcx::BC3Decoder();
auto decoder_bc4 = rgbcx::BC4Decoder();
auto decoder_bc5 = rgbcx::BC5Decoder();
switch (dxgi_format) {
case DXGI_FORMAT_BC1_UNORM:
unpacked_image.set_pixels(decoder_bc1.DecodeImage(reinterpret_cast<uint8_t *>(&packed_image8[0]), source_image.width(), source_image.height()));
break;
case DXGI_FORMAT_BC3_UNORM:
unpacked_image.set_pixels(
decoder_bc3.DecodeImage(reinterpret_cast<uint8_t *>(&packed_image16[0]), source_image.width(), source_image.height()));
break;
case DXGI_FORMAT_BC4_UNORM:
unpacked_image.set_pixels(decoder_bc4.DecodeImage(reinterpret_cast<uint8_t *>(&packed_image8[0]), source_image.width(), source_image.height()));
break;
case DXGI_FORMAT_BC5_UNORM:
unpacked_image.set_pixels(
decoder_bc5.DecodeImage(reinterpret_cast<uint8_t *>(&packed_image16[0]), source_image.width(), source_image.height()));
break;
default:
assert(0);
break;
}
unpacked_image.set_block(bx, by, 4, 4, unpacked_pixels);
} // bx
} // by
// for (uint32_t by = 0; by < blocks_y; by++) {
// for (uint32_t bx = 0; bx < blocks_x; bx++) {
// void *pBlock = (bytes_per_block == 16) ? (void *)&packed_image16[bx + by * blocks_x] : (void *)&packed_image8[bx + by * blocks_x];
//
// color_quad_u8 unpacked_pixels[16];
// for (uint32_t i = 0; i < 16; i++) unpacked_pixels[i].set(0, 0, 0, 255);
//
// switch (dxgi_format) {
// case DXGI_FORMAT_BC1_UNORM:
// rgbcx::unpack_bc1(pBlock, unpacked_pixels, true, bc1_mode);
// break;
// case DXGI_FORMAT_BC3_UNORM:
// if (!rgbcx::unpack_bc3(pBlock, unpacked_pixels, bc1_mode)) punchthrough_flag = true;
// break;
// case DXGI_FORMAT_BC4_UNORM:
// rgbcx::unpack_bc4(pBlock, &unpacked_pixels[0][0], 4);
// break;
// case DXGI_FORMAT_BC5_UNORM:
// rgbcx::unpack_bc5(pBlock, &unpacked_pixels[0][0], 0, 1, 4);
// break;
// case DXGI_FORMAT_BC7_UNORM:
// bc7decomp::unpack_bc7((const uint8_t *)pBlock, (bc7decomp::color_rgba *)unpacked_pixels);
// break;
// default:
// assert(0);
// break;
// }
//
// unpacked_image.set_block(bx, by, 4, 4, unpacked_pixels);
// } // bx
// } // by
if ((punchthrough_flag) && (dxgi_format == DXGI_FORMAT_BC3_UNORM))
fprintf(stderr, "Warning: BC3 mode selected, but rgbcx::unpack_bc3() returned one or more blocks using 3-color mode!\n");
@ -807,7 +832,9 @@ int main(int argc, char *argv[]) {
if (png_alpha_output_filename.size()) {
image_u8 unpacked_image_alpha(unpacked_image);
for (uint32_t y = 0; y < unpacked_image_alpha.height(); y++)
for (uint32_t x = 0; x < unpacked_image_alpha.width(); x++) unpacked_image_alpha(x, y).set(unpacked_image_alpha(x, y)[3], 255);
for (uint32_t x = 0; x < unpacked_image_alpha.width(); x++) {
uint8_t alpha = unpacked_image_alpha(x, y).A();
unpacked_image_alpha(x, y).SetRGBA(alpha, alpha, alpha, 255); }
if (!save_png(png_alpha_output_filename.c_str(), unpacked_image_alpha, false))
failed = true;
@ -818,3 +845,4 @@ int main(int argc, char *argv[]) {
return failed ? EXIT_FAILURE : EXIT_SUCCESS;
}
#pragma GCC diagnostic pop

@ -18,66 +18,132 @@
*/
#pragma once
#include <cassert>
#include <cstdint>
#include <limits>
#include <type_traits>
#include "ndebug.h"
static inline uint32_t iabs(int32_t i) { return (i < 0) ? static_cast<uint32_t>(-i) : static_cast<uint32_t>(i); }
static inline uint64_t iabs(int64_t i) { return (i < 0) ? static_cast<uint64_t>(-i) : static_cast<uint64_t>(i); }
#define UINT5_MAX 0x1FU // 31
#define UINT6_MAX 0x3FU // 63
template <typename S> constexpr void Assert5Bit(S x) {
static_assert(std::is_unsigned<S>::value);
assert(x <= UINT5_MAX);
}
template <typename S> constexpr void Assert6Bit(S x) {
static_assert(std::is_unsigned<S>::value);
assert(x <= UINT6_MAX);
}
template <typename S> constexpr auto iabs(S i) {
using O = typename std::make_unsigned<S>::type;
return (i < 0) ? static_cast<O>(-i) : static_cast<O>(i);
}
/**
* Unpacks an unsigned integer into an array of smaller integers.
* @tparam I Input data type. Must be an unsigned integral type large enough to hold C * S bits.
* @tparam O Output data type. must be an unsigned integral type large enough to hold C bits..
* @tparam S Number of bits in each value.
* @tparam C Number of values to unpack.
* @param packed Packed integer input of type I.
* @return Unpacked std::array of type O and size C.
*/
template <typename I, typename O, size_t S, size_t C> constexpr auto Unpack(I packed) noexcept(ndebug) {
std::array<O, C> vals;
I mask = (1 << S) - 1;
for (int i = 0; i < C; i++) {
vals[i] = (packed >> (i * S)) & mask;
assert(vals[i] < 1 << S);
// type checking
static_assert(std::is_unsigned<I>::value, "Packed input type must be unsigned");
static_assert(std::is_unsigned<O>::value, "Unpacked output type must be unsigned");
static_assert(std::numeric_limits<I>::digits >= (C * S), "Packed input type must be big enough to represent the number of bits multiplied by count");
static_assert(std::numeric_limits<O>::digits >= S, "Unpacked output type must be big enough to represent the number of bits");
constexpr O mask = (1U << S) - 1U; // maximum value representable by S bits
std::array<O, C> vals; // output values array of size C
for (unsigned i = 0; i < C; i++) {
vals[i] = static_cast<O>(packed >> (i * S)) & mask;
assert(vals[i] <= mask);
}
return vals;
}
/**
* Packs an array of unsigned integers into a single integer.
* @tparam I Input data type. Must be an unsigned integral type large enough to hold C bits.
* @tparam O Output data type. must be an unsigned integral type large enough to hold C * S bits.
* @tparam S Number of bits in each value.
* @tparam C Number of values to unpack.
* @param vals Unpacked std::array of type I and size C.
* @return Packed integer input of type O.
*/
template <typename I, typename O, size_t S, size_t C> constexpr auto Pack(const std::array<I, C> &vals) noexcept(ndebug) {
O packed = 0;
for (int i = 0; i < C; i++) {
packed |= vals[i] << (i * S);
assert(vals[i] < 1 << S);
// type checking
static_assert(std::is_unsigned<I>::value, "Unpacked input type must be unsigned");
static_assert(std::is_unsigned<O>::value, "Packed output type must be unsigned");
static_assert(std::numeric_limits<I>::digits >= S, "Unpacked input type must be big enough to represent the number of bits");
static_assert(std::numeric_limits<O>::digits >= (C * S), "Packed output type must be big enough to represent the number of bits multiplied by count");
constexpr I max_input = (1U << S) - 1U; // maximum value representable by S bits
constexpr O max_output = (static_cast<O>(1U) << (C * S)) - 1U; // maximum value representable by S * C bits
O packed = 0; // output value of type O
for (unsigned i = 0; i < C; i++) {
assert(vals[i] <= max_input);
packed |= static_cast<O>(vals[i]) << (i * S);
}
assert(packed <= max_output);
return packed;
}
static inline uint8_t scale8To5(uint32_t v) {
template <size_t Size, int Op(int)> constexpr std::array<uint8_t, Size> ExpandArray() {
std::array<uint8_t, Size> res;
for (int i = 0; i < Size; i++) { res[i] = Op(i); }
return res;
}
template <typename S> constexpr S scale8To5(S v) {
v = v * 31 + 128;
return (uint8_t)((v + (v >> 8)) >> 8);
return static_cast<S>((v + (v >> 8)) >> 8);
}
static inline uint8_t scale8To6(uint32_t v) {
template <typename S> constexpr S scale8To6(S v) {
v = v * 63 + 128;
return (uint8_t)((v + (v >> 8)) >> 8);
return static_cast<S>((v + (v >> 8)) >> 8);
}
static constexpr int scale5To8(int v) { return (v << 3) | (v >> 2); }
static constexpr int scale6To8(int v) { return (v << 2) | (v >> 4); }
template <typename S> constexpr S scale5To8(S v) {
Assert5Bit(v);
assert(v <= UINT5_MAX);
return static_cast<S>((v << 3) | (v >> 2));
}
template <typename S> constexpr S scale6To8(S v) {
Assert6Bit(v);
return static_cast<S>((v << 2) | (v >> 4));
}
template <typename S> inline S maximum(S a, S b) { return (a > b) ? a : b; }
template <typename S> inline S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); }
template <typename S> inline S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); }
template <typename S> constexpr S maximum(S a, S b) { return (a > b) ? a : b; }
template <typename S> constexpr S maximum(S a, S b, S c) { return maximum(maximum(a, b), c); }
template <typename S> constexpr S maximum(S a, S b, S c, S d) { return maximum(maximum(maximum(a, b), c), d); }
template <typename S> inline S minimum(S a, S b) { return (a < b) ? a : b; }
template <typename S> inline S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); }
template <typename S> inline S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); }
template <typename S> constexpr S minimum(S a, S b) { return (a < b) ? a : b; }
template <typename S> constexpr S minimum(S a, S b, S c) { return minimum(minimum(a, b), c); }
template <typename S> constexpr S minimum(S a, S b, S c, S d) { return minimum(minimum(minimum(a, b), c), d); }
template <typename T> inline T square(T a) { return a * a; }
template <typename T> constexpr T square(T a) { return a * a; }
static inline float clampf(float value, float low, float high) {
constexpr float clampf(float value, float low, float high) {
if (value < low)
value = low;
else if (value > high)
value = high;
return value;
}
static inline uint8_t clamp255(int32_t i) { return (uint8_t)((i & 0xFFFFFF00U) ? (~(i >> 31)) : i); }
constexpr uint8_t clamp255(int32_t i) { return static_cast<uint8_t>((static_cast<unsigned int>(i) & 0xFFFFFF00U) ? (~(i >> 31)) : i); }
template <typename S> inline S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); }
static inline int32_t clampi(int32_t value, int32_t low, int32_t high) {
template <typename S> constexpr S clamp(S value, S low, S high) { return (value < low) ? low : ((value > high) ? high : value); }
constexpr int32_t clampi(int32_t value, int32_t low, int32_t high) {
if (value < low)
value = low;
else if (value > high)
@ -85,7 +151,7 @@ static inline int32_t clampi(int32_t value, int32_t low, int32_t high) {
return value;
}
static inline int squarei(int a) { return a * a; }
static inline int absi(int a) { return (a < 0) ? -a : a; }
constexpr int squarei(int a) { return a * a; }
constexpr int absi(int a) { return (a < 0) ? -a : a; }
template <typename F> inline F lerp(F a, F b, F s) { return a + (b - a) * s; }
template <typename F> constexpr F lerp(F a, F b, F s) { return a + (b - a) * s; }

Loading…
Cancel
Save