mirror of
				https://github.com/yuzu-emu/FasTC.git
				synced 2025-11-04 05:44:52 +00: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(IO)
 | 
			
		||||
ADD_SUBDIRECTORY(Core)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,15 +1,21 @@
 | 
			
		|||
 | 
			
		||||
SET( SOURCES
 | 
			
		||||
	"src/TexComp.cpp"
 | 
			
		||||
	"src/CompressedImage.cpp"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
SET( HEADERS
 | 
			
		||||
	"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 )
 | 
			
		||||
 | 
			
		||||
ADD_LIBRARY( TexCompCore
 | 
			
		||||
	${HEADERS}
 | 
			
		||||
	${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_
 | 
			
		||||
#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_
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										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 <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 )
 | 
			
		||||
	INCLUDE_DIRECTORIES( ${PNG_INCLUDE_DIR} )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	SET( SOURCES ${SOURCES} "src/ImageLoaderPNG.cpp" )
 | 
			
		||||
	SET( HEADERS ${HEADERS} "src/ImageLoaderPNG.h" )
 | 
			
		||||
ENDIF()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -62,16 +62,19 @@ class ImageLoader {
 | 
			
		|||
  virtual bool ReadData() = 0;
 | 
			
		||||
 | 
			
		||||
  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; }
 | 
			
		||||
  unsigned char * GetGreenPixelData() const { return m_GreenData; }
 | 
			
		||||
  const unsigned char * GetGreenPixelData() const { return m_GreenData; }
 | 
			
		||||
 | 
			
		||||
  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; }
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
 | 
			
		||||
#include "ImageFile.h"
 | 
			
		||||
| 
						 | 
				
			
			@ -9,6 +10,101 @@
 | 
			
		|||
#  include "ImageLoaderPNG.h"
 | 
			
		||||
#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) : 
 | 
			
		||||
  m_PixelData(0),
 | 
			
		||||
  m_FileFormat(  DetectFileFormat(filename) )
 | 
			
		||||
| 
						 | 
				
			
			@ -80,7 +176,77 @@ bool ImageFile::LoadImage(const unsigned char *rawImageData) {
 | 
			
		|||
      break;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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;
 | 
			
		||||
 | 
			
		||||
  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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue