TexConv/CMP_CompressonatorLib/DXTC/Codec_DXTC_RGBA.cpp

633 lines
24 KiB
C++
Raw Normal View History

2020-07-31 11:31:32 +08:00
//===============================================================================
// Copyright (c) 2007-2016 Advanced Micro Devices, Inc. All rights reserved.
// Copyright (c) 2004-2006 ATI Technologies Inc.
//===============================================================================
//
// 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 :
//
2020-07-31 11:31:32 +08:00
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
2020-07-31 11:31:32 +08:00
// 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.
//
//
// File Name: Codec_DXTC.cpp
// Description: implementation of the CCodec_DXTC class
//
//////////////////////////////////////////////////////////////////////////////
#include "common.h"
#include "codec_dxtc.h"
#include "compressonatorxcodec.h"
2020-07-31 11:31:32 +08:00
#include "dxtc_v11_compress.h"
#include <algorithm>
#ifdef USE_CMP_CORE_API
#include "bcn_common_kernel.h"
#include "bcn_common_api.h"
#include "bc1_cmp.h"
#endif
using namespace CMP;
2020-07-31 11:31:32 +08:00
// #define PRINT_DECODE_INFO
using namespace std;
2020-07-31 11:31:32 +08:00
CodecError CCodec_DXTC::CompressRGBABlock(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4], CODECFLOAT* pfChannelWeights) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
2020-07-31 11:31:32 +08:00
return CompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], pfChannelWeights, false);
}
void CCodec_DXTC::DecompressRGBABlock(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
2020-07-31 11:31:32 +08:00
DecompressAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
DecompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], false);
2020-07-31 11:31:32 +08:00
for(CMP_DWORD i = 0; i < 16; i++)
((DWORD*)rgbaBlock)[i] = (alphaBlock[i] << RGBA8888_OFFSET_A) | (((DWORD*)rgbaBlock)[i] & ~(BYTE_MASK << RGBA8888_OFFSET_A));
}
CodecError CCodec_DXTC::CompressRGBABlock_ExplicitAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4], CODECFLOAT* pfChannelWeights) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressExplicitAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
2020-07-31 11:31:32 +08:00
return CompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], pfChannelWeights, false);
}
void CCodec_DXTC::DecompressRGBABlock_ExplicitAlpha(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
2020-07-31 11:31:32 +08:00
DecompressExplicitAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
DecompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], false);
2020-07-31 11:31:32 +08:00
for(CMP_DWORD i = 0; i < 16; i++)
((DWORD*)rgbaBlock)[i] = (alphaBlock[i] << RGBA8888_OFFSET_A) | (((DWORD*)rgbaBlock)[i] & ~(BYTE_MASK << RGBA8888_OFFSET_A));
}
#define ConstructColour(r, g, b) (((r) << 11) | ((g) << 5) | (b))
/*
2020-07-31 11:31:32 +08:00
Channel Bits
*/
#define RG 5
#define GG 6
#define BG 5
CodecError CCodec_DXTC::CompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2], CODECFLOAT* pfChannelWeights, bool bDXT1, bool bDXT1UseAlpha, CMP_BYTE nDXT1AlphaThreshold) {
#ifdef USE_CMP_CORE_API
CGU_Vec2ui cmpBlock;
CGU_Vec4f src_imageNorm[BLOCK_SIZE_4X4];
CGU_UINT32 jj=0;
for (CGU_UINT32 ii = 0; ii < 16; ii++)
{
src_imageNorm[ii].b = rgbBlock[jj++] / 255.0f;
src_imageNorm[ii].g = rgbBlock[jj++] / 255.0f;
src_imageNorm[ii].r = rgbBlock[jj++] / 255.0f;
src_imageNorm[ii].w = rgbBlock[jj++] / 255.0f;
}
cmpBlock = CompressBlockBC1_NORMALIZED(src_imageNorm,m_BC15Options);
compressedBlock[0] = cmpBlock.x;
compressedBlock[1] = cmpBlock.y;
#else // Use Legacy API
2020-07-31 11:31:32 +08:00
/*
ARGB Channel indexes
*/
int RC = 2, GC = 1, BC = 0;
if(bDXT1 && m_nCompressionSpeed == CMP_Speed_Normal) {
2020-07-31 11:31:32 +08:00
CMP_BYTE nEndpoints[2][3][2];
CMP_BYTE nIndices[2][BLOCK_SIZE_4X4];
double fError3 = CompRGBBlock((DWORD*)rgbBlock,compressedBlock, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints[0], nIndices[0], 3, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, nDXT1AlphaThreshold);
//printf(": %2d %2d %2d %2d %2d\n",nIndices[0][0],nIndices[0][1],nIndices[0][2],nIndices[0][3],nIndices[0][4]);
// use case of small min max ranges
if (compressedBlock[0] > 0) {
return CE_OK;
}
CMP_DWORD compressedBlock1[2];
double fError4 = (fError3 == 0.0) ? FLT_MAX : CompRGBBlock((DWORD*)rgbBlock, compressedBlock1, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints[1], nIndices[1], 4, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, nDXT1AlphaThreshold);
//if (fError3 > 0.0f)
// printf(": %2d %2d %2d %2d %2d\n",nIndices[1][0],nIndices[1][1],nIndices[1][2],nIndices[1][3],nIndices[1][4]);
2020-07-31 11:31:32 +08:00
unsigned int nMethod = (fError3 <= fError4) ? 0 : 1;
2020-07-31 11:31:32 +08:00
unsigned int c0 = ConstructColour((nEndpoints[nMethod][RC][0] >> (8-RG)), (nEndpoints[nMethod][GC][0] >> (8-GG)), (nEndpoints[nMethod][BC][0] >> (8-BG)));
unsigned int c1 = ConstructColour((nEndpoints[nMethod][RC][1] >> (8-RG)), (nEndpoints[nMethod][GC][1] >> (8-GG)), (nEndpoints[nMethod][BC][1] >> (8-BG)));
if(nMethod == 1 && c0 <= c1 || nMethod == 0 && c0 > c1)
compressedBlock[0] = c1 | (c0<<16);
else
compressedBlock[0] = c0 | (c1<<16);
compressedBlock[1] = 0;
for(int i=0; i<16; i++)
compressedBlock[1] |= (nIndices[nMethod][i] << (2*i));
}
else {
2020-07-31 11:31:32 +08:00
CMP_BYTE nEndpoints[3][2];
CMP_BYTE nIndices[BLOCK_SIZE_4X4];
CompRGBBlock((DWORD*)rgbBlock,compressedBlock, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints, nIndices, 4, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, nDXT1AlphaThreshold);
2020-07-31 11:31:32 +08:00
unsigned int c0 = ConstructColour((nEndpoints[RC][0] >> (8-RG)), (nEndpoints[GC][0] >> (8-GG)), (nEndpoints[BC][0] >> (8-BG)));
unsigned int c1 = ConstructColour((nEndpoints[RC][1] >> (8-RG)), (nEndpoints[GC][1] >> (8-GG)), (nEndpoints[BC][1] >> (8-BG)));
if(c0 <= c1)
compressedBlock[0] = c1 | (c0<<16);
else
compressedBlock[0] = c0 | (c1<<16);
compressedBlock[1] = 0;
for(int i=0; i<16; i++)
compressedBlock[1] |= (nIndices[i] << (2*i));
}
#endif
2020-07-31 11:31:32 +08:00
return CE_OK;
}
CodecError CCodec_DXTC::CompressRGBBlock_Fast(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2]) {
2020-07-31 11:31:32 +08:00
this->CompressRGBBlock(rgbBlock, compressedBlock);
return CE_OK;
}
CodecError CCodec_DXTC::CompressRGBBlock_SuperFast(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2]) {
CompressRGBBlock(rgbBlock, compressedBlock);
2020-07-31 11:31:32 +08:00
return CE_OK;
}
CodecError CCodec_DXTC::CompressRGBABlock_Fast(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressAlphaBlock_Fast(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
return CompressRGBBlock_Fast(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB]);
}
CodecError CCodec_DXTC::CompressRGBABlock_SuperFast(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressAlphaBlock_Fast(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
return CompressRGBBlock_SuperFast(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB]);
}
CodecError CCodec_DXTC::CompressRGBABlock_ExplicitAlpha_Fast(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressExplicitAlphaBlock_Fast(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
return CompressRGBBlock_Fast(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB]);
}
CodecError CCodec_DXTC::CompressRGBABlock_ExplicitAlpha_SuperFast(CMP_BYTE rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CMP_BYTE alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = static_cast<CMP_BYTE>(((DWORD*)rgbaBlock)[i] >> RGBA8888_OFFSET_A);
CodecError err = CompressExplicitAlphaBlock_Fast(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
return CompressRGBBlock_SuperFast(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB]);
}
CodecError CCodec_DXTC::CompressRGBABlock(CODECFLOAT rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4], CODECFLOAT* pfChannelWeights) {
2020-07-31 11:31:32 +08:00
CODECFLOAT alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = rgbaBlock[(i * 4) + RGBA32F_OFFSET_A];
CodecError err = CompressAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
2020-07-31 11:31:32 +08:00
return CompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], pfChannelWeights, false);
}
CodecError CCodec_DXTC::CompressRGBABlock_ExplicitAlpha(CODECFLOAT rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4], CODECFLOAT* pfChannelWeights) {
2020-07-31 11:31:32 +08:00
CODECFLOAT alphaBlock[BLOCK_SIZE_4X4];
for(CMP_DWORD i = 0; i < 16; i++)
alphaBlock[i] = rgbaBlock[(i * 4) + RGBA32F_OFFSET_A];
CodecError err = CompressExplicitAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
if(err != CE_OK)
return err;
return CompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], pfChannelWeights, false);
}
// ToDo Remove this interface
CodecError CCodec_DXTC::CompressRGBBlock(CODECFLOAT rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2], CODECFLOAT* pfChannelWeights, bool bDXT1, bool bDXT1UseAlpha, CODECFLOAT fDXT1AlphaThreshold) {
// Use Legacy API
#ifndef USE_CMP_CORE_API
int RC = 2, GC = 1, BC = 0;
#endif
2020-07-31 11:31:32 +08:00
if(bDXT1) {
2020-07-31 11:31:32 +08:00
CMP_BYTE nEndpoints[2][3][2];
CMP_BYTE nIndices[2][BLOCK_SIZE_4X4];
double fError3 = CompRGBBlock(rgbBlock,compressedBlock, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints[0], nIndices[0], 3, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, fDXT1AlphaThreshold);
CMP_DWORD compressedBlock1[2];
double fError4 = (fError3 == 0.0) ? FLT_MAX : CompRGBBlock(rgbBlock,compressedBlock1, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints[1], nIndices[1], 4, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, fDXT1AlphaThreshold);
2020-07-31 11:31:32 +08:00
unsigned int nMethod = (fError3 <= fError4) ? 0 : 1;
unsigned int c0 = ConstructColour((nEndpoints[nMethod][RC][0] >> (8-RG)), (nEndpoints[nMethod][GC][0] >> (8-GG)), (nEndpoints[nMethod][BC][0] >> (8-BG)));
unsigned int c1 = ConstructColour((nEndpoints[nMethod][RC][1] >> (8-RG)), (nEndpoints[nMethod][GC][1] >> (8-GG)), (nEndpoints[nMethod][BC][1] >> (8-BG)));
if(nMethod == 1 && c0 <= c1 || nMethod == 0 && c0 > c1)
compressedBlock[0] = c1 | (c0<<16);
else
compressedBlock[0] = c0 | (c1<<16);
compressedBlock[1] = 0;
for(int i=0; i<16; i++)
compressedBlock[1] |= (nIndices[nMethod][i] << (2*i));
} else {
2020-07-31 11:31:32 +08:00
CMP_BYTE nEndpoints[3][2];
CMP_BYTE nIndices[BLOCK_SIZE_4X4];
CompRGBBlock(rgbBlock,compressedBlock, BLOCK_SIZE_4X4, RG, GG, BG, nEndpoints, nIndices, 4, m_bUseSSE2, m_b3DRefinement, m_nRefinementSteps, pfChannelWeights, bDXT1UseAlpha, fDXT1AlphaThreshold);
2020-07-31 11:31:32 +08:00
unsigned int c0 = ConstructColour((nEndpoints[RC][0] >> (8-RG)), (nEndpoints[GC][0] >> (8-GG)), (nEndpoints[BC][0] >> (8-BG)));
unsigned int c1 = ConstructColour((nEndpoints[RC][1] >> (8-RG)), (nEndpoints[GC][1] >> (8-GG)), (nEndpoints[BC][1] >> (8-BG)));
if(c0 <= c1)
compressedBlock[0] = c1 | (c0<<16);
else
compressedBlock[0] = c0 | (c1<<16);
compressedBlock[1] = 0;
for(int i=0; i<16; i++)
compressedBlock[1] |= (nIndices[i] << (2*i));
}
2020-07-31 11:31:32 +08:00
return CE_OK;
}
void CCodec_DXTC::DecompressRGBABlock(CODECFLOAT rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CODECFLOAT alphaBlock[BLOCK_SIZE_4X4];
2020-07-31 11:31:32 +08:00
DecompressAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
DecompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], false);
2020-07-31 11:31:32 +08:00
for(CMP_DWORD i = 0; i < 16; i++)
rgbaBlock[(i * 4) + RGBA32F_OFFSET_A] = alphaBlock[i];
}
void CCodec_DXTC::DecompressRGBABlock_ExplicitAlpha(CODECFLOAT rgbaBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[4]) {
2020-07-31 11:31:32 +08:00
CODECFLOAT alphaBlock[BLOCK_SIZE_4X4];
2020-07-31 11:31:32 +08:00
DecompressExplicitAlphaBlock(alphaBlock, &compressedBlock[DXTC_OFFSET_ALPHA]);
DecompressRGBBlock(rgbaBlock, &compressedBlock[DXTC_OFFSET_RGB], false);
2020-07-31 11:31:32 +08:00
for(CMP_DWORD i = 0; i < 16; i++)
rgbaBlock[(i * 4) + RGBA32F_OFFSET_A] = alphaBlock[i];
}
// This function decompresses a DXT colour block
// The block is decompressed to 8 bits per channel
// The return data is rgbBlock[BLOCK_SIZE_4X4X4] = [RGBA,RGBA,...]
void CCodec_DXTC::DecompressRGBBlock(CMP_BYTE rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2], bool bDXT1) {
2020-07-31 11:31:32 +08:00
CMP_DWORD n0 = compressedBlock[0] & 0xffff;
CMP_DWORD n1 = compressedBlock[0]>>16;
CMP_DWORD r0;
CMP_DWORD g0;
CMP_DWORD b0;
CMP_DWORD r1;
CMP_DWORD g1;
CMP_DWORD b1;
// Decode RGB bits
r0 = ((n0 & 0xf800) >> 8);
g0 = ((n0 & 0x07e0) >> 3);
b0 = ((n0 & 0x001f) << 3);
r1 = ((n1 & 0xf800) >> 8);
g1 = ((n1 & 0x07e0) >> 3);
b1 = ((n1 & 0x001f) << 3);
// Apply the lower bit replication to give full dynamic range
r0 += (r0>>5);
r1 += (r1>>5);
g0 += (g0>>6);
g1 += (g1>>6);
b0 += (b0>>5);
b1 += (b1>>5);
2020-07-31 11:31:32 +08:00
// Save the pixel in ABGR
CMP_DWORD c0 = 0xff000000 | (b0<<16) | (g0<<8) | r0;
CMP_DWORD c1 = 0xff000000 | (b1<<16) | (g1<<8) | r1;
if(!bDXT1 || n0 > n1) {
2020-07-31 11:31:32 +08:00
CMP_DWORD c2 = 0xff000000 | (((2*b0+b1)/3)<<16) | (((2*g0+g1)/3)<<8) | (((2*r0+r1)/3));
CMP_DWORD c3 = 0xff000000 | (((2*b1+b0)/3)<<16) | (((2*g1+g0)/3)<<8) | (((2*r1+r0)/3));
for(int i=0; i<16; i++) {
2020-07-31 11:31:32 +08:00
int index = (compressedBlock[1] >> (2 * i)) & 3;
switch(index) {
2020-07-31 11:31:32 +08:00
case 0:
((DWORD*)rgbBlock)[i] = c0;
break;
case 1:
((DWORD*)rgbBlock)[i] = c1;
break;
case 2:
((DWORD*)rgbBlock)[i] = c2;
break;
case 3:
((DWORD*)rgbBlock)[i] = c3;
break;
}
}
} else {
2020-07-31 11:31:32 +08:00
// Transparent decode
CMP_DWORD c2 = 0xff000000 | (((b0+b1)/2)<<16) | (((g0+g1)/2)<<8) | (((r0+r1)/2));
for(int i=0; i<16; i++) {
2020-07-31 11:31:32 +08:00
int index = (compressedBlock[1] >> (2 * i)) & 3;
switch(index) {
case 0:
((DWORD*)rgbBlock)[i] = c0;
break;
case 1:
((DWORD*)rgbBlock)[i] = c1;
break;
case 2:
((DWORD*)rgbBlock)[i] = c2;
break;
case 3:
((DWORD*)rgbBlock)[i] = 0x00000000;
break;
2020-07-31 11:31:32 +08:00
}
}
}
}
//
// This function decompresses a DXT colour block
// The block is decompressed to 8 bits per channel
//
void CCodec_DXTC::DecompressRGBBlock(CODECFLOAT rgbBlock[BLOCK_SIZE_4X4X4], CMP_DWORD compressedBlock[2], bool bDXT1) {
2020-07-31 11:31:32 +08:00
CMP_DWORD n0 = compressedBlock[0] & 0xffff;
CMP_DWORD n1 = compressedBlock[0]>>16;
CMP_DWORD r0;
CMP_DWORD g0;
CMP_DWORD b0;
CMP_DWORD r1;
CMP_DWORD g1;
CMP_DWORD b1;
r0 = ((n0 & 0xf800) >> 8);
g0 = ((n0 & 0x07e0) >> 3);
b0 = ((n0 & 0x001f) << 3);
r1 = ((n1 & 0xf800) >> 8);
g1 = ((n1 & 0x07e0) >> 3);
b1 = ((n1 & 0x001f) << 3);
// Apply the lower bit replication to give full dynamic range
r0 += (r0>>5);
r1 += (r1>>5);
g0 += (g0>>6);
g1 += (g1>>6);
b0 += (b0>>5);
b1 += (b1>>5);
2020-07-31 11:31:32 +08:00
#ifdef PRINT_DECODE_INFO
FILE *gt_File_decode = fopen("decode_patterns.txt", "a");
#endif
CODECFLOAT c0[4], c1[4], c2[4], c3[4];
c0[RGBA32F_OFFSET_A] = 1.0;
c0[RGBA32F_OFFSET_R] = CONVERT_BYTE_TO_FLOAT(r0);
c0[RGBA32F_OFFSET_G] = CONVERT_BYTE_TO_FLOAT(g0);
c0[RGBA32F_OFFSET_B] = CONVERT_BYTE_TO_FLOAT(b0);
c1[RGBA32F_OFFSET_A] = 1.0;
c1[RGBA32F_OFFSET_R] = CONVERT_BYTE_TO_FLOAT(r1);
c1[RGBA32F_OFFSET_G] = CONVERT_BYTE_TO_FLOAT(g1);
c1[RGBA32F_OFFSET_B] = CONVERT_BYTE_TO_FLOAT(b1);
if(!bDXT1 || n0 > n1) {
2020-07-31 11:31:32 +08:00
#ifdef PRINT_DECODE_INFO
fprintf(gt_File_decode, "BC1A : C0(%3d,%3d,%3d) C1(%3d,%3d,%3d) index = ",
r0, g0, b0, r1, g1, b1
);
2020-07-31 11:31:32 +08:00
#endif
c2[RGBA32F_OFFSET_A] = 1.0;
c2[RGBA32F_OFFSET_R] = ((2*c0[RGBA32F_OFFSET_R]+c1[RGBA32F_OFFSET_R])/3);
c2[RGBA32F_OFFSET_G] = ((2*c0[RGBA32F_OFFSET_G]+c1[RGBA32F_OFFSET_G])/3);
c2[RGBA32F_OFFSET_B] = ((2*c0[RGBA32F_OFFSET_B]+c1[RGBA32F_OFFSET_B])/3);
c3[RGBA32F_OFFSET_A] = 1.0;
c3[RGBA32F_OFFSET_R] = ((2*c1[RGBA32F_OFFSET_R]+c0[RGBA32F_OFFSET_R])/3);
c3[RGBA32F_OFFSET_G] = ((2*c1[RGBA32F_OFFSET_G]+c0[RGBA32F_OFFSET_G])/3);
c3[RGBA32F_OFFSET_B] = ((2*c1[RGBA32F_OFFSET_B]+c0[RGBA32F_OFFSET_B])/3);
for(int i=0; i<16; i++) {
2020-07-31 11:31:32 +08:00
int index = (compressedBlock[1] >> (2 * i)) & 3;
#ifdef PRINT_DECODE_INFO
fprintf(gt_File_decode, "%2d,", index);
#endif
switch(index) {
2020-07-31 11:31:32 +08:00
case 0:
memcpy(&rgbBlock[i*4], c0, 4 * sizeof(CODECFLOAT));
break;
case 1:
memcpy(&rgbBlock[i*4], c1, 4 * sizeof(CODECFLOAT));
break;
case 2:
memcpy(&rgbBlock[i*4], c2, 4 * sizeof(CODECFLOAT));
break;
case 3:
memcpy(&rgbBlock[i*4], c3, 4 * sizeof(CODECFLOAT));
break;
}
}
} else {
2020-07-31 11:31:32 +08:00
#ifdef PRINT_DECODE_INFO
fprintf(gt_File_decode, "BC1AT : C0(%3d,%3d,%3d) C1(%3d,%3d,%3d) index = ",
r0, g0, b0, r1, g1, b1
);
2020-07-31 11:31:32 +08:00
#endif
// Transparent decode
c2[RGBA32F_OFFSET_A] = 1.0;
c2[RGBA32F_OFFSET_R] = ((c0[RGBA32F_OFFSET_R]+c1[RGBA32F_OFFSET_R])/2);
c2[RGBA32F_OFFSET_G] = ((c0[RGBA32F_OFFSET_G]+c1[RGBA32F_OFFSET_G])/2);
c2[RGBA32F_OFFSET_B] = ((c0[RGBA32F_OFFSET_B]+c1[RGBA32F_OFFSET_B])/2);
c3[RGBA32F_OFFSET_A] = 0.0;
c3[RGBA32F_OFFSET_R] = 0.0;
c3[RGBA32F_OFFSET_G] = 0.0;
c3[RGBA32F_OFFSET_B] = 0.0;
for(int i=0; i<16; i++) {
2020-07-31 11:31:32 +08:00
int index = (compressedBlock[1] >> (2 * i)) & 3;
#ifdef PRINT_DECODE_INFO
fprintf(gt_File_decode, "%2d,", index);
#endif
switch(index) {
case 0:
memcpy(&rgbBlock[i*4], c0, 4 * sizeof(CODECFLOAT));
break;
case 1:
memcpy(&rgbBlock[i*4], c1, 4 * sizeof(CODECFLOAT));
break;
case 2:
memcpy(&rgbBlock[i*4], c2, 4 * sizeof(CODECFLOAT));
break;
case 3:
memcpy(&rgbBlock[i*4], c3, 4 * sizeof(CODECFLOAT));
break;
2020-07-31 11:31:32 +08:00
}
}
}
#ifdef PRINT_DECODE_INFO
fprintf(gt_File_decode, "\n");
fclose(gt_File_decode);
#endif
}
CODECFLOAT* CCodec_DXTC::CalculateColourWeightings(CMP_BYTE block[BLOCK_SIZE_4X4X4]) {
2020-07-31 11:31:32 +08:00
if(!m_bUseChannelWeighting)
return NULL;
if(m_bUseAdaptiveWeighting) {
2020-07-31 11:31:32 +08:00
float medianR = 0.0f, medianG = 0.0f, medianB = 0.0f;
for(CMP_DWORD k=0; k<BLOCK_SIZE_4X4; k++) {
2020-07-31 11:31:32 +08:00
CMP_DWORD R = (block[k] & 0xff0000) >> 16;
CMP_DWORD G = (block[k] & 0xff00) >> 8;
CMP_DWORD B = block[k] & 0xff;
medianR += R;
medianG += G;
medianB += B;
}
medianR /= BLOCK_SIZE_4X4;
medianG /= BLOCK_SIZE_4X4;
medianB /= BLOCK_SIZE_4X4;
// Now skew the colour weightings based on the gravity center of the block
float largest = max(max(medianR, medianG), medianB);
if(largest > 0) {
2020-07-31 11:31:32 +08:00
medianR /= largest;
medianG /= largest;
medianB /= largest;
} else
2020-07-31 11:31:32 +08:00
medianR = medianG = medianB = 1.0f;
// Scale weightings back up to 1.0f
CODECFLOAT fWeightScale = 1.0f / (m_fBaseChannelWeights[0] + m_fBaseChannelWeights[1] + m_fBaseChannelWeights[2]);
m_fChannelWeights[0] = m_fBaseChannelWeights[0] * fWeightScale;
m_fChannelWeights[1] = m_fBaseChannelWeights[1] * fWeightScale;
m_fChannelWeights[2] = m_fBaseChannelWeights[2] * fWeightScale;
m_fChannelWeights[0] = ((m_fChannelWeights[0] * 3 * medianR) + m_fChannelWeights[0]) * 0.25f;
m_fChannelWeights[1] = ((m_fChannelWeights[1] * 3 * medianG) + m_fChannelWeights[1]) * 0.25f;
m_fChannelWeights[2] = ((m_fChannelWeights[2] * 3 * medianB) + m_fChannelWeights[2]) * 0.25f;
fWeightScale = 1.0f / (m_fChannelWeights[0] + m_fChannelWeights[1] + m_fChannelWeights[2]);
m_fChannelWeights[0] *= fWeightScale;
m_fChannelWeights[1] *= fWeightScale;
m_fChannelWeights[2] *= fWeightScale;
}
return m_fChannelWeights;
}
CODECFLOAT* CCodec_DXTC::CalculateColourWeightings(CODECFLOAT block[BLOCK_SIZE_4X4X4]) {
2020-07-31 11:31:32 +08:00
if(!m_bUseChannelWeighting)
return NULL;
if(m_bUseAdaptiveWeighting) {
2020-07-31 11:31:32 +08:00
float medianR = 0.0f, medianG = 0.0f, medianB = 0.0f;
for(CMP_DWORD k=0; k<BLOCK_SIZE_4X4; k++) {
2020-07-31 11:31:32 +08:00
*block++;
medianB += *block++;
medianG += *block++;
medianR += *block++;
}
medianR /= BLOCK_SIZE_4X4;
medianG /= BLOCK_SIZE_4X4;
medianB /= BLOCK_SIZE_4X4;
// Now skew the colour weightings based on the gravity center of the block
float largest = max(max(medianR, medianG), medianB);
if(largest > 0) {
2020-07-31 11:31:32 +08:00
medianR /= largest;
medianG /= largest;
medianB /= largest;
} else
2020-07-31 11:31:32 +08:00
medianR = medianG = medianB = 1.0f;
// Scale weightings back up to 1.0f
CODECFLOAT fWeightScale = 1.0f / (m_fBaseChannelWeights[0] + m_fBaseChannelWeights[1] + m_fBaseChannelWeights[2]);
m_fChannelWeights[0] *= m_fBaseChannelWeights[0] * fWeightScale;
m_fChannelWeights[1] *= m_fBaseChannelWeights[1] * fWeightScale;
m_fChannelWeights[2] *= m_fBaseChannelWeights[2] * fWeightScale;
m_fChannelWeights[0] = ((m_fChannelWeights[0] * 3 * medianR) + m_fChannelWeights[0]) * 0.25f;
m_fChannelWeights[1] = ((m_fChannelWeights[1] * 3 * medianG) + m_fChannelWeights[1]) * 0.25f;
m_fChannelWeights[2] = ((m_fChannelWeights[2] * 3 * medianB) + m_fChannelWeights[2]) * 0.25f;
fWeightScale = 1.0f / (m_fChannelWeights[0] + m_fChannelWeights[1] + m_fChannelWeights[2]);
m_fChannelWeights[0] *= fWeightScale;
m_fChannelWeights[1] *= fWeightScale;
m_fChannelWeights[2] *= fWeightScale;
}
return m_fChannelWeights;
}