mirror of
https://github.com/yuzu-emu/FasTC.git
synced 2024-12-02 20:44:21 +01:00
Fleshed out some more of the library
This commit is contained in:
parent
39d7f2c942
commit
a076d1efb8
@ -3,3 +3,4 @@ PROJECT(TexC)
|
|||||||
|
|
||||||
ADD_SUBDIRECTORY(BPTCEncoder)
|
ADD_SUBDIRECTORY(BPTCEncoder)
|
||||||
ADD_SUBDIRECTORY(IO)
|
ADD_SUBDIRECTORY(IO)
|
||||||
|
ADD_SUBDIRECTORY(Core)
|
||||||
|
@ -1,15 +1,21 @@
|
|||||||
|
|
||||||
SET( SOURCES
|
SET( SOURCES
|
||||||
"src/TexComp.cpp"
|
"src/TexComp.cpp"
|
||||||
|
"src/CompressedImage.cpp"
|
||||||
)
|
)
|
||||||
|
|
||||||
SET( HEADERS
|
SET( HEADERS
|
||||||
"include/TexComp.h"
|
"include/TexComp.h"
|
||||||
|
"include/CompressedImage.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
INCLUDE_DIRECTORIES( ${TexC_BINARY_DIR}/IO/include )
|
||||||
|
INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/IO/include )
|
||||||
INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include )
|
INCLUDE_DIRECTORIES( ${TexC_SOURCE_DIR}/Core/include )
|
||||||
|
|
||||||
ADD_LIBRARY( TexCompCore
|
ADD_LIBRARY( TexCompCore
|
||||||
${HEADERS}
|
${HEADERS}
|
||||||
${SOURCES}
|
${SOURCES}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
TARGET_LINK_LIBRARIES( TexCompCore TexCompIO )
|
||||||
|
34
Core/include/CompressedImage.h
Normal file
34
Core/include/CompressedImage.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef _COMPRESSED_IMAGE_H_
|
||||||
|
#define _COMPRESSED_IMAGE_H_
|
||||||
|
|
||||||
|
enum ECompressionFormat {
|
||||||
|
eCompressionFormat_DXT1,
|
||||||
|
eCompressionFormat_DXT5,
|
||||||
|
eCompressionFormat_BPTC,
|
||||||
|
|
||||||
|
kNumCompressionFormats
|
||||||
|
};
|
||||||
|
|
||||||
|
class CompressedImage {
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char *m_Data;
|
||||||
|
unsigned int m_DataSz;
|
||||||
|
unsigned int m_Width;
|
||||||
|
unsigned int m_Height;
|
||||||
|
ECompressionFormat m_Format;
|
||||||
|
|
||||||
|
void InitData(const unsigned char *withData);
|
||||||
|
public:
|
||||||
|
CompressedImage(
|
||||||
|
const unsigned int width,
|
||||||
|
const unsigned int height,
|
||||||
|
const ECompressionFormat format,
|
||||||
|
const unsigned char *data
|
||||||
|
);
|
||||||
|
|
||||||
|
CompressedImage( const CompressedImage &other );
|
||||||
|
~CompressedImage();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _COMPRESSED_IMAGE_H_
|
@ -1,4 +1,27 @@
|
|||||||
#ifndef _TEX_COMP_H_
|
#ifndef _TEX_COMP_H_
|
||||||
#define _TEX_COMP_H_
|
#define _TEX_COMP_H_
|
||||||
|
|
||||||
|
#include "ImageFile.h"
|
||||||
|
#include "CompressedImage.h"
|
||||||
|
|
||||||
|
struct SCompressionSettings {
|
||||||
|
SCompressionSettings(); // defaults
|
||||||
|
ECompressionFormat format;
|
||||||
|
bool bUseSIMD;
|
||||||
|
int iNumThreads;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void CompressImage(
|
||||||
|
const ImageFile &,
|
||||||
|
CompressedImage &,
|
||||||
|
const SCompressionSettings &settings
|
||||||
|
);
|
||||||
|
|
||||||
|
typedef void (* CompressionFunc)(
|
||||||
|
const unsigned char *inData,
|
||||||
|
unsigned char *outData,
|
||||||
|
unsigned int width,
|
||||||
|
unsigned int height
|
||||||
|
);
|
||||||
|
|
||||||
#endif //_TEX_COMP_H_
|
#endif //_TEX_COMP_H_
|
||||||
|
50
Core/src/CompressedImage.cpp
Normal file
50
Core/src/CompressedImage.cpp
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#include "CompressedImage.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
CompressedImage::CompressedImage( const CompressedImage &other )
|
||||||
|
: m_Width(other.m_Width)
|
||||||
|
, m_Height(other.m_Height)
|
||||||
|
, m_Format(other.m_Format)
|
||||||
|
, m_Data(0)
|
||||||
|
{
|
||||||
|
InitData(other.m_Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressedImage::CompressedImage(
|
||||||
|
const unsigned int width,
|
||||||
|
const unsigned int height,
|
||||||
|
const ECompressionFormat format,
|
||||||
|
const unsigned char *data
|
||||||
|
)
|
||||||
|
: m_Width(width)
|
||||||
|
, m_Height(height)
|
||||||
|
, m_Format(format)
|
||||||
|
, m_Data(0)
|
||||||
|
{
|
||||||
|
InitData(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressedImage::InitData(const unsigned char *withData) {
|
||||||
|
unsigned int dataSz = 0;
|
||||||
|
int uncompDataSz = m_Width * m_Height * 4;
|
||||||
|
|
||||||
|
switch(m_Format) {
|
||||||
|
case eCompressionFormat_DXT1: dataSz = uncompDataSz / 8; break;
|
||||||
|
case eCompressionFormat_DXT5: dataSz = uncompDataSz / 4; break;
|
||||||
|
case eCompressionFormat_BPTC: dataSz = uncompDataSz / 4; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(dataSz > 0) {
|
||||||
|
m_Data = new unsigned char[dataSz];
|
||||||
|
memcpy(m_Data, withData, dataSz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CompressedImage::~CompressedImage() {
|
||||||
|
if(m_Data) {
|
||||||
|
delete [] m_Data;
|
||||||
|
m_Data = NULL;
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,55 @@
|
|||||||
#include "TexComp.h"
|
#include "TexComp.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
SCompressionSettings:: SCompressionSettings()
|
||||||
|
: format(eCompressionFormat_BPTC)
|
||||||
|
, bUseSIMD(false)
|
||||||
|
, iNumThreads(1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
static CompressionFunc ChooseFuncFromSettings(const SCompressionSettings &s) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReportError(const char *msg) {
|
||||||
|
fprintf(stderr, "TexComp -- %s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompressImage(
|
||||||
|
const ImageFile &img,
|
||||||
|
CompressedImage &outImg,
|
||||||
|
const SCompressionSettings &settings
|
||||||
|
) {
|
||||||
|
|
||||||
|
const unsigned int dataSz = img.GetWidth() * img.GetHeight() * 4;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cmpDataSz == 0) {
|
||||||
|
ReportError("Unknown compression format");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *cmpData = new unsigned char[cmpDataSz];
|
||||||
|
|
||||||
|
CompressionFunc f = ChooseFuncFromSettings(settings);
|
||||||
|
if(f) {
|
||||||
|
(*f)(img.GetPixels(), cmpData, img.GetWidth(), img.GetHeight());
|
||||||
|
outImg = CompressedImage(img.GetWidth(), img.GetHeight(), settings.format, cmpData);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ReportError("Could not find adequate compression function for specified settings");
|
||||||
|
// return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
delete [] cmpData;
|
||||||
|
}
|
||||||
|
@ -12,7 +12,6 @@ FIND_PACKAGE( PNG )
|
|||||||
IF( PNG_FOUND )
|
IF( PNG_FOUND )
|
||||||
INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
|
INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
|
||||||
|
|
||||||
|
|
||||||
SET( SOURCES ${SOURCES} "src/ImageLoaderPNG.cpp" )
|
SET( SOURCES ${SOURCES} "src/ImageLoaderPNG.cpp" )
|
||||||
SET( HEADERS ${HEADERS} "src/ImageLoaderPNG.h" )
|
SET( HEADERS ${HEADERS} "src/ImageLoaderPNG.h" )
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
@ -62,16 +62,19 @@ class ImageLoader {
|
|||||||
virtual bool ReadData() = 0;
|
virtual bool ReadData() = 0;
|
||||||
|
|
||||||
int GetRedChannelPrecision() const { return m_RedChannelPrecision; }
|
int GetRedChannelPrecision() const { return m_RedChannelPrecision; }
|
||||||
unsigned char * GetRedPixelData() const { return m_RedData; }
|
const unsigned char * GetRedPixelData() const { return m_RedData; }
|
||||||
|
|
||||||
int GetGreenChannelPrecision() const { return m_GreenChannelPrecision; }
|
int GetGreenChannelPrecision() const { return m_GreenChannelPrecision; }
|
||||||
unsigned char * GetGreenPixelData() const { return m_GreenData; }
|
const unsigned char * GetGreenPixelData() const { return m_GreenData; }
|
||||||
|
|
||||||
int GetBlueChannelPrecision() const { return m_BlueChannelPrecision; }
|
int GetBlueChannelPrecision() const { return m_BlueChannelPrecision; }
|
||||||
unsigned char * GetBluePixelData() const { return m_BlueData; }
|
const unsigned char * GetBluePixelData() const { return m_BlueData; }
|
||||||
|
|
||||||
int GetAlphaChannelPrecision() const { return m_AlphaChannelPrecision; }
|
int GetAlphaChannelPrecision() const { return m_AlphaChannelPrecision; }
|
||||||
unsigned char * GetAlphaPixelData() const { return m_AlphaData; }
|
const unsigned char * GetAlphaPixelData() const { return m_AlphaData; }
|
||||||
|
|
||||||
|
int GetWidth() const { return m_Width; }
|
||||||
|
int GetHeight() const { return m_Height; }
|
||||||
};
|
};
|
||||||
|
|
||||||
#cmakedefine PNG_FOUND
|
#cmakedefine PNG_FOUND
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <limits.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
#include "ImageFile.h"
|
#include "ImageFile.h"
|
||||||
@ -9,6 +10,101 @@
|
|||||||
# include "ImageLoaderPNG.h"
|
# include "ImageLoaderPNG.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Static helper functions
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
static inline void ReportError(const char *msg) {
|
||||||
|
fprintf(stderr, "ImageFile -- %s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static inline T abs(const T &a) {
|
||||||
|
return a > 0? a : -a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
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) :
|
ImageFile::ImageFile(const char *filename) :
|
||||||
m_PixelData(0),
|
m_PixelData(0),
|
||||||
m_FileFormat( DetectFileFormat(filename) )
|
m_FileFormat( DetectFileFormat(filename) )
|
||||||
@ -80,7 +176,77 @@ bool ImageFile::LoadImage(const unsigned char *rawImageData) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
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
|
#ifdef _MSC_VER
|
||||||
|
Loading…
Reference in New Issue
Block a user