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_encode_from_colour_index.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_encode_from_colour_index.c')
-rw-r--r-- | liblss16_encode_from_colour_index.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/liblss16_encode_from_colour_index.c b/liblss16_encode_from_colour_index.c new file mode 100644 index 0000000..1efff36 --- /dev/null +++ b/liblss16_encode_from_colour_index.c @@ -0,0 +1,177 @@ +/* See LICENSE file for copyright and license details. */ +#include "liblss16.h" +#include <string.h> +#include <stdlib.h> + + +static size_t +flush_buffer(struct liblss16_encoder *encoder, uint8_t *buffer, size_t size) +{ + size_t i; + for (i = 0; size && encoder->nbuffered - i > 1U; i += 2U, size--) + buffer[i] = (uint8_t)(encoder->buffered[i + 0] | (encoder->buffered[i + 1] << 4)); + memmove(&encoder->buffered[0], &encoder->buffered[i], encoder->nbuffered - i); + return i; +} + + +enum liblss16_encode_state +liblss16_encode_from_colour_index(struct liblss16_encoder *encoder, void *buffer_, size_t size, + size_t *written_out, const uint8_t *pixels, size_t npixels, + size_t *nconsumed_out, enum liblss16_encode_error *error_out) +{ + uint8_t *buffer = buffer_; + size_t n; + + *written_out = 0; + *nconsumed_out = 0; + + switch (encoder->header_position) { + case 0: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)0x3DU; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 1: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)0xF3U; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 2: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)0x13U; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 3: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)0x14U; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 4: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)encoder->header.width; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 5: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)(encoder->header.width >> 8); + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 6: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)encoder->header.height; + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + case 7: + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = (uint8_t)(encoder->header.height >> 8); + ++*nconsumed_out; + encoder->header_position++; + /* fall through */ + + default: + break; + } + + while (encoder->header_position < 8U + 16U * 3U) { + if (!size--) + return LIBLSS16_ENCODE_RUNNING; + *buffer++ = ((const uint8_t *)encoder->header.colour_map)[encoder->header_position++]; + ++*nconsumed_out; + encoder->header_position++; + } + + if (encoder->nbuffered > 1U) { + n = flush_buffer(encoder, buffer, size); + buffer = &buffer[n]; + size -= n; + *written_out += n; + if (encoder->nbuffered > 1U) + return LIBLSS16_ENCODE_RUNNING; + if (!encoder->y_rem) { + if (encoder->nbuffered) + abort(); + return LIBLSS16_ENCODE_DONE; + } + } + + while (npixels--) { + if (*pixels == encoder->previous) { + encoder->repetition++; + } else if (*pixels > 15U) { + if (error_out) + *error_out = LIBLSS16_ENCODE_BAD_COLOUR_INDEX; + return LIBLSS16_ENCODE_ERROR; + } else { + if (!encoder->repetition) { + /* do nothing */ + } else if (encoder->repetition < 16U) { + encoder->buffered[encoder->nbuffered++] = encoder->previous; + encoder->buffered[encoder->nbuffered++] = (uint8_t)encoder->repetition; + } else { + unsigned value = encoder->repetition - 16U; + encoder->buffered[encoder->nbuffered++] = encoder->previous; + encoder->buffered[encoder->nbuffered++] = 0; + encoder->buffered[encoder->nbuffered++] = (uint8_t)(value & 15U); + encoder->buffered[encoder->nbuffered++] = (uint8_t)(value >> 4); + } + encoder->buffered[encoder->nbuffered++] = *pixels; + encoder->previous = *pixels; + encoder->repetition = 0; + + n = flush_buffer(encoder, buffer, size); + buffer = &buffer[n]; + size -= n; + *written_out += n; + if (encoder->nbuffered > 1U) + return LIBLSS16_ENCODE_RUNNING; + } + ++pixels; + ++*nconsumed_out; + + if (!--encoder->x_rem) { + encoder->previous = 0; + encoder->repetition = 0; + encoder->x_rem = encoder->header.width; + encoder->y_rem--; + if (encoder->nbuffered & 1) + encoder->buffered[encoder->nbuffered++] = 0; + + n = flush_buffer(encoder, buffer, size); + buffer = &buffer[n]; + size -= n; + *written_out += n; + if (encoder->nbuffered > 1U) + return LIBLSS16_ENCODE_RUNNING; + else if (encoder->nbuffered) + abort(); + + if (!encoder->y_rem) + return LIBLSS16_ENCODE_DONE; + } + } + + return LIBLSS16_ENCODE_RUNNING; +} |