diff options
author | Mattias Andrée <m@maandree.se> | 2025-03-02 22:18:45 +0100 |
---|---|---|
committer | Mattias Andrée <m@maandree.se> | 2025-03-02 22:18:45 +0100 |
commit | fd54698d12d468420d344f0ff4d5e502e04d64d4 (patch) | |
tree | 62fbc4488e3374b27dddffe00de665894e7eec41 /liblss16_optimise.c | |
parent | First commit (diff) | |
download | liblss16-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.c | 80 |
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)); +} |