mirror of
https://github.com/love2d/love-android.git
synced 2026-08-16 16:21:33 +02:00
154 lines
3.7 KiB
C
154 lines
3.7 KiB
C
//-----------------------------------------------------------------------------
|
|
// 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;
|
|
}
|