diff --git a/CLTool/src/clunix.cpp b/CLTool/src/clunix.cpp index 7a5a0e6..2328ded 100644 --- a/CLTool/src/clunix.cpp +++ b/CLTool/src/clunix.cpp @@ -4,6 +4,7 @@ #include "TexComp.h" #include "ImageFile.h" +#include "Image.h" void PrintUsage() { fprintf(stderr, "Usage: tc [-s|-t ] \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); } diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 3464eb8..a814763 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -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... diff --git a/Core/include/Image.h b/Core/include/Image.h new file mode 100644 index 0000000..8aaaef3 --- /dev/null +++ b/Core/include/Image.h @@ -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__ diff --git a/Core/src/Image.cpp b/Core/src/Image.cpp new file mode 100644 index 0000000..27c2382 --- /dev/null +++ b/Core/src/Image.cpp @@ -0,0 +1,94 @@ +#include "Image.h" +#include "ImageLoader.h" + +#include +#include +#include +#include +#include + +template +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; +} diff --git a/Core/src/TexComp.cpp b/Core/src/TexComp.cpp index d3e6cdb..41bdaea 100644 --- a/Core/src/TexComp.cpp +++ b/Core/src/TexComp.cpp @@ -1,13 +1,15 @@ -#include "BC7Compressor.h" #include "TexComp.h" -#include "ThreadGroup.h" -#include "ImageFile.h" #include #include #include #include +#include "BC7Compressor.h" +#include "ThreadGroup.h" +#include "ImageFile.h" +#include "Image.h" + template 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; - -} diff --git a/IO/CMakeLists.txt b/IO/CMakeLists.txt index 35ee590..17063af 100644 --- a/IO/CMakeLists.txt +++ b/IO/CMakeLists.txt @@ -1,6 +1,7 @@ SET( SOURCES "src/ImageFile.cpp" + "src/ImageLoader.cpp" ) SET( HEADERS diff --git a/IO/config/ImageLoader.h.in b/IO/config/ImageLoader.h.in index ed0fe3d..fdc4402 100644 --- a/IO/config/ImageLoader.h.in +++ b/IO/config/ImageLoader.h.in @@ -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 diff --git a/IO/include/ImageFile.h b/IO/include/ImageFile.h index 26641c1..1aea2c1 100644 --- a/IO/include/ImageFile.h +++ b/IO/include/ImageFile.h @@ -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_ diff --git a/IO/src/ImageFile.cpp b/IO/src/ImageFile.cpp index 82034fa..087a842 100644 --- a/IO/src/ImageFile.cpp +++ b/IO/src/ImageFile.cpp @@ -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; +ImageFile::~ImageFile() { + 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; -} - diff --git a/IO/src/ImageLoader.cpp b/IO/src/ImageLoader.cpp new file mode 100644 index 0000000..d1050e5 --- /dev/null +++ b/IO/src/ImageLoader.cpp @@ -0,0 +1,174 @@ +#include "ImageLoader.h" + +#include +#include +#include +#include + +template +static inline T min(const T &a, const T &b) { + return (a > b)? b : a; +} + +template +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; +}