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]; uint32 uncompData[144];
DecompressBlock(blockPtr, blockWidth, blockHeight, uncompData); 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; uint8 *outRow = dcj.OutBuf() + (j*dcj.Width() + i)*4;
for(uint32 jj = 0; jj < blockHeight; jj++) { for(uint32 jj = 0; jj < decompHeight; jj++) {
memcpy(outRow + jj*dcj.Width()*4, uncompData + jj*blockWidth, blockWidth*4); memcpy(outRow + jj*dcj.Width()*4, uncompData + jj*blockWidth, decompWidth*4);
} }
blockIdx++; blockIdx++;

View file

@ -353,10 +353,13 @@ void Decompress(const FasTC::DecompressionJob &dj) {
uint32 pixels[16]; uint32 pixels[16];
DecompressBC7Block(inBuf, pixels); DecompressBC7Block(inBuf, pixels);
memcpy(outBuf + j*dj.Width() + i, pixels, 4 * sizeof(pixels[0])); uint32 decompWidth = std::min(4U, dj.Width() - i);
memcpy(outBuf + (j+1)*dj.Width() + i, pixels+4, 4 * sizeof(pixels[0])); uint32 decompHeight = std::min(4U, dj.Height() - j);
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 *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; inBuf += 16;
} }

View file

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

View file

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

View file

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

View file

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

View file

@ -19,22 +19,28 @@
#include "rg_etc1.h" #include "rg_etc1.h"
#include <algorithm>
#include <cassert>
namespace ETCC { namespace ETCC {
void Decompress(const FasTC::DecompressionJob &cj) { void Decompress(const FasTC::DecompressionJob &dcj) {
uint32 blocksX = (dcj.Width() + 3) / 4;
uint32 blocksX = cj.Width() / 4; uint32 blocksY = (dcj.Height() + 3) / 4;
uint32 blocksY = cj.Height() / 4;
for(uint32 j = 0; j < blocksY; j++) { for(uint32 j = 0; j < blocksY; j++) {
for(uint32 i = 0; i < blocksX; i++) { for(uint32 i = 0; i < blocksX; i++) {
uint32 pixels[16]; uint32 pixels[16];
uint32 blockIdx = j*blocksX + i; uint32 blockIdx = j*blocksX + i;
rg_etc1::unpack_etc1_block(cj.InBuf() + blockIdx * 8, pixels); rg_etc1::unpack_etc1_block(dcj.InBuf() + blockIdx * 8, pixels);
for(uint32 y = 0; y < 4; y++)
for(uint32 x = 0; x < 4; x++) { uint32 decompWidth = std::min(4U, dcj.Width() - i * 4);
uint32 *out = reinterpret_cast<uint32 *>(cj.OutBuf()); uint32 decompHeight = std::min(4U, dcj.Height() - j * 4);
out[(j*4 + y)*cj.Width() + (i*4 + x)] = pixels[y*4 + x];
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; m_Height = pixelHeight;
uint32 uncompressedSize = pixelWidth * pixelHeight * 4; uint32 uncompressedSize = pixelWidth * pixelHeight * 4;
uint32 compressedSize = CompressedImage::GetCompressedSize(uncompressedSize, fmt); uint32 compressedSize = CompressedImage::GetCompressedSize(pixelWidth, pixelHeight, fmt);
assert(compressedSize + 16 == m_NumRawDataBytes); assert(compressedSize + 16 == m_NumRawDataBytes);
m_PixelData = new uint8[compressedSize]; m_PixelData = new uint8[compressedSize];

View file

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