summaryrefslogtreecommitdiff
path: root/DevIL/src-IL/src/il_rle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'DevIL/src-IL/src/il_rle.cpp')
-rw-r--r--DevIL/src-IL/src/il_rle.cpp153
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;
+}