tga.c 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (c) 2008-2010 Travis Geiselbrecht
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining
  5. * a copy of this software and associated documentation files
  6. * (the "Software"), to deal in the Software without restriction,
  7. * including without limitation the rights to use, copy, modify, merge,
  8. * publish, distribute, sublicense, and/or sell copies of the Software,
  9. * and to permit persons to whom the Software is furnished to do so,
  10. * subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be
  13. * included in all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  18. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  19. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  20. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  21. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. */
  23. /**
  24. * @file
  25. * @brief Parse tga format files
  26. *
  27. * @ingroup graphics
  28. */
  29. #include <debug.h>
  30. #include <compiler.h>
  31. #include <lib/tga.h>
  32. #define LOCAL_TRACE 0
  33. struct tga_header {
  34. uint8_t idlength;
  35. uint8_t colormaptype;
  36. uint8_t datatypecode;
  37. uint16_t colormaporigin;
  38. uint16_t colormaplength;
  39. uint8_t colormapdepth;
  40. uint16_t x_origin;
  41. uint16_t y_origin;
  42. uint16_t width;
  43. uint16_t height;
  44. uint8_t bitsperpixel;
  45. uint8_t imagedescriptor;
  46. } __PACKED;
  47. static void print_tga_info(const struct tga_header *header)
  48. {
  49. LTRACEF("idlength %hhd\n", header->idlength);
  50. LTRACEF("colormaptype %hhd\n", header->colormaptype);
  51. LTRACEF("datatypecode %hhd\n", header->datatypecode);
  52. LTRACEF("colormaporigin %hd\n", header->colormaporigin);
  53. LTRACEF("colormaplength %hd\n", header->colormaplength);
  54. LTRACEF("colormapdepth %hhd\n", header->colormapdepth);
  55. LTRACEF("x_origin %hd\n", header->x_origin);
  56. LTRACEF("y_origin %hd\n", header->y_origin);
  57. LTRACEF("width %hd\n", header->width);
  58. LTRACEF("height %hd\n", header->height);
  59. LTRACEF("bitsperpixel %hhd\n", header->bitsperpixel);
  60. LTRACEF("imagedescriptor %hhd\n", header->imagedescriptor);
  61. }
  62. static void decode_2byte(gfx_surface *surface, uint x, uint y, const void *input)
  63. {
  64. const uint8_t *in = (const uint8_t *)input;
  65. // printf("in 0x%hhx 0x%hhx\n", in[0], in[1]);
  66. uint r,g,b;
  67. b = (in[0] & 0x1f) << 3;
  68. g = (((in[0] >> 5) & 0x7) | ((in[1] & 0x3) << 3)) << 3;
  69. r = ((in[1] >> 2) & 0x1f) << 3;
  70. gfx_putpixel(surface, x, y, 0xff000000 | r << 16 | g << 8 | b);
  71. }
  72. static void decode_3byte(gfx_surface *surface, uint x, uint y, const void *input)
  73. {
  74. const uint8_t *in = (const uint8_t *)input;
  75. // printf("in 0x%hhx 0x%hhx\n", in[0], in[1]);
  76. gfx_putpixel(surface, x, y, 0xff000000 | in[2] << 16 | in[1] << 8 | in[0]);
  77. }
  78. static void decode_4byte(gfx_surface *surface, uint x, uint y, const void *input)
  79. {
  80. const uint8_t *in = (const uint8_t *)input;
  81. // printf("in 0x%hhx 0x%hhx 0x%hhx 0x%hhx\n", in[0], in[1], in[2], in[3]);
  82. if (in[3] == 0)
  83. gfx_putpixel(surface, x, y, 0);
  84. else
  85. gfx_putpixel(surface, x, y, in[3] << 24 | in[2] << 16 | in[1] << 8 | in[0]);
  86. }
  87. /**
  88. * @brief Decode a tga image
  89. *
  90. * @param ptr Pointer to tga data in memory
  91. * @param len Length of tga data
  92. * @param format Desired format of returned graphics surface
  93. *
  94. * @return Graphics surface or NULL on error.
  95. *
  96. * @ingroup graphics
  97. */
  98. gfx_surface *tga_decode(const void *ptr, size_t len, gfx_format format)
  99. {
  100. const struct tga_header *header = (const struct tga_header *)ptr;
  101. LTRACEF("ptr %p, len %zu\n", ptr, len);
  102. #if LOCAL_TRACE > 0
  103. print_tga_info(header);
  104. #endif
  105. /* do some sanity checks */
  106. if (header->datatypecode != 2 && header->datatypecode != 10) {
  107. dprintf(INFO, "tga_decode: unknown data type %d\n", header->datatypecode);
  108. return NULL;
  109. }
  110. if (header->bitsperpixel != 16 && header->bitsperpixel != 24 && header->bitsperpixel != 32) {
  111. dprintf(INFO, "tga_decode: unsupported bits per pixel %d\n", header->bitsperpixel);
  112. return NULL;
  113. }
  114. if (header->colormaptype != 0) {
  115. dprintf(INFO, "tga_decode: has colormap, can't handle\n");
  116. return NULL;
  117. }
  118. const void *imagestart = ((const uint8_t *)ptr + sizeof(struct tga_header) + header->idlength);
  119. /* create a surface to hold the decoded bits */
  120. gfx_surface *surface = gfx_create_surface(NULL, header->width, header->height, header->width, format);
  121. DEBUG_ASSERT(surface);
  122. /* copy the bits out */
  123. void (*decodefunc)(gfx_surface *, uint x, uint y, const void *) = NULL;
  124. uint step = 1;
  125. if (header->bitsperpixel == 16) {
  126. step = 2;
  127. decodefunc = decode_2byte;
  128. } else if (header->bitsperpixel == 24) {
  129. step = 3;
  130. decodefunc = decode_3byte;
  131. } else if (header->bitsperpixel == 32) {
  132. step = 4;
  133. decodefunc = decode_4byte;
  134. }
  135. if (header->datatypecode == 2) {
  136. /* no RLE */
  137. uint pos = 0;
  138. uint x, y;
  139. uint surfacey;
  140. for (y = 0; y < header->height; y++) {
  141. if ((header->imagedescriptor & (1 << 5)) == 0)
  142. surfacey = (surface->height - 1) - y;
  143. else
  144. surfacey = y;
  145. for (x = 0; x < header->width; x++) {
  146. decodefunc(surface, x, surfacey, (const uint8_t *)imagestart + pos);
  147. pos += step;
  148. }
  149. }
  150. } else if (header->datatypecode == 10) {
  151. /* RLE compression */
  152. uint pos = 0;
  153. uint count = 0;
  154. uint x, y;
  155. x = 0;
  156. if ((header->imagedescriptor & (1 << 5)) == 0)
  157. y = header->height - 1;
  158. else
  159. y = 0;
  160. while (count < (uint)header->height * (uint)header->width) {
  161. uint runpos;
  162. uint8_t run = *((const uint8_t *)imagestart + pos);
  163. bool repeat_run = (run & 0x80);
  164. uint runlen = (run & 0x7f) + 1;
  165. // printf("pos 0x%x count %u run 0x%hhx runtype %d runlen %u\n", pos, count, run, run & 0x80, runlen);
  166. /* consume the run byte */
  167. pos++;
  168. /* start of a run */
  169. for (runpos = 0; runpos < runlen; runpos++) {
  170. decodefunc(surface, x, y, (const uint8_t *)imagestart + pos);
  171. count++;
  172. x++;
  173. if (x == surface->width) {
  174. if ((header->imagedescriptor & (1 << 5)) == 0)
  175. y--;
  176. else
  177. y++;
  178. x = 0;
  179. }
  180. /* if a run of raw pixels, consume an input pixel */
  181. if (!repeat_run)
  182. pos += step;
  183. }
  184. /* if this was a run of repeated pixels, consume the one input pixel we repeated */
  185. if (repeat_run)
  186. pos += step;
  187. }
  188. // printf("done with RLE: x %d, y %d, pos %d, count %d\n", x, y, pos, count);
  189. }
  190. return surface;
  191. }