diff options
Diffstat (limited to 'DevIL/src-IL/src/il_rle.cpp')
-rw-r--r-- | DevIL/src-IL/src/il_rle.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/DevIL/src-IL/src/il_rle.cpp b/DevIL/src-IL/src/il_rle.cpp new file mode 100644 index 00000000..5644f8e3 --- /dev/null +++ b/DevIL/src-IL/src/il_rle.cpp @@ -0,0 +1,153 @@ +//----------------------------------------------------------------------------- +// Description: Functions for run-length encoding +//----------------------------------------------------------------------------- + +// RLE code from TrueVision's TGA sample code available as Tgautils.zip at +// ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version + +#define IL_RLE_C + +#include "il_internal.h" +#include "il_rle.h" + +ILboolean ilRleCompressLine(ILubyte *p, ILuint n, ILubyte bpp, + ILubyte *q, ILuint *DestWidth, ILenum CompressMode) { + + ILint DiffCount; // pixel count until two identical + ILint SameCount; // number of identical adjacent pixels + ILint RLEBufSize = 0; // count of number of bytes encoded + ILint MaxRun; + const ILint bmp_pad_to_even = 1 - ((ILint)q - *DestWidth) % 2; + + switch( CompressMode ) { + case IL_TGACOMP: + MaxRun = TGA_MAX_RUN; + break; + case IL_SGICOMP: + MaxRun = SGI_MAX_RUN; + break; + case IL_BMPCOMP: + MaxRun = BMP_MAX_RUN; + break; + default: + ilSetError(IL_INVALID_PARAM); + return IL_FALSE; + } + + while( n > 0 ) { + // Analyze pixels + DiffCount = CountDiffPixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n); + SameCount = CountSamePixels(p, bpp, (ILint)n > MaxRun ? MaxRun : n); + + if( CompressMode == IL_BMPCOMP ) { + ILint remaining_data = n - DiffCount - SameCount; + if( remaining_data < 3 ) { // check if the run has gone near the end + // no absolute run can be done + // complete the line adding 0x01 + pixel, for each pixel + while( remaining_data > 0 ) { + *q++ = 0x01; + *q++ = *p++; + remaining_data--; + } + DiffCount = 0; + SameCount = 0; + n = 0; + } + } + + if( DiffCount > 0 ) { // create a raw packet (bmp absolute run) + switch(CompressMode) { + case IL_TGACOMP: + *q++ = (ILbyte)(DiffCount - 1); + break; + case IL_BMPCOMP: + *q++ = 0x00; RLEBufSize++; + *q++ = (ILbyte)DiffCount; + break; + case IL_SGICOMP: + *q++ = (ILbyte)(DiffCount | 0x80); + break; + } + n -= DiffCount; + RLEBufSize += (DiffCount * bpp) + 1; + + while( DiffCount > 0 ) { + switch(bpp) { + case 4: *q++ = *p++; + case 3: *q++ = *p++; + case 2: *q++ = *p++; + case 1: *q++ = *p++; + } + DiffCount--; + } + + if( CompressMode == IL_BMPCOMP ) { + if( (size_t)q % 2 == bmp_pad_to_even ) { + *q++ = 0x00; // insert padding + } + } + } + + if( SameCount > 1 ) { // create a RLE packet + switch(CompressMode) { + case IL_TGACOMP: + *q++ = (ILbyte)((SameCount - 1) | 0x80); + break; + case IL_SGICOMP: + case IL_BMPCOMP: + *q++ = (ILbyte)(SameCount); + break; + } + n -= SameCount; + RLEBufSize += bpp + 1; + p += (SameCount - 1) * bpp; + *q++ = *p++; + switch(bpp) { + case 4: *q++ = *p++; + case 3: *q++ = *p++; + case 2: *q++ = *p++; + case 1: *q++ = *p++; + } + } + } + + // write line termination code + switch(CompressMode) { + case IL_SGICOMP: + ++RLEBufSize; + *q++ = 0; + break; + case IL_BMPCOMP: + *q++ = 0x00; RLEBufSize++; + *q++ = 0x00; RLEBufSize++; + break; + } + *DestWidth = RLEBufSize; + + return IL_TRUE; +} + + +// Compresses an entire image using run-length encoding +ILuint ilRleCompress(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, + ILubyte *Dest, ILenum CompressMode, ILuint *ScanTable) { + ILuint DestW = 0, i, j, LineLen, Bps = Width * Bpp, SizeOfPlane = Width * Height * Bpp; + + if( ScanTable ) + imemclear(ScanTable,Depth*Height*sizeof(ILuint)); + for( j = 0; j < Depth; j++ ) { + for( i = 0; i < Height; i++ ) { + if( ScanTable ) + *ScanTable++ = DestW; + ilRleCompressLine(Data + j * SizeOfPlane + i * Bps, Width, Bpp, Dest + DestW, &LineLen, CompressMode); + DestW += LineLen; + } + } + + if( CompressMode == IL_BMPCOMP ) { // add end of image + *(Data+DestW) = 0x00; DestW++; + *(Data+DestW) = 0x01; DestW++; + } + + return DestW; +} |