mirror of
https://github.com/yuzu-emu/FasTC
synced 2024-11-25 15:58:56 +00:00
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:
parent
2f8ea3dc07
commit
0b9db85b82
9 changed files with 56 additions and 55 deletions
|
@ -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++;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue