mirror of
https://github.com/drewcassidy/quicktex.git
synced 2024-09-13 06:37:34 +00:00
Fix all warnings
I mean it doesnt work, but it also doesnt produce warnings
This commit is contained in:
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 ()
|
||||
|
74
LICENSE.md
74
LICENSE.md
@ -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> {
|
||||
public:
|
||||
BC1Decoder(const Interpolator &interpolator, bool write_alpha = false) : _interpolator(interpolator), _write_alpha(write_alpha) {}
|
||||
BC1Decoder() : BC1Decoder(Interpolator()) {}
|
||||
|
||||
void DecodeBlock(Color4x4 *dest, BC1Block *const block) const noexcept(ndebug) override;
|
||||
namespace rgbcx {
|
||||
class BC1Decoder final : public BlockDecoder<BC1Block, 4, 4> {
|
||||
public:
|
||||
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;
|
||||
|
||||
constexpr const Interpolator &GetInterpolator() const { return _interpolator; }
|
||||
constexpr bool WritesAlpha() const { return _write_alpha; }
|
31
src/BC3/BC3Decoder.cpp
Normal file
31
src/BC3/BC3Decoder.cpp
Normal file
@ -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
|
41
src/BC3/BC3Decoder.h
Normal file
41
src/BC3/BC3Decoder.h
Normal file
@ -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
|
39
src/BC4/BC4Decoder.cpp
Normal file
39
src/BC4/BC4Decoder.cpp
Normal file
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
40
src/BC4/BC4Decoder.h
Normal file
40
src/BC4/BC4Decoder.h
Normal file
@ -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
|
31
src/BC5/BC5Decoder.cpp
Normal file
31
src/BC5/BC5Decoder.cpp
Normal file
@ -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
|
45
src/BC5/BC5Decoder.h
Normal file
45
src/BC5/BC5Decoder.h
Normal file
@ -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
|
80
src/BlockDecoder.h
Normal file
80
src/BlockDecoder.h
Normal file
@ -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;
|
||||
};
|
||||
|
81
src/Color.cpp
Normal file
81
src/Color.cpp
Normal file
@ -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
|
85
src/Color.h
Normal file
85
src/Color.h
Normal file
@ -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()]); }
|
||||
}
|
||||
private:
|
||||
std::array<Color, 4> _colors;
|
||||
};
|
||||
|
||||
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]); }
|
||||
}
|
||||
|
||||
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>;
|
||||
|
22
src/Image.cpp
Normal file
22
src/Image.cpp
Normal file
@ -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
|
65
src/blocks.h
65
src/blocks.h
@ -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
|
68
src/color.h
68
src/color.h
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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<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<Color32, 4> InterpolateBC1(uint16_t low, uint16_t high) const;
|
||||
virtual std::array<Color, 4> InterpolateBC1(uint16_t low, uint16_t high) const;
|
||||
|
||||
/**
|
||||
* Gets the type of an interpolator
|
||||
* @return The interpolator type
|
||||
*/
|
||||
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
|
255
src/rgbcx.cpp
255
src/rgbcx.cpp
@ -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;
|
||||
}
|
||||
|
25
src/rgbcxDecoders.h
Normal file
25
src/rgbcxDecoders.h
Normal file
@ -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];
|
||||
auto decoder_bc1 = rgbcx::BC1Decoder();
|
||||
auto decoder_bc3 = rgbcx::BC3Decoder();
|
||||
auto decoder_bc4 = rgbcx::BC4Decoder();
|
||||
auto decoder_bc5 = rgbcx::BC5Decoder();
|
||||
|
||||
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:
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
// 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
|
128
src/util.h
128
src/util.h
@ -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…
Reference in New Issue
Block a user