Allow decompressors to decode images whose images are not a multiple

of the block size for the given format. Fixes #27.
This commit is contained in:
Pavel Krajcevski 2016-10-06 23:55:11 -07:00
parent 2f8ea3dc07
commit 0b9db85b82
9 changed files with 56 additions and 55 deletions

View file

@ -970,9 +970,12 @@ namespace ASTCC {
uint32 uncompData[144];
DecompressBlock(blockPtr, blockWidth, blockHeight, uncompData);
uint32 decompWidth = std::min(blockWidth, dcj.Width() - i);
uint32 decompHeight = std::min(blockHeight, dcj.Height() - j);
uint8 *outRow = dcj.OutBuf() + (j*dcj.Width() + i)*4;
for(uint32 jj = 0; jj < blockHeight; jj++) {
memcpy(outRow + jj*dcj.Width()*4, uncompData + jj*blockWidth, blockWidth*4);
for(uint32 jj = 0; jj < decompHeight; jj++) {
memcpy(outRow + jj*dcj.Width()*4, uncompData + jj*blockWidth, decompWidth*4);
}
blockIdx++;

View file

@ -353,10 +353,13 @@ void Decompress(const FasTC::DecompressionJob &dj) {
uint32 pixels[16];
DecompressBC7Block(inBuf, pixels);
memcpy(outBuf + j*dj.Width() + i, pixels, 4 * sizeof(pixels[0]));
memcpy(outBuf + (j+1)*dj.Width() + i, pixels+4, 4 * sizeof(pixels[0]));
memcpy(outBuf + (j+2)*dj.Width() + i, pixels+8, 4 * sizeof(pixels[0]));
memcpy(outBuf + (j+3)*dj.Width() + i, pixels+12, 4 * sizeof(pixels[0]));
uint32 decompWidth = std::min(4U, dj.Width() - i);
uint32 decompHeight = std::min(4U, dj.Height() - j);
uint32 *outRow = outBuf + j * dj.Width() + i;
for (uint32 jj = 0; jj < decompHeight; ++jj) {
memcpy(outRow + jj*dj.Width(), pixels + 4 * jj, decompWidth * sizeof(pixels[0]));
}
inBuf += 16;
}

View file

@ -51,14 +51,10 @@ class CompressedImage : public FasTC::Image<FasTC::Pixel> {
virtual void ComputePixels();
static uint32 GetCompressedSize(uint32 uncompressedSize, FasTC::ECompressionFormat format);
static uint32 GetUncompressedSize(uint32 compressedSize, FasTC::ECompressionFormat format) {
uint32 cmp = GetCompressedSize(compressedSize, format);
return compressedSize * (compressedSize / cmp);
}
static uint32 GetCompressedSize(uint32 width, uint32 height, FasTC::ECompressionFormat format);
uint32 GetCompressedSize() const {
return GetCompressedSize(GetUncompressedSize(), m_Format);
return GetCompressedSize(GetWidth(), GetHeight(), m_Format);
}
uint32 GetUncompressedSize() const {
return GetWidth() * GetHeight() * sizeof(uint32);

View file

@ -133,21 +133,16 @@ void CompressedImage::ComputePixels() {
SetImageData(GetWidth(), GetHeight(), newPixels);
}
uint32 CompressedImage::GetCompressedSize(uint32 uncompressedSize, ECompressionFormat format) {
// Make sure that the uncompressed size is a multiple of the pixel size.
assert(uncompressedSize % sizeof(uint32) == 0);
uint32 CompressedImage::GetCompressedSize(uint32 width, uint32 height, ECompressionFormat format) {
// The compressed size is the block size times the number of blocks
uint32 blockDim[2];
GetBlockDimensions(format, blockDim);
const uint32 blocksWide = (width + blockDim[0] - 1) / blockDim[0];
const uint32 blocksHigh = (height + blockDim[1] - 1) / blockDim[1];
const uint32 uncompBlockSize = blockDim[0] * blockDim[1] * sizeof(uint32);
// The uncompressed block size should be a factor of the uncompressed size.
assert(uncompressedSize % uncompBlockSize == 0);
const uint32 nBlocks = uncompressedSize / uncompBlockSize;
const uint32 nBlocks = blocksWide * blocksHigh;
const uint32 blockSz = GetBlockSize(format);
return nBlocks * blockSz;

View file

@ -392,14 +392,13 @@ CompressedImage *CompressImage(
height = newHeight;
}
uint32 dataSz = width * height * 4;
uint32 *data = new uint32[dataSz / 4];
memset(data, 0, dataSz);
uint32 *data = new uint32[width * height];
memset(data, 0, width * height * sizeof(data[0]));
CompressedImage *outImg = NULL;
// Allocate data based on the compression method
uint32 cmpDataSz = CompressedImage::GetCompressedSize(dataSz, settings.format);
uint32 cmpDataSz = CompressedImage::GetCompressedSize(width, height, settings.format);
// Make sure that we have RGBA data...
img->ComputePixels();
@ -485,7 +484,7 @@ bool CompressImageData(
// Allocate data based on the compression method
uint32 compressedDataSzNeeded =
CompressedImage::GetCompressedSize(dataSz, settings.format);
CompressedImage::GetCompressedSize(width, height, settings.format);
if(compressedDataSzNeeded == 0) {
ReportError("Unknown compression format");

View file

@ -17,6 +17,7 @@
#include "FasTC/DXTCompressor.h"
#include <algorithm>
#include <cassert>
#include <cstdlib>
#include <cstring>
@ -94,13 +95,9 @@ namespace {
namespace DXTC
{
void DecompressDXT1(const FasTC::DecompressionJob &dcj)
{
assert(!(dcj.Height() & 3));
assert(!(dcj.Width() & 3));
uint32 blockW = dcj.Width() >> 2;
uint32 blockH = dcj.Height() >> 2;
void DecompressDXT1(const FasTC::DecompressionJob &dcj) {
uint32 blockW = (dcj.Width() + 3) >> 2;
uint32 blockH = (dcj.Height() + 3) >> 2;
const uint32 blockSz = GetBlockSize(FasTC::eCompressionFormat_DXT1);
@ -115,8 +112,11 @@ namespace DXTC
uint32 offset = (j * blockW + i) * blockSz;
DecompressDXT1Block(dcj.InBuf() + offset, outBlock, true);
for(uint32 y = 0; y < 4; y++)
for(uint32 x = 0; x < 4; x++) {
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
for(uint32 y = 0; y < decompHeight; y++)
for(uint32 x = 0; x < decompWidth; x++) {
offset = (j*4 + y)*dcj.Width() + ((i*4)+x);
outPixels[offset] = outBlock[y*4 + x];
}
@ -124,13 +124,9 @@ namespace DXTC
}
}
void DecompressDXT5(const FasTC::DecompressionJob &dcj)
{
assert(!(dcj.Height() & 3));
assert(!(dcj.Width() & 3));
uint32 blockW = dcj.Width() >> 2;
uint32 blockH = dcj.Height() >> 2;
void DecompressDXT5(const FasTC::DecompressionJob &dcj) {
uint32 blockW = (dcj.Width() + 3) >> 2;
uint32 blockH = (dcj.Height() + 3) >> 2;
const uint32 blockSz = GetBlockSize(FasTC::eCompressionFormat_DXT5);
@ -146,8 +142,11 @@ namespace DXTC
DecompressDXT5Block(dcj.InBuf() + offset, outBlock);
DecompressDXT1Block(dcj.InBuf() + offset + blockSz / 2, outBlock, false);
for (uint32 y = 0; y < 4; y++)
for (uint32 x = 0; x < 4; x++) {
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
for (uint32 y = 0; y < decompHeight; y++)
for (uint32 x = 0; x < decompWidth; x++) {
offset = (j * 4 + y)*dcj.Width() + ((i * 4) + x);
outPixels[offset] = outBlock[y * 4 + x];
}

View file

@ -19,22 +19,28 @@
#include "rg_etc1.h"
#include <algorithm>
#include <cassert>
namespace ETCC {
void Decompress(const FasTC::DecompressionJob &cj) {
uint32 blocksX = cj.Width() / 4;
uint32 blocksY = cj.Height() / 4;
void Decompress(const FasTC::DecompressionJob &dcj) {
uint32 blocksX = (dcj.Width() + 3) / 4;
uint32 blocksY = (dcj.Height() + 3) / 4;
for(uint32 j = 0; j < blocksY; j++) {
for(uint32 i = 0; i < blocksX; i++) {
uint32 pixels[16];
uint32 blockIdx = j*blocksX + i;
rg_etc1::unpack_etc1_block(cj.InBuf() + blockIdx * 8, pixels);
for(uint32 y = 0; y < 4; y++)
for(uint32 x = 0; x < 4; x++) {
uint32 *out = reinterpret_cast<uint32 *>(cj.OutBuf());
out[(j*4 + y)*cj.Width() + (i*4 + x)] = pixels[y*4 + x];
rg_etc1::unpack_etc1_block(dcj.InBuf() + blockIdx * 8, pixels);
uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
for(uint32 y = 0; y < decompHeight; y++)
for(uint32 x = 0; x < decompWidth; x++) {
uint32 *out = reinterpret_cast<uint32 *>(dcj.OutBuf());
out[(j*4 + y)*dcj.Width() + (i*4 + x)] = pixels[y*4 + x];
}
}
}

View file

@ -188,7 +188,7 @@ bool ImageLoaderASTC::ReadData() {
m_Height = pixelHeight;
uint32 uncompressedSize = pixelWidth * pixelHeight * 4;
uint32 compressedSize = CompressedImage::GetCompressedSize(uncompressedSize, fmt);
uint32 compressedSize = CompressedImage::GetCompressedSize(pixelWidth, pixelHeight, fmt);
assert(compressedSize + 16 == m_NumRawDataBytes);
m_PixelData = new uint8[compressedSize];

View file

@ -305,7 +305,7 @@ bool ImageLoaderKTX::ReadData() {
return false;
}
uint32 dataSize = CompressedImage::GetCompressedSize(pixelWidth * pixelHeight * 4, m_Format);
uint32 dataSize = CompressedImage::GetCompressedSize(pixelWidth, pixelHeight, m_Format);
m_PixelData = new uint8[dataSize];
memcpy(m_PixelData, rdr.GetData(), dataSize);
rdr.Advance(dataSize);