image.c (18961B)
1 #include <stdint.h>
2 #include <stdlib.h>
3 #include <stdbool.h>
4 #include "display.h"
5 #include "fixed.h"
6
7 #define TAIF_FLAG_8BPP 0x01
8 #define TAIF_FLAG_TRANSPARENT 0x02
9 #define TAIF_FLAG_ANIMATED 0x04
10 #define TAIF_WINDOW_SIZE 4096
11
12 typedef struct {
13 uint8_t window[TAIF_WINDOW_SIZE];
14 uint32_t stream_position;
15 uint32_t window_position;
16 uint32_t filled;
17 uint32_t match_distance;
18 uint32_t match_remaining;
19 uint8_t item_flags;
20 uint8_t flags_remaining;
21 } ta_image_decoder;
22
23 typedef struct ta_image_cache {
24 const uint8_t *data;
25 uint32_t length;
26 uint32_t width;
27 uint32_t height;
28 uint32_t stride;
29 uint32_t frame_size;
30 uint16_t frame_count;
31 uint16_t palette_entries;
32 uint32_t frames_decoded;
33 uint8_t flags;
34 uint8_t palette[256][3];
35 const uint8_t *stream;
36 uint32_t stream_length;
37 ta_image_decoder decoder;
38 uint8_t *pixels;
39 uint8_t *scaled;
40 uint32_t scaled_width;
41 uint32_t scaled_height;
42 uint8_t scaled_bpp;
43 struct ta_image_cache *next;
44 } ta_image_cache;
45
46 static ta_image_cache *image_cache;
47
48 static uint16_t read_le16(const uint8_t *data) {
49 return (uint16_t)((uint16_t)data[0] | ((uint16_t)data[1] << 8));
50 }
51
52 static bool parse_image(const uint8_t *data, uint32_t length, ta_image_cache *image) {
53 if (data == 0 || length < 11 || data[0] != 'T' || data[1] != 'A' || data[2] != 'I' || data[3] != 'F' || data[4] != 1) {
54 return false;
55 }
56
57 uint8_t flags = data[5];
58 if ((flags & 0xf8) != 0) {
59 return false;
60 }
61
62 uint32_t width = read_le16(data + 6);
63 uint32_t height = read_le16(data + 8);
64 uint32_t palette_entries = (uint32_t)data[10] + 1;
65 bool eight_bpp = (flags & TAIF_FLAG_8BPP) != 0;
66 bool transparent = (flags & TAIF_FLAG_TRANSPARENT) != 0;
67 uint32_t max_entries = eight_bpp ? (transparent ? 255 : 256) : (transparent ? 15 : 16);
68 uint32_t header_size = 11;
69 uint16_t frame_count = 1;
70
71 if (width == 0 || height == 0 || palette_entries > max_entries) {
72 return false;
73 }
74
75 if ((flags & TAIF_FLAG_ANIMATED) != 0) {
76 if (length < 14 || data[11] == 0) {
77 return false;
78 }
79
80 frame_count = read_le16(data + 12);
81 if (frame_count < 2) {
82 return false;
83 }
84
85 header_size = 14;
86 }
87
88 uint64_t stride = eight_bpp ? width : (width + 1) / 2;
89 uint64_t frame_size = stride * height;
90 uint64_t max_size = (uint64_t)(size_t)-1;
91 uint64_t palette_size = (uint64_t)palette_entries * 3;
92
93 if (frame_size == 0 || frame_size > max_size || frame_size > 0xffffffffu || header_size + palette_size > length) {
94 return false;
95 }
96
97 const uint8_t *palette = data + header_size;
98
99 image->pixels = (uint8_t *)malloc((size_t)frame_size);
100 if (image->pixels == 0) {
101 return false;
102 }
103
104 for (uint32_t i = 0; i < (uint32_t)frame_size; i++) {
105 image->pixels[i] = 0;
106 }
107
108 image->data = data;
109 image->length = length;
110 image->width = width;
111 image->height = height;
112 image->stride = (uint32_t)stride;
113 image->frame_size = (uint32_t)frame_size;
114 image->frame_count = frame_count;
115 image->palette_entries = (uint16_t)palette_entries;
116 image->flags = flags;
117 image->stream = palette + palette_size;
118 image->stream_length = length - (uint32_t)(header_size + palette_size);
119
120 for (uint32_t i = 0; i < palette_entries; i++) {
121 for (uint32_t channel = 0; channel < 3; channel++) {
122 image->palette[i][channel] = palette[i * 3 + channel];
123 }
124 }
125
126 return true;
127 }
128
129 static void decoder_reset(ta_image_cache *image) {
130 ta_image_decoder *decoder = &image->decoder;
131
132 decoder->stream_position = 0;
133 decoder->window_position = 0;
134 decoder->filled = 0;
135 decoder->match_distance = 0;
136 decoder->match_remaining = 0;
137 decoder->item_flags = 0;
138 decoder->flags_remaining = 0;
139
140 for (uint32_t i = 0; i < image->frame_size; i++) {
141 image->pixels[i] = 0;
142 }
143
144 free(image->scaled);
145
146 image->scaled = 0;
147 image->frames_decoded = 0;
148 }
149
150 static bool decode_next_frame(ta_image_cache *image) {
151 ta_image_decoder *decoder = &image->decoder;
152 const uint8_t *stream = image->stream;
153 uint32_t stream_length = image->stream_length;
154 uint32_t frame_size = image->frame_size;
155 uint32_t position = 0;
156
157 while (position < frame_size) {
158 uint8_t value;
159
160 if (decoder->match_remaining != 0) {
161 uint32_t source_position = (decoder->window_position + TAIF_WINDOW_SIZE - decoder->match_distance) & (TAIF_WINDOW_SIZE - 1);
162
163 value = decoder->window[source_position];
164 decoder->match_remaining--;
165 } else {
166 if (decoder->flags_remaining == 0) {
167 if (decoder->stream_position >= stream_length) {
168 return false;
169 }
170
171 decoder->item_flags = stream[decoder->stream_position++];
172 decoder->flags_remaining = 8;
173 }
174
175 bool literal = (decoder->item_flags & 1) != 0;
176
177 decoder->item_flags >>= 1;
178 decoder->flags_remaining--;
179
180 if (literal) {
181 if (decoder->stream_position >= stream_length) {
182 return false;
183 }
184
185 value = stream[decoder->stream_position++];
186 } else {
187 if (stream_length - decoder->stream_position < 2) {
188 return false;
189 }
190
191 uint8_t b0 = stream[decoder->stream_position++];
192 uint8_t b1 = stream[decoder->stream_position++];
193
194 decoder->match_distance = ((((uint32_t)b1 >> 4) << 8) | b0) + 1;
195 decoder->match_remaining = (b1 & 0x0f) + 3;
196
197 if (decoder->match_distance > decoder->filled) {
198 return false;
199 }
200
201 continue;
202 }
203 }
204
205 image->pixels[position++] ^= value;
206 decoder->window[decoder->window_position] = value;
207 decoder->window_position = (decoder->window_position + 1) & (TAIF_WINDOW_SIZE - 1);
208
209 if (decoder->filled < TAIF_WINDOW_SIZE) {
210 decoder->filled++;
211 }
212 }
213
214 bool eight_bpp = (image->flags & TAIF_FLAG_8BPP) != 0;
215 bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0;
216 uint32_t max_index = transparent ? image->palette_entries : (uint32_t)image->palette_entries - 1;
217 uint32_t full_bytes = eight_bpp ? image->width : image->width / 2;
218 bool odd_column = !eight_bpp && (image->width & 1) != 0;
219
220 for (uint32_t row = 0; row < image->height; row++) {
221 const uint8_t *line = image->pixels + (size_t)row * image->stride;
222
223 for (uint32_t i = 0; i < full_bytes; i++) {
224 if (eight_bpp) {
225 if (line[i] > max_index) {
226 return false;
227 }
228 } else if ((uint32_t)(line[i] >> 4) > max_index || (uint32_t)(line[i] & 0x0f) > max_index) {
229 return false;
230 }
231 }
232
233 if (odd_column && (uint32_t)(line[full_bytes] >> 4) > max_index) {
234 return false;
235 }
236 }
237
238 free(image->scaled);
239
240 image->scaled = 0;
241 image->frames_decoded++;
242
243 return true;
244 }
245
246 static ta_image_cache *find_image(const uint8_t *data) {
247 if (data == 0) {
248 return 0;
249 }
250
251 for (ta_image_cache *image = image_cache; image != 0; image = image->next) {
252 if (image->data == data) {
253 return image;
254 }
255 }
256
257 return 0;
258 }
259
260 bool ta_image_init(const uint8_t *data, uint32_t length) {
261 if (find_image(data) != 0) {
262 return true;
263 }
264
265 ta_image_cache *image = (ta_image_cache *)malloc(sizeof(*image));
266 if (image == 0) {
267 return false;
268 }
269
270 *image = (ta_image_cache){0};
271
272 if (!parse_image(data, length, image)) {
273 free(image);
274 return false;
275 }
276
277 if (!decode_next_frame(image)) {
278 free(image->pixels);
279 free(image);
280 return false;
281 }
282
283 image->next = image_cache;
284 image_cache = image;
285 return true;
286 }
287
288 bool ta_image_get_size(const uint8_t *data, uint32_t *width, uint32_t *height) {
289 ta_image_cache *image = find_image(data);
290 if (image == 0 || width == 0 || height == 0) {
291 return false;
292 }
293
294 *width = image->width;
295 *height = image->height;
296
297 return true;
298 }
299
300 static ta_image_cache *get_image(const uint8_t *data, uint32_t length, uint16_t frame) {
301 if (!ta_image_init(data, length)) {
302 return 0;
303 }
304
305 ta_image_cache *image = find_image(data);
306 if (frame >= image->frame_count) {
307 return 0;
308 }
309
310 uint32_t wanted = (uint32_t)frame + 1;
311
312 if (image->frames_decoded > wanted) {
313 decoder_reset(image);
314 }
315
316 while (image->frames_decoded < wanted) {
317 if (!decode_next_frame(image)) {
318 decoder_reset(image);
319 return 0;
320 }
321 }
322
323 return image;
324 }
325
326 static uint8_t get_pixel_index(const ta_image_cache *image, uint32_t x, uint32_t y) {
327 if ((image->flags & TAIF_FLAG_8BPP) != 0) {
328 return image->pixels[y * image->stride + x];
329 }
330
331 uint8_t packed = image->pixels[y * image->stride + x / 2];
332 return (x & 1) == 0 ? packed >> 4 : packed & 0x0f;
333 }
334
335 typedef struct {
336 uint16_t first;
337 uint16_t second;
338 uint8_t fraction;
339 } ta_image_axis;
340
341 static ta_image_axis axis_position(uint32_t index, uint32_t count, uint32_t source_count) {
342 ta_image_axis axis;
343
344 #ifdef TA_DISABLE_BILINEAR_FILTERING
345 axis.first = (uint16_t)((uint64_t)index * source_count / count);
346 axis.second = axis.first;
347 axis.fraction = 0;
348 #else
349 uint64_t position = ((uint64_t)(2 * (uint64_t)index + 1) * source_count * 128) / count;
350
351 if (position <= 128) {
352 axis.first = 0;
353 axis.second = 0;
354 axis.fraction = 0;
355 } else {
356 position -= 128;
357
358 uint32_t first = (uint32_t)(position >> 8);
359
360 if (first >= source_count - 1) {
361 axis.first = (uint16_t)(source_count - 1);
362 axis.second = axis.first;
363 axis.fraction = 0;
364 } else {
365 axis.first = (uint16_t)first;
366 axis.second = (uint16_t)(first + 1);
367 axis.fraction = (uint8_t)(position & 0xff);
368 }
369 }
370 #endif
371
372 return axis;
373 }
374
375 static uint32_t sample_image(const ta_image_cache *image, ta_image_axis column, ta_image_axis row, uint32_t *red, uint32_t *green, uint32_t *blue) {
376 uint32_t weight_x0 = 256 - column.fraction;
377 uint32_t weight_y0 = 256 - row.fraction;
378 bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0;
379
380 uint32_t weights[4] = {
381 weight_x0 * weight_y0,
382 column.fraction * weight_y0,
383 weight_x0 * row.fraction,
384 column.fraction * row.fraction
385 };
386
387 uint8_t indices[4] = {
388 get_pixel_index(image, column.first, row.first),
389 get_pixel_index(image, column.second, row.first),
390 get_pixel_index(image, column.first, row.second),
391 get_pixel_index(image, column.second, row.second)
392 };
393
394 uint32_t red_sum = 0;
395 uint32_t green_sum = 0;
396 uint32_t blue_sum = 0;
397 uint32_t alpha_sum = 0;
398
399 for (uint32_t sample = 0; sample < 4; sample++) {
400 if (transparent && indices[sample] == 0) {
401 continue;
402 }
403
404 uint32_t palette_index = indices[sample] - (transparent ? 1 : 0);
405
406 red_sum += (uint32_t)image->palette[palette_index][0] * weights[sample];
407 green_sum += (uint32_t)image->palette[palette_index][1] * weights[sample];
408 blue_sum += (uint32_t)image->palette[palette_index][2] * weights[sample];
409 alpha_sum += weights[sample];
410 }
411
412 *red = red_sum;
413 *green = green_sum;
414 *blue = blue_sum;
415
416 return alpha_sum;
417 }
418
419 static void copy_bytes(uint8_t *destination, const uint8_t *source, size_t count) {
420 if ((((size_t)destination | (size_t)source) & 3) == 0) {
421 size_t words = count / 4;
422
423 for (size_t i = 0; i < words; i++) {
424 ((uint32_t *)destination)[i] = ((const uint32_t *)source)[i];
425 }
426
427 destination += words * 4;
428 source += words * 4;
429 count &= 3;
430 }
431
432 while (count--) {
433 *destination++ = *source++;
434 }
435 }
436
437 static bool prepare_scaled(ta_image_cache *image, uint32_t width, uint32_t height) {
438 if (image->scaled != 0 && image->scaled_width == width && image->scaled_height == height && image->scaled_bpp == ta_display->bpp) {
439 return true;
440 }
441
442 size_t bytes_per_pixel = ta_display->bpp / 8;
443 uint8_t *scaled = (uint8_t *)malloc((size_t)width * height * bytes_per_pixel);
444 ta_image_axis *columns = (ta_image_axis *)malloc((size_t)width * sizeof(*columns));
445
446 if (scaled == 0 || columns == 0) {
447 free(scaled);
448 free(columns);
449
450 return false;
451 }
452
453 for (uint32_t column = 0; column < width; column++) {
454 columns[column] = axis_position(column, width, image->width);
455 }
456
457 uint8_t *output = scaled;
458
459 for (uint32_t y = 0; y < height; y++) {
460 ta_image_axis row = axis_position(y, height, image->height);
461
462 for (uint32_t x = 0; x < width; x++) {
463 uint32_t red;
464 uint32_t green;
465 uint32_t blue;
466
467 sample_image(image, columns[x], row, &red, &green, &blue);
468
469 red = (red + 32768) >> 16;
470 green = (green + 32768) >> 16;
471 blue = (blue + 32768) >> 16;
472
473 if (ta_display->bpp == 32) {
474 *(uint32_t *)output = (red << 16) | (green << 8) | blue;
475 output += 4;
476 } else {
477 *output++ = (uint8_t)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6));
478 }
479 }
480 }
481
482 free(columns);
483 free(image->scaled);
484
485 image->scaled = scaled;
486 image->scaled_width = width;
487 image->scaled_height = height;
488 image->scaled_bpp = (uint8_t)ta_display->bpp;
489
490 return true;
491 }
492
493 bool ta_image_draw(const uint8_t *data, uint32_t length, ta_fixed x, ta_fixed y, ta_fixed width, ta_fixed height, uint16_t frame) {
494 if (data == 0 || length == 0 || x > TA_FIXED_ONE || y > TA_FIXED_ONE || width == 0 || height == 0 || width > TA_FIXED_ONE || height > TA_FIXED_ONE || (!ta_display->sprite_mode && ta_display->buffers[1] == 0) || (ta_display->sprite_mode && (!ta_display_sprites || ta_display->bpp != 32)) || (ta_display->bpp != 8 && ta_display->bpp != 32)) {
495 return false;
496 }
497
498 uint32_t pixel_x = (uint32_t)(((uint64_t)x * ta_display->width) >> 16);
499 uint32_t pixel_y = (uint32_t)(((uint64_t)y * ta_display->height) >> 16);
500 uint32_t pixel_width = (uint32_t)(((uint64_t)width * ta_display->width) >> 16);
501 uint32_t pixel_height = (uint32_t)(((uint64_t)height * ta_display->height) >> 16);
502
503 if (pixel_width == 0 || pixel_height == 0) {
504 return false;
505 }
506
507 ta_image_cache *image = get_image(data, length, frame);
508 if (image == 0) {
509 return false;
510 }
511
512 uint32_t visible_width = 0;
513 uint32_t visible_height = 0;
514
515 if (pixel_x < ta_display->width) {
516 visible_width = pixel_width > ta_display->width - pixel_x ? (uint32_t)(ta_display->width - pixel_x) : pixel_width;
517 }
518
519 if (pixel_y < ta_display->height) {
520 visible_height = pixel_height > ta_display->height - pixel_y ? (uint32_t)(ta_display->height - pixel_y) : pixel_height;
521 }
522
523 if (visible_width == 0 || visible_height == 0) {
524 return true;
525 }
526
527 bool transparent = (image->flags & TAIF_FLAG_TRANSPARENT) != 0;
528
529 if (ta_display->sprite_mode) {
530 uint32_t source_width = image->width;
531 uint32_t source_height = image->height;
532
533 if (visible_width < pixel_width) {
534 source_width = (uint32_t)(((uint64_t)visible_width * image->width + pixel_width - 1) / pixel_width);
535 }
536
537 if (visible_height < pixel_height) {
538 source_height = (uint32_t)(((uint64_t)visible_height * image->height + pixel_height - 1) / pixel_height);
539 }
540
541 ta_display_sprite *sprite = ta_display_sprite_create((uint16_t)source_width, (uint16_t)source_height);
542 if (!sprite) {
543 return false;
544 }
545
546 sprite->x = (uint16_t)pixel_x;
547 sprite->y = (uint16_t)pixel_y;
548 sprite->draw_width = (uint16_t)visible_width;
549 sprite->draw_height = (uint16_t)visible_height;
550
551 uint32_t *pixels = (uint32_t *)sprite->pixels;
552 uint32_t palette_offset = transparent ? 1 : 0;
553
554 for (uint32_t image_y = 0; image_y < source_height; image_y++) {
555 for (uint32_t image_x = 0; image_x < source_width; image_x++) {
556 uint8_t index = get_pixel_index(image, image_x, image_y);
557 uint32_t *pixel = &pixels[(size_t)image_y * source_width + image_x];
558
559 if (transparent && index == 0) {
560 *pixel = 0;
561 } else {
562 const uint8_t *color = image->palette[index - palette_offset];
563
564 *pixel = ((uint32_t)color[0] << 24) | ((uint32_t)color[1] << 16) | ((uint32_t)color[2] << 8) | 0xff;
565 }
566 }
567 }
568
569 if (!ta_display_sprite_add(sprite)) {
570 free(sprite);
571 return false;
572 }
573
574 return true;
575 }
576
577 if (!transparent && prepare_scaled(image, pixel_width, pixel_height)) {
578 size_t bytes_per_pixel = ta_display->bpp / 8;
579
580 for (uint32_t image_y = 0; image_y < visible_height; image_y++) {
581 const uint8_t *source = image->scaled + (size_t)image_y * pixel_width * bytes_per_pixel;
582 uint8_t *destination = (uint8_t *)ta_display->buffers[1] + ((size_t)(pixel_y + image_y) * ta_display->width + pixel_x) * bytes_per_pixel;
583
584 if (ta_display->bpp == 8) {
585 copy_bytes(destination, source, visible_width);
586 } else {
587 const uint32_t *source32 = (const uint32_t *)source;
588 uint32_t *destination32 = (uint32_t *)destination;
589
590 for (uint32_t image_x = 0; image_x < visible_width; image_x++) {
591 destination32[image_x] = (destination32[image_x] & 0xff000000u) | source32[image_x];
592 }
593 }
594 }
595
596 return true;
597 }
598
599 ta_image_axis *columns = (ta_image_axis *)malloc((size_t)visible_width * sizeof(*columns));
600 if (columns == 0) {
601 return false;
602 }
603
604 for (uint32_t image_x = 0; image_x < visible_width; image_x++) {
605 columns[image_x] = axis_position(image_x, pixel_width, image->width);
606 }
607
608 for (uint32_t image_y = 0; image_y < visible_height; image_y++) {
609 ta_image_axis row = axis_position(image_y, pixel_height, image->height);
610 size_t row_start = (size_t)(pixel_y + image_y) * ta_display->width + pixel_x;
611
612 for (uint32_t image_x = 0; image_x < visible_width; image_x++) {
613 uint32_t red;
614 uint32_t green;
615 uint32_t blue;
616 uint32_t alpha_sum = sample_image(image, columns[image_x], row, &red, &green, &blue);
617
618 if (alpha_sum == 0) {
619 continue;
620 }
621
622 size_t destination_index = row_start + image_x;
623 uint32_t inverse_alpha = 65536 - alpha_sum;
624
625 if (ta_display->bpp == 32) {
626 uint32_t *pixels = (uint32_t *)ta_display->buffers[1];
627 uint32_t destination = pixels[destination_index];
628
629 red = (red + ((destination >> 16) & 0xff) * inverse_alpha + 32768) >> 16;
630 green = (green + ((destination >> 8) & 0xff) * inverse_alpha + 32768) >> 16;
631 blue = (blue + (destination & 0xff) * inverse_alpha + 32768) >> 16;
632
633 pixels[destination_index] = (destination & 0xff000000u) | (red << 16) | (green << 8) | blue;
634 } else {
635 uint8_t *pixels = (uint8_t *)ta_display->buffers[1];
636 uint32_t destination = pixels[destination_index];
637
638 red = (red + (((destination >> 5) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16;
639 green = (green + (((destination >> 2) & 7) * 255 / 7) * inverse_alpha + 32768) >> 16;
640 blue = (blue + ((destination & 3) * 255 / 3) * inverse_alpha + 32768) >> 16;
641
642 pixels[destination_index] = (uint8_t)(((red >> 5) << 5) | ((green >> 5) << 2) | (blue >> 6));
643 }
644 }
645 }
646
647 free(columns);
648
649 return true;
650 }
651
652 bool ta_image_render(const uint8_t *data, uint32_t length, uint16_t frame, uint32_t width, uint32_t height, uint32_t *pixels) {
653 if (pixels == 0 || width == 0 || height == 0) {
654 return false;
655 }
656
657 ta_image_cache *image = get_image(data, length, frame);
658 if (image == 0) {
659 return false;
660 }
661
662 ta_image_axis *columns = (ta_image_axis *)malloc((size_t)width * sizeof(*columns));
663 if (columns == 0) {
664 return false;
665 }
666
667 for (uint32_t x = 0; x < width; x++) {
668 columns[x] = axis_position(x, width, image->width);
669 }
670
671 for (uint32_t y = 0; y < height; y++) {
672 ta_image_axis row = axis_position(y, height, image->height);
673
674 for (uint32_t x = 0; x < width; x++) {
675 uint32_t red;
676 uint32_t green;
677 uint32_t blue;
678
679 sample_image(image, columns[x], row, &red, &green, &blue);
680
681 red = (red + 32768) >> 16;
682 green = (green + 32768) >> 16;
683 blue = (blue + 32768) >> 16;
684
685 pixels[(size_t)y * width + x] = (red << 16) | (green << 8) | blue;
686 }
687 }
688
689 free(columns);
690
691 return true;
692 }
693
694 void ta_image_release(void) {
695 while (image_cache != 0) {
696 ta_image_cache *image = image_cache;
697 image_cache = image->next;
698 free(image->pixels);
699 free(image->scaled);
700 free(image);
701 }
702 }