changeset 1660:7555c8803529

More work on improving the generic RLE decoder/encoder.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 30 May 2018 17:05:19 +0300
parents 99b8ab61dc1b
children dc3fbd130db7
files tools/lib64fmts.c tools/lib64gfx.c tools/lib64gfx.h
diffstat 3 files changed, 91 insertions(+), 52 deletions(-) [+]
line wrap: on
line diff
--- a/tools/lib64fmts.c	Wed May 30 14:45:14 2018 +0300
+++ b/tools/lib64fmts.c	Wed May 30 17:05:19 2018 +0300
@@ -52,8 +52,8 @@
     DMCompParams cfg;
 
     cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_2;
-    cfg.rleMarker1  = 0xfe;
+    cfg.flags       = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_2;
+    cfg.rleMarkerB  = 0xfe;
     if ((res = dmDecodeGenericRLEAlloc(&mem, buf, buf + len, &cfg)) != DMERR_OK)
         goto out;
 
@@ -76,11 +76,11 @@
         goto out;
 
     // And now RLE compress the data to the existing buffer
-    cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_2;
-    cfg.rleMarker1  = 0xfe;
-    cfg.rleMinCount = 3;
-    cfg.rleMaxCount = 255;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_2;
+    cfg.rleMarkerB   = 0xfe;
+    cfg.rleMinCountB = 3;
+    cfg.rleMaxCountB = 255;
     res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg);
 
 out:
@@ -113,8 +113,8 @@
     DMCompParams cfg;
 
     cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMarker1  = buf[0x0d];
+    cfg.flags       = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMarkerB  = buf[0x0d];
 
     if ((res = dmDecodeGenericRLEAlloc(&mem, buf + 0x0e, buf + len, &cfg)) != DMERR_OK)
         goto out;
@@ -140,14 +140,14 @@
 
     // Analyze and setup RLE
     dmGenericRLEAnalyze(tmp.data, tmp.len, &cfg);
-    cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMinCount = 3;
-    cfg.rleMaxCount = 255;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMinCountB = 3;
+    cfg.rleMaxCountB = 255;
 
     // Add the header bits
     if (!dmGrowBufPut(buf, magicID, strlen(magicID)) ||
-        !dmGrowBufPutU8(buf, cfg.rleMarker1))
+        !dmGrowBufPutU8(buf, cfg.rleMarkerB))
     {
         res = DMERR_MALLOC;
         goto out;
@@ -212,9 +212,9 @@
     DMCompParams cfg;
 
     cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_16BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMarker1  = buf[8];
-    cfg.rleMarker2  = buf[9];
+    cfg.flags       = DM_RLE_BYTE_RUNS | DM_RLE_WORD_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMarkerB  = buf[8];
+    cfg.rleMarkerW  = buf[9];
 
     if ((res = dmDecodeGenericRLEAlloc(&mem, buf + 10, buf + len, &cfg)) != DMERR_OK)
         goto out;
@@ -280,8 +280,8 @@
 
     // Now do an RLE decode on the enlarged buffer
     cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMarker1  = 0xC2;
+    cfg.flags       = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMarkerB  = 0xC2;
 
     if ((res = dmDecodeGenericRLEAlloc(&mem, tmp.data, tmp.data + tmp.len, &cfg)) != DMERR_OK)
         goto out;
@@ -307,11 +307,11 @@
         goto out;
 
     // And now RLE compress the data to the existing buffer
-    cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMarker1  = 0xC2;
-    cfg.rleMinCount = 3;
-    cfg.rleMaxCount = 255;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMarkerB   = 0xC2;
+    cfg.rleMinCountB = 3;
+    cfg.rleMaxCountB = 255;
 
     res = dmEncodeGenericRLE(buf, tmp.data, tmp.data + tmp.len, &cfg);
 
@@ -548,8 +548,8 @@
         DMCompParams cfg;
 
         cfg.type        = DM_COMP_RLE_MARKER;
-        cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-        cfg.rleMarker1  = buf[15];
+        cfg.flags       = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+        cfg.rleMarkerB  = buf[15];
 
         if ((res = dmDecodeGenericRLEAlloc(
             &mem, buf + FUNPAINT2_HEADER_SIZE, buf + len, &cfg)) == DMERR_OK)
@@ -589,14 +589,14 @@
 
     // Analyze and setup RLE
     dmGenericRLEAnalyze(tmp.data, tmp.len, &cfg);
-    cfg.type        = DM_COMP_RLE_MARKER;
-    cfg.flags       = DM_RLE_8BIT_RUNS | DM_RLE_ORDER_1;
-    cfg.rleMinCount = 3;
-    cfg.rleMaxCount = 255;
+    cfg.type         = DM_COMP_RLE_MARKER;
+    cfg.flags        = DM_RLE_BYTE_RUNS | DM_RLE_ORDER_1;
+    cfg.rleMinCountB = 3;
+    cfg.rleMaxCountB = 255;
 
     // Add the header bits
     if (!dmGrowBufPut(buf, fmtFunPaint2MagicID, strlen(fmtFunPaint2MagicID)) ||
-        !dmGrowBufPutU8(buf, cfg.rleMarker1))
+        !dmGrowBufPutU8(buf, cfg.rleMarkerB))
     {
         res = DMERR_MALLOC;
         goto out;
--- a/tools/lib64gfx.c	Wed May 30 14:45:14 2018 +0300
+++ b/tools/lib64gfx.c	Wed May 30 17:05:19 2018 +0300
@@ -308,19 +308,18 @@
                 {
                     if (stats[n] < smallest)
                     {
-                        selected = n;
+                        cfg->rleMarkerW = selected;
+                        cfg->rleMarkerB = selected = n;
                         smallest = stats[n];
                     }
                 }
-
-                cfg->rleMarker1 = selected;
             }
             break;
 
         case DM_COMP_RLE_MASK:
-            cfg->rleMarker1 = 0xC0;
-            cfg->rleMask1   = 0xC0;
-            cfg->rleMask2   = 0x3f;
+            cfg->rleMarkerMask = 0xC0;
+            cfg->rleMarkerBits = 0xC0;
+            cfg->rleCountMask  = 0x3f;
             break;
     }
 
@@ -341,7 +340,7 @@
         if (cfg->type == DM_COMP_RLE_MARKER)
         {
             // A simple marker byte RLE variant: [Marker] [count] [data]
-            if (data == cfg->rleMarker1 && (cfg->flags & DM_RLE_8BIT_RUNS))
+            if (data == cfg->rleMarkerB && (cfg->flags & DM_RLE_BYTE_RUNS))
             {
                 if (srcEnd - src + 1 < 2)
                 {
@@ -364,7 +363,7 @@
                 src += 2;
             }
             else
-            if (data == cfg->rleMarker2 && (cfg->flags & DM_RLE_16BIT_RUNS))
+            if (data == cfg->rleMarkerW && (cfg->flags & DM_RLE_WORD_RUNS))
             {
                 if (srcEnd - src + 1 < 3)
                 {
@@ -392,7 +391,7 @@
         {
             // Mask marker RLE: usually high bit(s) of byte mark RLE sequence
             // and the lower bits contain the count: [Mask + count] [data]
-            if ((data & cfg->rleMask1) == cfg->rleMarker1)
+            if ((data & cfg->rleMarkerMask) == cfg->rleMarkerBits)
             {
                 if (srcEnd - src + 1 < 1)
                 {
@@ -400,7 +399,7 @@
                     goto err;
                 }
 
-                count = data & cfg->rleMask2;
+                count = data & cfg->rleCountMask;
                 data = *src++;
             }
         }
@@ -432,17 +431,41 @@
 }
 
 
-static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, Uint8 count, const DMCompParams *cfg)
+static BOOL dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, int count, const DMCompParams *cfg)
 {
     BOOL copyOnly = FALSE;
 
     switch (cfg->type)
     {
         case DM_COMP_RLE_MARKER:
-            if (count >= cfg->rleMinCount || data == cfg->rleMarker1)
+            if ((cfg->flags & DM_RLE_WORD_RUNS) &&
+                (count >= cfg->rleMinCountW || data == cfg->rleMarkerW))
             {
                 // A simple marker byte RLE variant: [Marker] [count] [data]
-                if (!dmGrowBufPutU8(dst, cfg->rleMarker1))
+                if (!dmGrowBufPutU8(dst, cfg->rleMarkerW))
+                    return FALSE;
+
+                switch (cfg->flags & DM_RLE_ORDER_MASK)
+                {
+                    case DM_RLE_ORDER_1:
+                        if (!dmGrowBufPutU16LE(dst, count) ||
+                            !dmGrowBufPutU8(dst, data))
+                            return FALSE;
+                        break;
+
+                    case DM_RLE_ORDER_2:
+                        if (!dmGrowBufPutU8(dst, data) ||
+                            !dmGrowBufPutU16LE(dst, count))
+                            return FALSE;
+                        break;
+                }
+            }
+            else
+            if ((cfg->flags & DM_RLE_BYTE_RUNS) &&
+                (count >= cfg->rleMinCountB || data == cfg->rleMarkerB))
+            {
+                // A simple marker byte RLE variant: [Marker] [count] [data]
+                if (!dmGrowBufPutU8(dst, cfg->rleMarkerB))
                     return FALSE;
 
                 switch (cfg->flags & DM_RLE_ORDER_MASK)
@@ -465,11 +488,11 @@
             break;
 
         case DM_COMP_RLE_MASK:
-            if (count >= cfg->rleMinCount || (data & cfg->rleMask1) == cfg->rleMarker1)
+            if (count >= cfg->rleMinCountB || (data & cfg->rleMarkerMask) == cfg->rleMarkerBits)
             {
                 // Mask marker RLE: usually high bit(s) of byte mark RLE sequence
                 // and the lower bits contain the count: [Mask + count] [data]
-                if (!dmGrowBufPutU8(dst, cfg->rleMarker1 | count) ||
+                if (!dmGrowBufPutU8(dst, cfg->rleMarkerBits | count) ||
                     !dmGrowBufPutU8(dst, data))
                     return FALSE;
             }
@@ -499,7 +522,11 @@
     {
         Uint8 data = *src++;
 
-        if (data != prev || count >= cfg->rleMaxCount)
+        // If new data byte is different, or we exceed the rleMaxCount
+        // for the active runs mode(s) .. then encode the run.
+        if (data != prev ||
+            ((cfg->flags & DM_RLE_WORD_RUNS) && count >= cfg->rleMaxCountW) ||
+            (((cfg->flags & DM_RLE_RUNS_MASK) == DM_RLE_BYTE_RUNS) && count >= cfg->rleMaxCountB))
         {
             if (!dmEncodeGenericRLESequence(dst, prev, count, cfg))
                 goto err;
--- a/tools/lib64gfx.h	Wed May 30 14:45:14 2018 +0300
+++ b/tools/lib64gfx.h	Wed May 30 17:05:19 2018 +0300
@@ -214,8 +214,8 @@
 
 enum
 {
-    DM_RLE_8BIT_RUNS        = 0x0001, // Uses one-byte runs
-    DM_RLE_16BIT_RUNS       = 0x0002, // Uses two-byte runs
+    DM_RLE_BYTE_RUNS        = 0x0001, // Uses one-byte run lengths
+    DM_RLE_WORD_RUNS        = 0x0002, // Uses two-byte (word) run lengths
     DM_RLE_RUNS_MASK        = 0x000f,
 
     DM_RLE_ORDER_1          = 0x0000, // Order: <marker>, <count/run length>, <data>
@@ -229,9 +229,21 @@
     int type;
     int flags;
     Uint8
-        rleMarker1, rleMarker2,
-        rleMask1, rleMask2,
-        rleMinCount, rleMaxCount;
+        // DM_COMP_RLE_MARKER mode
+        rleMarkerB,          // Marker byte for byte length runs (if DM_RLE_BYTE_RUNS used)
+        rleMarkerW,          // Marker byte for word length runs (if DM_RLE_WORD_RUNS used)
+
+        // DM_COMP_RLE_MASK mode
+        rleMarkerBits,
+        rleMarkerMask,       // Mask bits for marker: data & rleMarkerMask == rleMarkerBits
+        rleCountMask;        // Mask bits for length: count = data & rleCountMask
+
+    int
+        // Minimum and maximum run lengths
+        rleMinCountB,
+        rleMinCountW,
+        rleMaxCountB,
+        rleMaxCountW;
 } DMCompParams;