aboutsummaryrefslogtreecommitdiffstats
path: root/liblss16_encode_from_colour_index.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_encode_from_colour_index.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_encode_from_colour_index.c')
-rw-r--r--liblss16_encode_from_colour_index.c177
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;
+}