mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2024-11-28 03:14:15 +01:00
Broke the coupling between ImageFile and Image. One is strictly for IO, the other can be platform and file format agnostic.
This commit is contained in:
parent
c1222d75f9
commit
2c22889533
@ -4,6 +4,7 @@
|
||||
|
||||
#include "TexComp.h"
|
||||
#include "ImageFile.h"
|
||||
#include "Image.h"
|
||||
|
||||
void PrintUsage() {
|
||||
fprintf(stderr, "Usage: tc [-s|-t <num>] <imagefile>\n");
|
||||
@ -76,6 +77,11 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
ImageFile file (argv[fileArg]);
|
||||
const Image *img = file.GetImage();
|
||||
if(NULL == img) {
|
||||
fprintf(stderr, "Error loading file: %s\n", argv[fileArg]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SCompressionSettings settings;
|
||||
settings.bUseSIMD = bUseSIMD;
|
||||
@ -83,13 +89,13 @@ int main(int argc, char **argv) {
|
||||
settings.iQuality = quality;
|
||||
settings.iNumCompressions = numCompressions;
|
||||
|
||||
CompressedImage *ci = file.Compress(settings);
|
||||
CompressedImage *ci = img->Compress(settings);
|
||||
if(NULL == ci) {
|
||||
fprintf(stderr, "Error compressing image!\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
double PSNR = ComputePSNR(*ci, file);
|
||||
double PSNR = img->ComputePSNR(*ci);
|
||||
if(PSNR > 0.0) {
|
||||
fprintf(stdout, "PSNR: %.3f\n", PSNR);
|
||||
}
|
||||
|
@ -2,12 +2,14 @@
|
||||
SET( SOURCES
|
||||
"src/TexComp.cpp"
|
||||
"src/CompressedImage.cpp"
|
||||
"src/Image.cpp"
|
||||
)
|
||||
|
||||
SET( HEADERS
|
||||
"include/TexComp.h"
|
||||
"include/CompressedImage.h"
|
||||
"include/TexCompTypes.h"
|
||||
"include/Image.h"
|
||||
)
|
||||
|
||||
# Make sure to add the appropriate stopwatch files...
|
||||
|
30
Core/include/Image.h
Normal file
30
Core/include/Image.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef __TEXCOMP_IMAGE_H__
|
||||
#define __TEXCOMP_IMAGE_H__
|
||||
|
||||
#include "TexCompTypes.h"
|
||||
#include "TexComp.h"
|
||||
|
||||
// Forward declarations
|
||||
class ImageLoader;
|
||||
|
||||
// Class definition
|
||||
class Image {
|
||||
|
||||
public:
|
||||
Image(const ImageLoader &);
|
||||
const uint8 *RawData() const { return m_PixelData; }
|
||||
|
||||
CompressedImage *Compress(const SCompressionSettings &settings) const;
|
||||
double ComputePSNR(const CompressedImage &ci) const;
|
||||
|
||||
uint32 GetWidth() const { return m_Width; }
|
||||
uint32 GetHeight() const { return m_Height; }
|
||||
|
||||
private:
|
||||
uint32 m_Width;
|
||||
uint32 m_Height;
|
||||
|
||||
uint8 *m_PixelData;
|
||||
};
|
||||
|
||||
#endif // __TEXCOMP_IMAGE_H__
|
94
Core/src/Image.cpp
Normal file
94
Core/src/Image.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "Image.h"
|
||||
#include "ImageLoader.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
template <typename T>
|
||||
static inline T sad( const T &a, const T &b ) {
|
||||
return (a > b)? a - b : b - a;
|
||||
}
|
||||
|
||||
Image::Image(const ImageLoader &loader)
|
||||
: m_PixelData(0)
|
||||
, m_Width(loader.GetWidth())
|
||||
, m_Height(loader.GetHeight())
|
||||
{
|
||||
if(loader.GetImageData()) {
|
||||
m_PixelData = new uint8[ loader.GetImageDataSz() ];
|
||||
if(!m_PixelData) { fprintf(stderr, "%s\n", "Out of memory!"); return; }
|
||||
memcpy(m_PixelData, loader.GetImageData(), loader.GetImageDataSz());
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "%s\n", "Failed to get data from image loader!");
|
||||
}
|
||||
}
|
||||
|
||||
CompressedImage *Image::Compress(const SCompressionSettings &settings) const {
|
||||
CompressedImage *outImg = NULL;
|
||||
const unsigned int dataSz = GetWidth() * GetHeight() * 4;
|
||||
|
||||
assert(dataSz > 0);
|
||||
|
||||
// Allocate data based on the compression method
|
||||
int cmpDataSz = 0;
|
||||
switch(settings.format) {
|
||||
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8;
|
||||
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4;
|
||||
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4;
|
||||
}
|
||||
|
||||
unsigned char *cmpData = new unsigned char[cmpDataSz];
|
||||
CompressImageData(m_PixelData, dataSz, cmpData, cmpDataSz, settings);
|
||||
|
||||
outImg = new CompressedImage(GetWidth(), GetHeight(), settings.format, cmpData);
|
||||
return outImg;
|
||||
}
|
||||
|
||||
double Image::ComputePSNR(const CompressedImage &ci) const {
|
||||
unsigned int imageSz = 4 * GetWidth() * GetHeight();
|
||||
unsigned char *unCompData = new unsigned char[imageSz];
|
||||
if(!(ci.DecompressImage(unCompData, imageSz))) {
|
||||
fprintf(stderr, "%s\n", "Failed to decompress image.");
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
const double wr = 1.0;
|
||||
const double wg = 1.0;
|
||||
const double wb = 1.0;
|
||||
|
||||
double MSE = 0.0;
|
||||
for(int i = 0; i < imageSz; i+=4) {
|
||||
|
||||
const unsigned char *pixelDataRaw = m_PixelData + i;
|
||||
const unsigned char *pixelDataUncomp = unCompData + i;
|
||||
|
||||
double dr = double(sad(pixelDataRaw[0], pixelDataUncomp[0])) * wr;
|
||||
double dg = double(sad(pixelDataRaw[1], pixelDataUncomp[1])) * wg;
|
||||
double db = double(sad(pixelDataRaw[2], pixelDataUncomp[2])) * wb;
|
||||
|
||||
const double pixelMSE =
|
||||
(double(dr) * double(dr)) +
|
||||
(double(dg) * double(dg)) +
|
||||
(double(db) * double(db));
|
||||
|
||||
//fprintf(stderr, "Pixel MSE: %f\n", pixelMSE);
|
||||
MSE += pixelMSE;
|
||||
}
|
||||
|
||||
MSE /= (double(GetWidth()) * double(GetHeight()));
|
||||
|
||||
double MAXI =
|
||||
(255.0 * wr) * (255.0 * wr) +
|
||||
(255.0 * wg) * (255.0 * wg) +
|
||||
(255.0 * wb) * (255.0 * wb);
|
||||
|
||||
double PSNR = 10 * log10(MAXI/MSE);
|
||||
|
||||
// Cleanup
|
||||
delete unCompData;
|
||||
return PSNR;
|
||||
}
|
@ -1,13 +1,15 @@
|
||||
#include "BC7Compressor.h"
|
||||
#include "TexComp.h"
|
||||
#include "ThreadGroup.h"
|
||||
#include "ImageFile.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "BC7Compressor.h"
|
||||
#include "ThreadGroup.h"
|
||||
#include "ImageFile.h"
|
||||
#include "Image.h"
|
||||
|
||||
template <typename T>
|
||||
static T min(const T &a, const T &b) {
|
||||
return (a < b)? a : b;
|
||||
@ -192,51 +194,3 @@ bool CompressImageData(
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
double ComputePSNR(const CompressedImage &ci, const ImageFile &file) {
|
||||
unsigned int imageSz = 4 * file.GetWidth() * file.GetHeight();
|
||||
unsigned char *unCompData = new unsigned char[imageSz];
|
||||
if(!(ci.DecompressImage(unCompData, imageSz))) {
|
||||
ReportError("Failed to decompress image.");
|
||||
return -1.0f;
|
||||
}
|
||||
|
||||
const unsigned char *rawData = file.RawData();
|
||||
|
||||
const double wr = 1.0;
|
||||
const double wg = 1.0;
|
||||
const double wb = 1.0;
|
||||
|
||||
double MSE = 0.0;
|
||||
for(int i = 0; i < imageSz; i+=4) {
|
||||
|
||||
const unsigned char *pixelDataRaw = rawData + i;
|
||||
const unsigned char *pixelDataUncomp = unCompData + i;
|
||||
|
||||
double dr = double(sad(pixelDataRaw[0], pixelDataUncomp[0])) * wr;
|
||||
double dg = double(sad(pixelDataRaw[1], pixelDataUncomp[1])) * wg;
|
||||
double db = double(sad(pixelDataRaw[2], pixelDataUncomp[2])) * wb;
|
||||
|
||||
const double pixelMSE =
|
||||
(double(dr) * double(dr)) +
|
||||
(double(dg) * double(dg)) +
|
||||
(double(db) * double(db));
|
||||
|
||||
//fprintf(stderr, "Pixel MSE: %f\n", pixelMSE);
|
||||
MSE += pixelMSE;
|
||||
}
|
||||
|
||||
MSE /= (double(file.GetWidth()) * double(file.GetHeight()));
|
||||
|
||||
double MAXI =
|
||||
(255.0 * wr) * (255.0 * wr) +
|
||||
(255.0 * wg) * (255.0 * wg) +
|
||||
(255.0 * wb) * (255.0 * wb);
|
||||
|
||||
double PSNR = 10 * log10(MAXI/MSE);
|
||||
|
||||
// Cleanup
|
||||
delete unCompData;
|
||||
return PSNR;
|
||||
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
|
||||
SET( SOURCES
|
||||
"src/ImageFile.cpp"
|
||||
"src/ImageLoader.cpp"
|
||||
)
|
||||
|
||||
SET( HEADERS
|
||||
|
@ -11,21 +11,24 @@ class ImageLoader {
|
||||
uint32 m_Width;
|
||||
uint32 m_Height;
|
||||
|
||||
unsigned int m_RedChannelPrecision;
|
||||
unsigned char *m_RedData;
|
||||
uint32 m_RedChannelPrecision;
|
||||
uint8 *m_RedData;
|
||||
|
||||
unsigned int m_GreenChannelPrecision;
|
||||
unsigned char *m_GreenData;
|
||||
uint32 m_GreenChannelPrecision;
|
||||
uint8 *m_GreenData;
|
||||
|
||||
unsigned int m_BlueChannelPrecision;
|
||||
unsigned char *m_BlueData;
|
||||
uint32 m_BlueChannelPrecision;
|
||||
uint8 *m_BlueData;
|
||||
|
||||
unsigned int m_AlphaChannelPrecision;
|
||||
unsigned char *m_AlphaData;
|
||||
uint32 m_AlphaChannelPrecision;
|
||||
uint8 *m_AlphaData;
|
||||
|
||||
const unsigned char *const m_RawData;
|
||||
uint8 *m_PixelData;
|
||||
const uint8 *const m_RawData;
|
||||
|
||||
ImageLoader(const unsigned char *rawData) : m_RawData(rawData)
|
||||
ImageLoader(const uint8 *rawData)
|
||||
: m_RawData(rawData)
|
||||
, m_PixelData(0)
|
||||
, m_Width(0), m_Height(0)
|
||||
, m_RedChannelPrecision(0), m_RedData(0)
|
||||
, m_GreenChannelPrecision(0), m_GreenData(0)
|
||||
@ -33,6 +36,9 @@ class ImageLoader {
|
||||
, m_AlphaChannelPrecision(0), m_AlphaData(0)
|
||||
{ }
|
||||
|
||||
uint32 GetChannelForPixel(uint32 x, uint32 y, uint32 ch);
|
||||
|
||||
public:
|
||||
virtual ~ImageLoader() {
|
||||
if(m_RedData) {
|
||||
delete [] m_RedData;
|
||||
@ -55,23 +61,26 @@ class ImageLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual bool ReadData() = 0;
|
||||
|
||||
int GetRedChannelPrecision() const { return m_RedChannelPrecision; }
|
||||
const unsigned char * GetRedPixelData() const { return m_RedData; }
|
||||
uint32 GetRedChannelPrecision() const { return m_RedChannelPrecision; }
|
||||
const uint8 * GetRedPixelData() const { return m_RedData; }
|
||||
|
||||
int GetGreenChannelPrecision() const { return m_GreenChannelPrecision; }
|
||||
const unsigned char * GetGreenPixelData() const { return m_GreenData; }
|
||||
uint32 GetGreenChannelPrecision() const { return m_GreenChannelPrecision; }
|
||||
const uint8 * GetGreenPixelData() const { return m_GreenData; }
|
||||
|
||||
int GetBlueChannelPrecision() const { return m_BlueChannelPrecision; }
|
||||
const unsigned char * GetBluePixelData() const { return m_BlueData; }
|
||||
uint32 GetBlueChannelPrecision() const { return m_BlueChannelPrecision; }
|
||||
const uint8 * GetBluePixelData() const { return m_BlueData; }
|
||||
|
||||
int GetAlphaChannelPrecision() const { return m_AlphaChannelPrecision; }
|
||||
const unsigned char * GetAlphaPixelData() const { return m_AlphaData; }
|
||||
uint32 GetAlphaChannelPrecision() const { return m_AlphaChannelPrecision; }
|
||||
const uint8 * GetAlphaPixelData() const { return m_AlphaData; }
|
||||
|
||||
int GetWidth() const { return m_Width; }
|
||||
int GetHeight() const { return m_Height; }
|
||||
uint32 GetWidth() const { return m_Width; }
|
||||
uint32 GetHeight() const { return m_Height; }
|
||||
uint32 GetImageDataSz() const { return m_Width * m_Height * 4; }
|
||||
|
||||
bool LoadImage();
|
||||
const uint8 *GetImageData() const { return m_PixelData; }
|
||||
};
|
||||
|
||||
#cmakedefine PNG_FOUND
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "ImageFileFormat.h"
|
||||
|
||||
// Forward declare
|
||||
class Image;
|
||||
class CompressedImage;
|
||||
|
||||
// Class definition
|
||||
@ -18,19 +19,20 @@ public:
|
||||
unsigned int GetWidth() const { return m_Width; }
|
||||
unsigned int GetHeight() const { return m_Height; }
|
||||
CompressedImage *Compress(const SCompressionSettings &) const;
|
||||
|
||||
const unsigned char *RawData() const { return m_PixelData; }
|
||||
Image *GetImage() const { return m_Image; }
|
||||
|
||||
private:
|
||||
unsigned int m_Handle;
|
||||
unsigned int m_Width;
|
||||
unsigned int m_Height;
|
||||
unsigned char *m_PixelData;
|
||||
|
||||
Image *m_Image;
|
||||
|
||||
const EImageFileFormat m_FileFormat;
|
||||
|
||||
static unsigned char *ReadFileData(const char *filename);
|
||||
static EImageFileFormat DetectFileFormat(const char *filename);
|
||||
|
||||
bool LoadImage(const unsigned char *rawImageData);
|
||||
Image *LoadImage(const unsigned char *rawImageData) const;
|
||||
};
|
||||
#endif // _IMAGE_FILE_H_
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "ImageFile.h"
|
||||
#include "ImageLoader.h"
|
||||
#include "CompressedImage.h"
|
||||
#include "Image.h"
|
||||
|
||||
#ifdef PNG_FOUND
|
||||
# include "ImageLoaderPNG.h"
|
||||
@ -33,109 +34,74 @@ static inline T min(const T &a, const T &b) {
|
||||
return (a < b)? a : b;
|
||||
}
|
||||
|
||||
static unsigned int GetChannelForPixel(
|
||||
const ImageLoader *loader,
|
||||
unsigned int x, unsigned int y,
|
||||
int ch
|
||||
) {
|
||||
unsigned int prec;
|
||||
const unsigned char *data;
|
||||
|
||||
switch(ch) {
|
||||
case 0:
|
||||
prec = loader->GetRedChannelPrecision();
|
||||
data = loader->GetRedPixelData();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
prec = loader->GetGreenChannelPrecision();
|
||||
data = loader->GetGreenPixelData();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
prec = loader->GetBlueChannelPrecision();
|
||||
data = loader->GetBluePixelData();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
prec = loader->GetAlphaChannelPrecision();
|
||||
data = loader->GetAlphaPixelData();
|
||||
break;
|
||||
|
||||
default:
|
||||
ReportError("Unspecified channel");
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
if(0 == prec)
|
||||
return 0;
|
||||
|
||||
assert(x < loader->GetWidth());
|
||||
assert(y < loader->GetHeight());
|
||||
|
||||
int pixelIdx = y * loader->GetWidth() + x;
|
||||
const unsigned int val = data[pixelIdx];
|
||||
|
||||
if(prec < 8) {
|
||||
unsigned int ret = 0;
|
||||
for(unsigned int precLeft = 8; precLeft > 0; precLeft -= min(prec, abs(prec - precLeft))) {
|
||||
|
||||
if(prec > precLeft) {
|
||||
const int toShift = prec - precLeft;
|
||||
ret = ret << precLeft;
|
||||
ret |= val >> toShift;
|
||||
}
|
||||
else {
|
||||
ret = ret << prec;
|
||||
ret |= val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else if(prec > 8) {
|
||||
const int toShift = prec - 8;
|
||||
return val >> toShift;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ImageFile implementation
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ImageFile::ImageFile(const char *filename) :
|
||||
m_PixelData(0),
|
||||
m_FileFormat( DetectFileFormat(filename) )
|
||||
ImageFile::ImageFile(const char *filename)
|
||||
: m_FileFormat( DetectFileFormat(filename) )
|
||||
, m_Image(NULL)
|
||||
{
|
||||
unsigned char *rawData = ReadFileData(filename);
|
||||
if(rawData) {
|
||||
LoadImage(rawData);
|
||||
m_Image = LoadImage(rawData);
|
||||
delete [] rawData;
|
||||
}
|
||||
}
|
||||
|
||||
ImageFile::ImageFile(const char *filename, EImageFileFormat format) :
|
||||
m_FileFormat(format),
|
||||
m_PixelData(0)
|
||||
ImageFile::ImageFile(const char *filename, EImageFileFormat format)
|
||||
: m_FileFormat(format)
|
||||
, m_Image(NULL)
|
||||
{
|
||||
unsigned char *rawData = ReadFileData(filename);
|
||||
if(rawData) {
|
||||
LoadImage(rawData);
|
||||
m_Image = LoadImage(rawData);
|
||||
delete [] rawData;
|
||||
}
|
||||
}
|
||||
|
||||
ImageFile::~ImageFile() {
|
||||
if(m_PixelData) {
|
||||
delete [] m_PixelData;
|
||||
if(m_Image) {
|
||||
delete m_Image;
|
||||
m_Image = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
Image *ImageFile::LoadImage(const unsigned char *rawImageData) const {
|
||||
|
||||
ImageLoader *loader = NULL;
|
||||
switch(m_FileFormat) {
|
||||
|
||||
#ifdef PNG_FOUND
|
||||
case eFileFormat_PNG:
|
||||
{
|
||||
loader = new ImageLoaderPNG(rawImageData);
|
||||
}
|
||||
break;
|
||||
#endif // PNG_FOUND
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unable to load image: unknown file format.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(!loader)
|
||||
return NULL;
|
||||
|
||||
if(!(loader->LoadImage())) {
|
||||
fprintf(stderr, "Unable to load image!\n");
|
||||
delete loader;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Image *i = new Image(*loader);
|
||||
delete loader;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
|
||||
|
||||
int len = strlen(filename);
|
||||
@ -164,106 +130,6 @@ EImageFileFormat ImageFile::DetectFileFormat(const char *filename) {
|
||||
return kNumImageFileFormats;
|
||||
}
|
||||
|
||||
bool ImageFile::LoadImage(const unsigned char *rawImageData) {
|
||||
|
||||
ImageLoader *loader = NULL;
|
||||
switch(m_FileFormat) {
|
||||
|
||||
#ifdef PNG_FOUND
|
||||
case eFileFormat_PNG:
|
||||
{
|
||||
loader = new ImageLoaderPNG(rawImageData);
|
||||
}
|
||||
break;
|
||||
#endif // PNG_FOUND
|
||||
|
||||
default:
|
||||
fprintf(stderr, "Unable to load image: unknown file format.\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// Read the image data!
|
||||
if(!loader->ReadData())
|
||||
return false;
|
||||
|
||||
m_Width = loader->GetWidth();
|
||||
m_Height = loader->GetHeight();
|
||||
|
||||
// Create RGBA buffer
|
||||
const unsigned int dataSz = 4 * m_Width * m_Height;
|
||||
m_PixelData = new unsigned char[dataSz];
|
||||
|
||||
// Populate buffer in block stream order... make
|
||||
// sure that width and height are aligned to multiples of four.
|
||||
const unsigned int aw = ((m_Width + 3) >> 2) << 2;
|
||||
const unsigned int ah = ((m_Height + 3) >> 2) << 2;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if(aw != m_Width || ah != m_Height)
|
||||
fprintf(stderr, "Warning: Image dimension not multiple of four. Space will be filled with black.\n");
|
||||
#endif
|
||||
|
||||
int byteIdx = 0;
|
||||
for(int i = 0; i < ah; i+=4) {
|
||||
for(int j = 0; j < aw; j+= 4) {
|
||||
|
||||
// For each block, visit the pixels in sequential order
|
||||
for(int y = i; y < i+4; y++) {
|
||||
for(int x = j; x < j+4; x++) {
|
||||
|
||||
if(y >= m_Height || x >= m_Width) {
|
||||
m_PixelData[byteIdx++] = 0; // r
|
||||
m_PixelData[byteIdx++] = 0; // g
|
||||
m_PixelData[byteIdx++] = 0; // b
|
||||
m_PixelData[byteIdx++] = 0; // a
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int redVal = GetChannelForPixel(loader, x, y, 0);
|
||||
if(redVal == INT_MAX)
|
||||
return false;
|
||||
|
||||
unsigned int greenVal = redVal;
|
||||
unsigned int blueVal = redVal;
|
||||
|
||||
if(loader->GetGreenChannelPrecision() > 0) {
|
||||
greenVal = GetChannelForPixel(loader, x, y, 1);
|
||||
if(greenVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(loader->GetBlueChannelPrecision() > 0) {
|
||||
blueVal = GetChannelForPixel(loader, x, y, 2);
|
||||
if(blueVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int alphaVal = 0xFF;
|
||||
if(loader->GetAlphaChannelPrecision() > 0) {
|
||||
alphaVal = GetChannelForPixel(loader, x, y, 3);
|
||||
if(alphaVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Red channel
|
||||
m_PixelData[byteIdx++] = redVal & 0xFF;
|
||||
|
||||
// Green channel
|
||||
m_PixelData[byteIdx++] = greenVal & 0xFF;
|
||||
|
||||
// Blue channel
|
||||
m_PixelData[byteIdx++] = blueVal & 0xFF;
|
||||
|
||||
// Alpha channel
|
||||
m_PixelData[byteIdx++] = alphaVal & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
unsigned char *ImageFile::ReadFileData(const char *filename) {
|
||||
//!FIXME! - Actually, implement me
|
||||
@ -304,25 +170,3 @@ unsigned char *ImageFile::ReadFileData(const char *filename) {
|
||||
return rawData;
|
||||
}
|
||||
#endif
|
||||
|
||||
CompressedImage *ImageFile::Compress(const SCompressionSettings &settings) const {
|
||||
CompressedImage *outImg = NULL;
|
||||
const unsigned int dataSz = GetWidth() * GetHeight() * 4;
|
||||
|
||||
assert(dataSz > 0);
|
||||
|
||||
// Allocate data based on the compression method
|
||||
int cmpDataSz = 0;
|
||||
switch(settings.format) {
|
||||
case eCompressionFormat_DXT1: cmpDataSz = dataSz / 8;
|
||||
case eCompressionFormat_DXT5: cmpDataSz = dataSz / 4;
|
||||
case eCompressionFormat_BPTC: cmpDataSz = dataSz / 4;
|
||||
}
|
||||
|
||||
unsigned char *cmpData = new unsigned char[cmpDataSz];
|
||||
CompressImageData(m_PixelData, dataSz, cmpData, cmpDataSz, settings);
|
||||
|
||||
outImg = new CompressedImage(GetWidth(), GetHeight(), settings.format, cmpData);
|
||||
return outImg;
|
||||
}
|
||||
|
||||
|
174
IO/src/ImageLoader.cpp
Normal file
174
IO/src/ImageLoader.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include "ImageLoader.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include <assert.h>
|
||||
|
||||
template <typename T>
|
||||
static inline T min(const T &a, const T &b) {
|
||||
return (a > b)? b : a;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline T abs(const T &a) {
|
||||
return (a > 0)? a : -a;
|
||||
}
|
||||
|
||||
void ReportError(const char *str) {
|
||||
fprintf(stderr, "ImageLoader.cpp -- ERROR: %s\n", str);
|
||||
}
|
||||
|
||||
unsigned int ImageLoader::GetChannelForPixel(uint32 x, uint32 y, uint32 ch) {
|
||||
uint32 prec;
|
||||
const uint8 *data;
|
||||
|
||||
switch(ch) {
|
||||
case 0:
|
||||
prec = GetRedChannelPrecision();
|
||||
data = GetRedPixelData();
|
||||
break;
|
||||
|
||||
case 1:
|
||||
prec = GetGreenChannelPrecision();
|
||||
data = GetGreenPixelData();
|
||||
break;
|
||||
|
||||
case 2:
|
||||
prec = GetBlueChannelPrecision();
|
||||
data = GetBluePixelData();
|
||||
break;
|
||||
|
||||
case 3:
|
||||
prec = GetAlphaChannelPrecision();
|
||||
data = GetAlphaPixelData();
|
||||
break;
|
||||
|
||||
default:
|
||||
ReportError("Unspecified channel");
|
||||
return INT_MAX;
|
||||
}
|
||||
|
||||
if(0 == prec)
|
||||
return 0;
|
||||
|
||||
assert(x < GetWidth());
|
||||
assert(y < GetHeight());
|
||||
|
||||
uint32 pixelIdx = y * GetWidth() + x;
|
||||
const uint32 val = data[pixelIdx];
|
||||
|
||||
if(prec < 8) {
|
||||
uint32 ret = 0;
|
||||
for(uint32 precLeft = 8; precLeft > 0; precLeft -= min(prec, abs(prec - precLeft))) {
|
||||
|
||||
if(prec > precLeft) {
|
||||
const int toShift = prec - precLeft;
|
||||
ret = ret << precLeft;
|
||||
ret |= val >> toShift;
|
||||
}
|
||||
else {
|
||||
ret = ret << prec;
|
||||
ret |= val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
else if(prec > 8) {
|
||||
const int toShift = prec - 8;
|
||||
return val >> toShift;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
bool ImageLoader::LoadImage() {
|
||||
|
||||
// Do we already have pixel data?
|
||||
if(m_PixelData)
|
||||
return true;
|
||||
|
||||
// Read the image data!
|
||||
if(!ReadData())
|
||||
return false;
|
||||
|
||||
m_Width = GetWidth();
|
||||
m_Height = GetHeight();
|
||||
|
||||
// Create RGBA buffer
|
||||
const unsigned int dataSz = 4 * m_Width * m_Height;
|
||||
|
||||
m_PixelData = new unsigned char[dataSz];
|
||||
|
||||
// Populate buffer in block stream order... make
|
||||
// sure that width and height are aligned to multiples of four.
|
||||
const unsigned int aw = ((m_Width + 3) >> 2) << 2;
|
||||
const unsigned int ah = ((m_Height + 3) >> 2) << 2;
|
||||
|
||||
#ifndef NDEBUG
|
||||
if(aw != m_Width || ah != m_Height)
|
||||
fprintf(stderr, "Warning: Image dimension not multiple of four. Space will be filled with black.\n");
|
||||
#endif
|
||||
|
||||
int byteIdx = 0;
|
||||
for(int i = 0; i < ah; i+=4) {
|
||||
for(int j = 0; j < aw; j+= 4) {
|
||||
|
||||
// For each block, visit the pixels in sequential order
|
||||
for(int y = i; y < i+4; y++) {
|
||||
for(int x = j; x < j+4; x++) {
|
||||
|
||||
if(y >= m_Height || x >= m_Width) {
|
||||
m_PixelData[byteIdx++] = 0; // r
|
||||
m_PixelData[byteIdx++] = 0; // g
|
||||
m_PixelData[byteIdx++] = 0; // b
|
||||
m_PixelData[byteIdx++] = 0; // a
|
||||
continue;
|
||||
}
|
||||
|
||||
unsigned int redVal = GetChannelForPixel(x, y, 0);
|
||||
if(redVal == INT_MAX)
|
||||
return false;
|
||||
|
||||
unsigned int greenVal = redVal;
|
||||
unsigned int blueVal = redVal;
|
||||
|
||||
if(GetGreenChannelPrecision() > 0) {
|
||||
greenVal = GetChannelForPixel(x, y, 1);
|
||||
if(greenVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
if(GetBlueChannelPrecision() > 0) {
|
||||
blueVal = GetChannelForPixel(x, y, 2);
|
||||
if(blueVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned int alphaVal = 0xFF;
|
||||
if(GetAlphaChannelPrecision() > 0) {
|
||||
alphaVal = GetChannelForPixel(x, y, 3);
|
||||
if(alphaVal == INT_MAX)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Red channel
|
||||
m_PixelData[byteIdx++] = redVal & 0xFF;
|
||||
|
||||
// Green channel
|
||||
m_PixelData[byteIdx++] = greenVal & 0xFF;
|
||||
|
||||
// Blue channel
|
||||
m_PixelData[byteIdx++] = blueVal & 0xFF;
|
||||
|
||||
// Alpha channel
|
||||
m_PixelData[byteIdx++] = alphaVal & 0xFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
Loading…
Reference in New Issue
Block a user