mirror of
https://invent.kde.org/frameworks/kimageformats.git
synced 2026-11-01 15:58:47 -05:00
DDS: vendoring and using bcdec.h for DDS BC decompression
This can also make it easier to support BC6H in the future.
This commit is contained in:
committed by
Mirco Miranda
parent
477e9ea542
commit
67ee4cb720
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -45,7 +45,7 @@ endif()
|
||||
##################################
|
||||
|
||||
if(KIMAGEFORMATS_DDS)
|
||||
kimageformats_add_plugin(kimg_dds SOURCES dds.cpp scanlineconverter.cpp)
|
||||
kimageformats_add_plugin(kimg_dds SOURCES dds.cpp bcdec.cpp scanlineconverter.cpp)
|
||||
endif()
|
||||
|
||||
##################################
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
This file is part of the KDE project
|
||||
SPDX-FileCopyrightText: 2022 Sergii "iOrange" Kudlai
|
||||
|
||||
SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
// Single-header BCn decoder used by the DDS plugin (see bcdec.h).
|
||||
|
||||
#define BCDEC_IMPLEMENTATION
|
||||
#include "bcdec.h"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
SPDX-FileCopyrightText: 2022 Sergii "iOrange" Kudlai
|
||||
SPDX-License-Identifier: MIT
|
||||
+27
-366
@@ -9,6 +9,7 @@
|
||||
|
||||
// Forked from Qt 5.6 branch
|
||||
|
||||
#include "bcdec.h"
|
||||
#include "dds_p.h"
|
||||
#include "util_p.h"
|
||||
#include "scanlineconverter_p.h"
|
||||
@@ -965,32 +966,25 @@ static QImage readATI2(QDataStream &s, quint32 width, quint32 height)
|
||||
return image;
|
||||
}
|
||||
|
||||
quint8 block[16];
|
||||
quint8 texel[16 * 2];
|
||||
for (quint32 i = 0; i < height; i += 4) {
|
||||
for (quint32 j = 0; j < width; j += 4) {
|
||||
quint64 alpha1;
|
||||
quint64 alpha2;
|
||||
s >> alpha1;
|
||||
s >> alpha2;
|
||||
if (s.status() != QDataStream::Ok)
|
||||
if (s.readRawData(reinterpret_cast<char *>(block), sizeof(block)) != int(sizeof(block)))
|
||||
return QImage();
|
||||
|
||||
QRgb arr[16];
|
||||
memset(arr, 0, sizeof(QRgb) * 16);
|
||||
setAlphaDXT<Five>(arr, alpha1);
|
||||
for (int k = 0; k < 16; ++k) {
|
||||
quint8 a = qAlpha(arr[k]);
|
||||
arr[k] = qRgba(0, 0, a, 0);
|
||||
}
|
||||
setAlphaDXT<Five>(arr, alpha2);
|
||||
// BC5 (ATI2) stores two BC4 blocks: the first one is the second
|
||||
// normal component, the second one is the first normal component.
|
||||
bcdec_bc5(block, texel, 4 * 2);
|
||||
|
||||
const quint32 kMax = qMin<quint32>(4, height - i);
|
||||
const quint32 lMax = qMin<quint32>(4, width - j);
|
||||
for (quint32 k = 0; k < kMax; k++) {
|
||||
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
|
||||
for (quint32 l = 0; l < lMax; l++) {
|
||||
QRgb pixel = arr[k * 4 + l];
|
||||
const quint8 nx = qAlpha(pixel);
|
||||
const quint8 ny = qBlue(pixel);
|
||||
const quint8 *pixel = texel + (k * 4 + l) * 2;
|
||||
const quint8 nx = pixel[1];
|
||||
const quint8 ny = pixel[0];
|
||||
const quint8 nz = getNormalZ(nx, ny);
|
||||
line[j + l] = qRgb(nx, ny, nz);
|
||||
}
|
||||
@@ -1010,23 +1004,21 @@ static QImage readBC4(QDataStream &s, quint32 width, quint32 height)
|
||||
return image;
|
||||
}
|
||||
|
||||
quint8 block[8];
|
||||
quint8 texel[16];
|
||||
for (quint32 i = 0; i < height; i += 4) {
|
||||
for (quint32 j = 0; j < width; j += 4) {
|
||||
quint64 block;
|
||||
s >> block;
|
||||
if (s.status() != QDataStream::Ok)
|
||||
if (s.readRawData(reinterpret_cast<char *>(block), sizeof(block)) != int(sizeof(block)))
|
||||
return QImage();
|
||||
|
||||
QRgb arr[16];
|
||||
memset(arr, 0, sizeof(QRgb) * 16);
|
||||
setAlphaDXT<Five>(arr, block);
|
||||
bcdec_bc4(block, texel, 4);
|
||||
|
||||
const quint32 kMax = qMin<quint32>(4, height - i);
|
||||
const quint32 lMax = qMin<quint32>(4, width - j);
|
||||
for (quint32 k = 0; k < kMax; k++) {
|
||||
quint8 *line = reinterpret_cast<quint8 *>(image.scanLine(i + k));
|
||||
quint8 *line = image.scanLine(i + k);
|
||||
for (quint32 l = 0; l < lMax; l++) {
|
||||
line[j + l] = qAlpha(arr[k * 4 + l]);
|
||||
line[j + l] = texel[k * 4 + l];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1035,360 +1027,29 @@ static QImage readBC4(QDataStream &s, quint32 width, quint32 height)
|
||||
return image;
|
||||
}
|
||||
|
||||
/* *** BC7 ***
|
||||
* The decoder is implemented following the "BC7 Format" specification
|
||||
* (https://learn.microsoft.com/en-us/windows/win32/direct3d11/bc7-format).
|
||||
* The partition tables are the same described in the OpenGL ARB_texture_compression_bptc
|
||||
* extension (the ones on the Khronos registry data format page contain errors).
|
||||
*/
|
||||
|
||||
static inline quint64 bc7ReadU64(const quint8 *p)
|
||||
{
|
||||
return quint64(p[0]) | (quint64(p[1]) << 8) | (quint64(p[2]) << 16) | (quint64(p[3]) << 24)
|
||||
| (quint64(p[4]) << 32) | (quint64(p[5]) << 40) | (quint64(p[6]) << 48) | (quint64(p[7]) << 56);
|
||||
}
|
||||
|
||||
struct BC7BitStream {
|
||||
quint64 low = 0;
|
||||
quint64 high = 0;
|
||||
};
|
||||
|
||||
static inline int bc7ReadBits(BC7BitStream *bstream, int numBits)
|
||||
{
|
||||
const quint64 mask = (quint64(1) << numBits) - 1;
|
||||
const quint32 bits = bstream->low & mask;
|
||||
bstream->low >>= numBits;
|
||||
bstream->low |= (bstream->high & mask) << (64 - numBits);
|
||||
bstream->high >>= numBits;
|
||||
return bits;
|
||||
}
|
||||
|
||||
static inline int bc7Interpolate(int a, int b, const int *weights, int index)
|
||||
{
|
||||
return (a * (64 - weights[index]) + b * weights[index] + 32) >> 6;
|
||||
}
|
||||
|
||||
static QImage readBC7(QDataStream &s, quint32 width, quint32 height)
|
||||
{
|
||||
// Number of bits used to encode each endpoint per mode (RGB, Alpha).
|
||||
static const quint8 actualBitsCount[2][8] = {
|
||||
{ 4, 6, 5, 7, 5, 7, 7, 5 }, // RGBA
|
||||
{ 0, 0, 0, 0, 6, 8, 7, 5 } // Alpha
|
||||
};
|
||||
|
||||
// Modes that explicitly store P-bits.
|
||||
static const quint8 modesWithPBits = 0b11001011;
|
||||
|
||||
// Interpolation weights for 2, 3 and 4 bit indices.
|
||||
static const int weight2[] = { 0, 21, 43, 64 };
|
||||
static const int weight3[] = { 0, 9, 18, 27, 37, 46, 55, 64 };
|
||||
static const int weight4[] = { 0, 4, 9, 13, 17, 21, 26, 30, 34, 38, 43, 47, 51, 55, 60, 64 };
|
||||
|
||||
// Partition tables for the 2-subset and 3-subset modes. The MSB of each
|
||||
// value marks the fix-up index of the subset (the subset is in the low bits).
|
||||
static const quint8 partitionSets[2][64][4][4] = {
|
||||
{ // 2-subset
|
||||
{ {128, 0, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} },
|
||||
{ {128, 0, 0, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 129} },
|
||||
{ {128, 1, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 1, 129} },
|
||||
{ {128, 0, 1, 1}, {0, 1, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 1}, {0, 0, 1, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 0, 1, 1}, {0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 0, 1, 129} },
|
||||
{ {128, 0, 1, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 1}, { 0, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 1}, {0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 1}, {0, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 1, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 1, 1}, { 1, 1, 1, 1}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, {1, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {1, 1, 1, 129} },
|
||||
{ {128, 1, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 1, 0} },
|
||||
{ {128, 1, 129, 1}, {0, 0, 1, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 0}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 1, 0, 0}, {1, 1, 1, 0} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} },
|
||||
{ {128, 1, 1, 1}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {0, 0, 0, 129} },
|
||||
{ {128, 0, 129, 1}, {0, 0, 0, 1}, { 0, 0, 0, 1}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {1, 0, 0, 0}, {129, 0, 0, 0}, {1, 1, 0, 0} },
|
||||
{ {128, 1, 129, 0}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {0, 1, 1, 0} },
|
||||
{ {128, 0, 129, 1}, {0, 1, 1, 0}, { 0, 1, 1, 0}, {1, 1, 0, 0} },
|
||||
{ {128, 0, 0, 1}, {0, 1, 1, 1}, {129, 1, 1, 0}, {1, 0, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, {0, 0, 0, 0} },
|
||||
{ {128, 1, 129, 1}, {0, 0, 0, 1}, { 1, 0, 0, 0}, {1, 1, 1, 0} },
|
||||
{ {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} },
|
||||
{ {128, 1, 0, 1}, {0, 1, 0, 1}, { 0, 1, 0, 1}, {0, 1, 0, 129} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 0, 0}, {1, 1, 1, 129} },
|
||||
{ {128, 1, 0, 1}, {1, 0, 129, 0}, { 0, 1, 0, 1}, {1, 0, 1, 0} },
|
||||
{ {128, 0, 1, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 1, 0, 0} },
|
||||
{ {128, 0, 129, 1}, {1, 1, 0, 0}, { 0, 0, 1, 1}, {1, 1, 0, 0} },
|
||||
{ {128, 1, 0, 1}, {0, 1, 0, 1}, {129, 0, 1, 0}, {1, 0, 1, 0} },
|
||||
{ {128, 1, 1, 0}, {1, 0, 0, 1}, { 0, 1, 1, 0}, {1, 0, 0, 129} },
|
||||
{ {128, 1, 0, 1}, {1, 0, 1, 0}, { 1, 0, 1, 0}, {0, 1, 0, 129} },
|
||||
{ {128, 1, 129, 1}, {0, 0, 1, 1}, { 1, 1, 0, 0}, {1, 1, 1, 0} },
|
||||
{ {128, 0, 0, 1}, {0, 0, 1, 1}, {129, 1, 0, 0}, {1, 0, 0, 0} },
|
||||
{ {128, 0, 129, 1}, {0, 0, 1, 0}, { 0, 1, 0, 0}, {1, 1, 0, 0} },
|
||||
{ {128, 0, 129, 1}, {1, 0, 1, 1}, { 1, 1, 0, 1}, {1, 1, 0, 0} },
|
||||
{ {128, 1, 129, 0}, {1, 0, 0, 1}, { 1, 0, 0, 1}, {0, 1, 1, 0} },
|
||||
{ {128, 0, 1, 1}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {0, 0, 1, 129} },
|
||||
{ {128, 1, 1, 0}, {0, 1, 1, 0}, { 1, 0, 0, 1}, {1, 0, 0, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 1, 129, 0}, { 0, 1, 1, 0}, {0, 0, 0, 0} },
|
||||
{ {128, 1, 0, 0}, {1, 1, 129, 0}, { 0, 1, 0, 0}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 129, 0}, {0, 1, 1, 1}, { 0, 0, 1, 0}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 129, 0}, { 0, 1, 1, 1}, {0, 0, 1, 0} },
|
||||
{ {128, 0, 0, 0}, {0, 1, 0, 0}, {129, 1, 1, 0}, {0, 1, 0, 0} },
|
||||
{ {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 0, 0, 1}, {0, 0, 1, 129} },
|
||||
{ {128, 0, 1, 1}, {0, 1, 1, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} },
|
||||
{ {128, 1, 129, 0}, {0, 0, 1, 1}, { 1, 0, 0, 1}, {1, 1, 0, 0} },
|
||||
{ {128, 0, 129, 1}, {1, 0, 0, 1}, { 1, 1, 0, 0}, {0, 1, 1, 0} },
|
||||
{ {128, 1, 1, 0}, {1, 1, 0, 0}, { 1, 1, 0, 0}, {1, 0, 0, 129} },
|
||||
{ {128, 1, 1, 0}, {0, 0, 1, 1}, { 0, 0, 1, 1}, {1, 0, 0, 129} },
|
||||
{ {128, 1, 1, 1}, {1, 1, 1, 0}, { 1, 0, 0, 0}, {0, 0, 0, 129} },
|
||||
{ {128, 0, 0, 1}, {1, 0, 0, 0}, { 1, 1, 1, 0}, {0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 1, 1}, { 0, 0, 1, 1}, {0, 0, 1, 129} },
|
||||
{ {128, 0, 129, 1}, {0, 0, 1, 1}, { 1, 1, 1, 1}, {0, 0, 0, 0} },
|
||||
{ {128, 0, 129, 0}, {0, 0, 1, 0}, { 1, 1, 1, 0}, {1, 1, 1, 0} },
|
||||
{ {128, 1, 0, 0}, {0, 1, 0, 0}, { 0, 1, 1, 1}, {0, 1, 1, 129} }
|
||||
},
|
||||
{ // 3-subset
|
||||
{ {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 2, 2, 1}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 0, 129}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 2, 1} },
|
||||
{ {128, 0, 0, 0}, {2, 0, 0, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} },
|
||||
{ {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 1}, { 0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 2, 2}, { 1, 1, 2, 130} },
|
||||
{ {128, 0, 1, 129}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 2, 130} },
|
||||
{ {128, 0, 2, 130}, {0, 0, 2, 2}, { 1, 1, 1, 1}, { 1, 1, 1, 129} },
|
||||
{ {128, 0, 1, 1}, {0, 0, 1, 1}, {130, 2, 1, 1}, { 2, 2, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, {129, 1, 1, 1}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 1, 1}, {129, 1, 1, 1}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 1, 2}, {0, 0, 129, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 130} },
|
||||
{ {128, 1, 1, 2}, {0, 1, 129, 2}, { 0, 1, 1, 2}, { 0, 1, 1, 130} },
|
||||
{ {128, 1, 2, 2}, {0, 129, 2, 2}, { 0, 1, 2, 2}, { 0, 1, 2, 130} },
|
||||
{ {128, 0, 1, 129}, {0, 1, 1, 2}, { 1, 1, 2, 2}, { 1, 2, 2, 130} },
|
||||
{ {128, 0, 1, 129}, {2, 0, 0, 1}, {130, 2, 0, 0}, { 2, 2, 2, 0} },
|
||||
{ {128, 0, 0, 129}, {0, 0, 1, 1}, { 0, 1, 1, 2}, { 1, 1, 2, 130} },
|
||||
{ {128, 1, 1, 129}, {0, 0, 1, 1}, {130, 0, 0, 1}, { 2, 2, 0, 0} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 1, 1, 2, 130} },
|
||||
{ {128, 0, 2, 130}, {0, 0, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 1, 129} },
|
||||
{ {128, 1, 1, 129}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 2, 2, 130} },
|
||||
{ {128, 0, 0, 129}, {0, 0, 0, 1}, {130, 2, 2, 1}, { 2, 2, 2, 1} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 129, 1}, { 0, 1, 2, 2}, { 0, 1, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 0, 0}, {130, 2, 129, 0}, { 2, 2, 1, 0} },
|
||||
{ {128, 1, 2, 130}, {0, 129, 2, 2}, { 0, 0, 1, 1}, { 0, 0, 0, 0} },
|
||||
{ {128, 0, 1, 2}, {0, 0, 1, 2}, {129, 1, 2, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 1, 1, 0}, {1, 2, 130, 1}, {129, 2, 2, 1}, { 0, 1, 1, 0} },
|
||||
{ {128, 0, 0, 0}, {0, 1, 129, 0}, { 1, 2, 130, 1}, { 1, 2, 2, 1} },
|
||||
{ {128, 0, 2, 2}, {1, 1, 0, 2}, {129, 1, 0, 2}, { 0, 0, 2, 130} },
|
||||
{ {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 0, 0, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 1, 1}, {0, 1, 2, 2}, { 0, 1, 130, 2}, { 0, 0, 1, 129} },
|
||||
{ {128, 0, 0, 0}, {2, 0, 0, 0}, {130, 2, 1, 1}, { 2, 2, 2, 129} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 2}, {129, 1, 2, 2}, { 1, 2, 2, 130} },
|
||||
{ {128, 2, 2, 130}, {0, 0, 2, 2}, { 0, 0, 1, 2}, { 0, 0, 1, 129} },
|
||||
{ {128, 0, 1, 129}, {0, 0, 1, 2}, { 0, 0, 2, 2}, { 0, 2, 2, 130} },
|
||||
{ {128, 1, 2, 0}, {0, 129, 2, 0}, { 0, 1, 130, 0}, { 0, 1, 2, 0} },
|
||||
{ {128, 0, 0, 0}, {1, 1, 129, 1}, { 2, 2, 130, 2}, { 0, 0, 0, 0} },
|
||||
{ {128, 1, 2, 0}, {1, 2, 0, 1}, {130, 0, 129, 2}, { 0, 1, 2, 0} },
|
||||
{ {128, 1, 2, 0}, {2, 0, 1, 2}, {129, 130, 0, 1}, { 0, 1, 2, 0} },
|
||||
{ {128, 0, 1, 1}, {2, 2, 0, 0}, { 1, 1, 130, 2}, { 0, 0, 1, 129} },
|
||||
{ {128, 0, 1, 1}, {1, 1, 130, 2}, { 2, 2, 0, 0}, { 0, 0, 1, 129} },
|
||||
{ {128, 1, 0, 129}, {0, 1, 0, 1}, { 2, 2, 2, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, {130, 1, 2, 1}, { 2, 1, 2, 129} },
|
||||
{ {128, 0, 2, 2}, {1, 129, 2, 2}, { 0, 0, 2, 2}, { 1, 1, 2, 130} },
|
||||
{ {128, 0, 2, 130}, {0, 0, 1, 1}, { 0, 0, 2, 2}, { 0, 0, 1, 129} },
|
||||
{ {128, 2, 2, 0}, {1, 2, 130, 1}, { 0, 2, 2, 0}, { 1, 2, 2, 129} },
|
||||
{ {128, 1, 0, 1}, {2, 2, 130, 2}, { 2, 2, 2, 2}, { 0, 1, 0, 129} },
|
||||
{ {128, 0, 0, 0}, {2, 1, 2, 1}, {130, 1, 2, 1}, { 2, 1, 2, 129} },
|
||||
{ {128, 1, 0, 129}, {0, 1, 0, 1}, { 0, 1, 0, 1}, { 2, 2, 2, 130} },
|
||||
{ {128, 2, 2, 130}, {0, 1, 1, 1}, { 0, 2, 2, 2}, { 0, 1, 1, 129} },
|
||||
{ {128, 0, 0, 2}, {1, 129, 1, 2}, { 0, 0, 0, 2}, { 1, 1, 1, 130} },
|
||||
{ {128, 0, 0, 0}, {2, 129, 1, 2}, { 2, 1, 1, 2}, { 2, 1, 1, 130} },
|
||||
{ {128, 2, 2, 2}, {0, 129, 1, 1}, { 0, 1, 1, 1}, { 0, 2, 2, 130} },
|
||||
{ {128, 0, 0, 2}, {1, 1, 1, 2}, {129, 1, 1, 2}, { 0, 0, 0, 130} },
|
||||
{ {128, 1, 1, 0}, {0, 129, 1, 0}, { 0, 1, 1, 0}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 2, 1, 129, 2}, { 2, 1, 1, 130} },
|
||||
{ {128, 1, 1, 0}, {0, 129, 1, 0}, { 2, 2, 2, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 0, 2, 2}, {0, 0, 1, 1}, { 0, 0, 129, 1}, { 0, 0, 2, 130} },
|
||||
{ {128, 0, 2, 2}, {1, 1, 2, 2}, {129, 1, 2, 2}, { 0, 0, 2, 130} },
|
||||
{ {128, 0, 0, 0}, {0, 0, 0, 0}, { 0, 0, 0, 0}, { 2, 129, 1, 130} },
|
||||
{ {128, 0, 0, 130}, {0, 0, 0, 1}, { 0, 0, 0, 2}, { 0, 0, 0, 129} },
|
||||
{ {128, 2, 2, 2}, {1, 2, 2, 2}, { 0, 2, 2, 2}, {129, 2, 2, 130} },
|
||||
{ {128, 1, 0, 129}, {2, 2, 2, 2}, { 2, 2, 2, 2}, { 2, 2, 2, 130} },
|
||||
{ {128, 1, 1, 129}, {2, 0, 1, 1}, {130, 2, 0, 1}, { 2, 2, 2, 0} }
|
||||
}
|
||||
};
|
||||
|
||||
QImage image = imageAlloc(width, height, QImage::Format_ARGB32);
|
||||
if (image.isNull()) {
|
||||
return image;
|
||||
}
|
||||
|
||||
quint8 block[16];
|
||||
quint8 texel[4][4][4];
|
||||
for (quint32 by = 0; by < height; by += 4) {
|
||||
for (quint32 bx = 0; bx < width; bx += 4) {
|
||||
quint8 texel[16 * 4];
|
||||
for (quint32 i = 0; i < height; i += 4) {
|
||||
for (quint32 j = 0; j < width; j += 4) {
|
||||
if (s.readRawData(reinterpret_cast<char *>(block), sizeof(block)) != int(sizeof(block)))
|
||||
return QImage();
|
||||
|
||||
memset(texel, 0, sizeof(texel));
|
||||
bcdec_bc7(block, texel, 4 * 4);
|
||||
|
||||
BC7BitStream bstream;
|
||||
bstream.low = bc7ReadU64(block);
|
||||
bstream.high = bc7ReadU64(block + 8);
|
||||
|
||||
// The mode is the number of leading zero bits.
|
||||
int mode = 0;
|
||||
while (mode < 8 && bc7ReadBits(&bstream, 1) == 0)
|
||||
++mode;
|
||||
|
||||
// Reserved mode: the decompressed block is transparent black.
|
||||
if (mode < 8) {
|
||||
int partition = 0;
|
||||
int numPartitions = 1;
|
||||
int rotation = 0;
|
||||
int indexSelectionBit = 0;
|
||||
|
||||
if (mode == 0 || mode == 1 || mode == 2 || mode == 3 || mode == 7) {
|
||||
numPartitions = (mode == 0 || mode == 2) ? 3 : 2;
|
||||
partition = bc7ReadBits(&bstream, (mode == 0) ? 4 : 6);
|
||||
}
|
||||
|
||||
const int numEndpoints = numPartitions * 2;
|
||||
|
||||
if (mode == 4 || mode == 5) {
|
||||
rotation = bc7ReadBits(&bstream, 2);
|
||||
|
||||
if (mode == 4)
|
||||
indexSelectionBit = bc7ReadBits(&bstream, 1);
|
||||
}
|
||||
|
||||
int endpoints[6][4];
|
||||
memset(endpoints, 0, sizeof(endpoints));
|
||||
|
||||
for (int c = 0; c < 3; ++c)
|
||||
for (int e = 0; e < numEndpoints; ++e)
|
||||
endpoints[e][c] = bc7ReadBits(&bstream, actualBitsCount[0][mode]);
|
||||
|
||||
if (actualBitsCount[1][mode] > 0)
|
||||
for (int e = 0; e < numEndpoints; ++e)
|
||||
endpoints[e][3] = bc7ReadBits(&bstream, actualBitsCount[1][mode]);
|
||||
|
||||
if (mode == 0 || mode == 1 || mode == 3 || mode == 6 || mode == 7) {
|
||||
for (int e = 0; e < numEndpoints; ++e)
|
||||
for (int c = 0; c < 4; ++c)
|
||||
endpoints[e][c] <<= 1;
|
||||
|
||||
if (mode == 1) {
|
||||
// The two subsets share one P-bit each.
|
||||
const int p0 = bc7ReadBits(&bstream, 1);
|
||||
const int p1 = bc7ReadBits(&bstream, 1);
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
endpoints[0][c] |= p0;
|
||||
endpoints[1][c] |= p0;
|
||||
endpoints[2][c] |= p1;
|
||||
endpoints[3][c] |= p1;
|
||||
}
|
||||
} else if (modesWithPBits & (1 << mode)) {
|
||||
// One P-bit per endpoint.
|
||||
for (int e = 0; e < numEndpoints; ++e) {
|
||||
const int p = bc7ReadBits(&bstream, 1);
|
||||
for (int c = 0; c < 4; ++c)
|
||||
endpoints[e][c] |= p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int e = 0; e < numEndpoints; ++e) {
|
||||
int bits = actualBitsCount[0][mode] + ((modesWithPBits >> mode) & 1);
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
endpoints[e][c] <<= (8 - bits);
|
||||
endpoints[e][c] |= (endpoints[e][c] >> bits);
|
||||
}
|
||||
|
||||
bits = actualBitsCount[1][mode] + ((modesWithPBits >> mode) & 1);
|
||||
endpoints[e][3] <<= (8 - bits);
|
||||
endpoints[e][3] |= (endpoints[e][3] >> bits);
|
||||
}
|
||||
|
||||
// If the mode does not store alpha, then alpha is opaque.
|
||||
if (actualBitsCount[1][mode] == 0)
|
||||
for (int e = 0; e < numEndpoints; ++e)
|
||||
endpoints[e][3] = 0xff;
|
||||
|
||||
const int indexBits = (mode == 0 || mode == 1) ? 3 : ((mode == 6) ? 4 : 2);
|
||||
const int indexBits2 = (mode == 4) ? 3 : ((mode == 5) ? 2 : 0);
|
||||
const int *weights = (indexBits == 2) ? weight2 : ((indexBits == 3) ? weight3 : weight4);
|
||||
const int *weights2 = (indexBits2 == 2) ? weight2 : weight3;
|
||||
|
||||
// The color indices are stored before the alpha indices.
|
||||
int indices[4][4];
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
const int partitionSet = (numPartitions == 1) ? ((i | j) ? 0 : 128)
|
||||
: partitionSets[numPartitions - 2][partition][i][j];
|
||||
int bits = indexBits;
|
||||
if (partitionSet & 0x80) // fix-up index
|
||||
bits--;
|
||||
indices[i][j] = bc7ReadBits(&bstream, bits);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
for (int j = 0; j < 4; ++j) {
|
||||
const int partitionSet = ((numPartitions == 1) ? ((i | j) ? 0 : 128)
|
||||
: partitionSets[numPartitions - 2][partition][i][j]) & 0x03;
|
||||
|
||||
const int index = indices[i][j];
|
||||
int r, g, b, a;
|
||||
if (indexBits2 == 0) {
|
||||
r = bc7Interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index);
|
||||
g = bc7Interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index);
|
||||
b = bc7Interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index);
|
||||
a = bc7Interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index);
|
||||
} else {
|
||||
const int index2 = bc7ReadBits(&bstream, (i | j) ? indexBits2 : (indexBits2 - 1));
|
||||
if (indexSelectionBit == 0) {
|
||||
r = bc7Interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights, index);
|
||||
g = bc7Interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights, index);
|
||||
b = bc7Interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights, index);
|
||||
a = bc7Interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights2, index2);
|
||||
} else {
|
||||
r = bc7Interpolate(endpoints[partitionSet * 2][0], endpoints[partitionSet * 2 + 1][0], weights2, index2);
|
||||
g = bc7Interpolate(endpoints[partitionSet * 2][1], endpoints[partitionSet * 2 + 1][1], weights2, index2);
|
||||
b = bc7Interpolate(endpoints[partitionSet * 2][2], endpoints[partitionSet * 2 + 1][2], weights2, index2);
|
||||
a = bc7Interpolate(endpoints[partitionSet * 2][3], endpoints[partitionSet * 2 + 1][3], weights, index);
|
||||
}
|
||||
}
|
||||
|
||||
switch (rotation) {
|
||||
case 1: // swap A and R
|
||||
std::swap(a, r);
|
||||
break;
|
||||
case 2: // swap A and G
|
||||
std::swap(a, g);
|
||||
break;
|
||||
case 3: // swap A and B
|
||||
std::swap(a, b);
|
||||
break;
|
||||
}
|
||||
|
||||
texel[i][j][0] = quint8(r);
|
||||
texel[i][j][1] = quint8(g);
|
||||
texel[i][j][2] = quint8(b);
|
||||
texel[i][j][3] = quint8(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const quint32 kMax = qMin<quint32>(4, height - by);
|
||||
const quint32 lMax = qMin<quint32>(4, width - bx);
|
||||
for (quint32 i = 0; i < kMax; i++) {
|
||||
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(by + i));
|
||||
for (quint32 j = 0; j < lMax; j++) {
|
||||
line[bx + j] = qRgba(texel[i][j][0], texel[i][j][1], texel[i][j][2], texel[i][j][3]);
|
||||
const quint32 kMax = qMin<quint32>(4, height - i);
|
||||
const quint32 lMax = qMin<quint32>(4, width - j);
|
||||
for (quint32 k = 0; k < kMax; k++) {
|
||||
QRgb *line = reinterpret_cast<QRgb *>(image.scanLine(i + k));
|
||||
for (quint32 l = 0; l < lMax; l++) {
|
||||
const quint8 *pixel = texel + (k * 4 + l) * 4;
|
||||
line[j + l] = qRgba(pixel[0], pixel[1], pixel[2], pixel[3]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user