aboutsummaryrefslogtreecommitdiffstats
path: root/liblss16_optimise.c
diff options
context:
space:
mode:
authorMattias Andrée <m@maandree.se>2025-03-02 22:18:45 +0100
committerMattias Andrée <m@maandree.se>2025-03-02 22:18:45 +0100
commitfd54698d12d468420d344f0ff4d5e502e04d64d4 (patch)
tree62fbc4488e3374b27dddffe00de665894e7eec41 /liblss16_optimise.c
parentFirst commit (diff)
downloadliblss16-fd54698d12d468420d344f0ff4d5e502e04d64d4.tar.gz
liblss16-fd54698d12d468420d344f0ff4d5e502e04d64d4.tar.bz2
liblss16-fd54698d12d468420d344f0ff4d5e502e04d64d4.tar.xz
Add some functions needed fore encoding LSS16 files
Signed-off-by: Mattias Andrée <m@maandree.se>
Diffstat (limited to 'liblss16_optimise.c')
-rw-r--r--liblss16_optimise.c80
1 files changed, 80 insertions, 0 deletions
diff --git a/liblss16_optimise.c b/liblss16_optimise.c
new file mode 100644
index 0000000..911fcd2
--- /dev/null
+++ b/liblss16_optimise.c
@@ -0,0 +1,80 @@
+/* See LICENSE file for copyright and license details. */
+#include "liblss16.h"
+#include <string.h>
+
+
+void
+liblss16_optimise(struct liblss16_header *header, uint8_t *pixels)
+{
+ uint8_t remap[16], unmap[16], ncolours, colour, preferred;
+ unsigned x, y, count, width;
+ size_t p, n;
+ int32_t zero[16], nonzero[16];
+ int32_t zero_penalty, least;
+
+ for (x = 0; x < 16U; x++) {
+ remap[x] = (uint8_t)x;
+ unmap[x] = 0;
+ }
+
+ memset(zero, 0, sizeof(zero));
+ memset(nonzero, 0, sizeof(nonzero));
+
+ for (x = 0; x < 15U; x++) {
+ if (unmap[x])
+ continue;
+ header->colour_map[ncolours++] = header->colour_map[x];
+ for (y = x + 1U; y < 16U; y++) {
+ if (header->colour_map[y].r != header->colour_map[x].r ||
+ header->colour_map[y].g != header->colour_map[x].g ||
+ header->colour_map[y].b != header->colour_map[x].b)
+ continue;
+ unmap[y] = 1;
+ remap[y] = ncolours;
+ }
+ }
+
+ width = (unsigned)header->width;
+ width = width < 17U ? width : 17U;
+ for (y = 0, p = 0; y < (unsigned)header->height; y++) {
+ colour = remap[pixels[p]];
+ count = 1U;
+ for (x = 1U; x < width; x++, p++) {
+ if (remap[pixels[p]] != colour)
+ break;
+ count += 1U;
+ }
+ p += (size_t)header->width - (size_t)x;
+ zero[colour] += count < 16U ? 2 : 3;
+ nonzero[colour] += count == 1 ? 1 : count < 17 ? 3 : 4;
+ }
+
+ least = zero[0] - nonzero[0];
+ preferred = 0U;
+ for (x = 1U; x < (unsigned)ncolours; x++) {
+ zero_penalty = zero[x] - nonzero[x];
+ if (zero_penalty < least) {
+ least = zero_penalty;
+ preferred = (uint8_t)x;
+ }
+ }
+
+ if (preferred) {
+ struct liblss16_colour tc;
+ uint8_t t8;
+ tc = header->colour_map[preferred];
+ header->colour_map[preferred] = header->colour_map[0];
+ header->colour_map[0] = tc;
+ t8 = remap[preferred];
+ remap[preferred] = remap[0];
+ remap[0] = t8;
+ }
+
+ n = p;
+ for (n = p, p = 0; p < n; p++)
+ pixels[p] = remap[pixels[p]];
+
+ memset(&header->colour_map[ncolours],
+ header->colour_map[ncolours - 1U].b,
+ (16U - ncolours) * sizeof(*header->colour_map));
+}