Open Source Tomb Raider Engine
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

tga.cpp 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. /*!
  2. * \file src/utils/tga.cpp
  3. * \brief TGA image reader/writer
  4. *
  5. * \todo type should pass more info (2 bits for RGBA|RGB|GREY; val for depth)
  6. *
  7. * \author Mongoose
  8. * \author xythobuz
  9. */
  10. #include <stdio.h>
  11. #include <string.h>
  12. #include <stdarg.h>
  13. #include "global.h"
  14. #include "utils/tga.h"
  15. typedef enum {
  16. //TGA_TYPE__NO_DATA = 0,
  17. //TGA_TYPE__MAPPED = 1,
  18. TGA_TYPE__COLOR = 2,
  19. TGA_TYPE__GREYSCALE = 3,
  20. //TGA_TYPE__MAPPED_RLE = 9,
  21. TGA_TYPE__COLOR_RLE = 10
  22. } tga_type_t;
  23. typedef struct {
  24. unsigned char comment_lenght; //!< Number of bytes in comment
  25. unsigned char colormap_type; //!< 0 No colormap; 1 Has colormap
  26. unsigned char image_type; //!< 1 Colormapped; 2 Unmapped; 9 Colormapped RLE; 10 Unmapped RLE
  27. unsigned short colormap_index; //!< Index of first color map entry
  28. unsigned short colormap_lenght; //!< Number of color map entries
  29. unsigned char colormap_bbp; //!< 16, 24, or 32 bits per pixel format
  30. unsigned short origin_x; //!< X coor of lower-left corner
  31. unsigned short origin_y; //!< Y coor of lower-left corner
  32. unsigned short width; //!< Width in pixels
  33. unsigned short height; //!< Height in pixels
  34. unsigned char bpp; //!< Number of bits in a pixel index
  35. unsigned char desc_flags; //!< Various magic bits
  36. } tga_t;
  37. int tgaCheck(FILE *f) {
  38. char buffer[10];
  39. assert(f != NULL);
  40. /* Read the header */
  41. fseek(f, 0, SEEK_SET);
  42. fread(buffer, 8, 1, f);
  43. // buffer[1] = 0 - Means not color mapped (1 would mean mapped)
  44. if (!(buffer[1] == 0 && (buffer[2] == TGA_TYPE__COLOR ||
  45. //buffer[2] == TGA_TYPE__GREYSCALE ||
  46. buffer[2] == TGA_TYPE__COLOR_RLE))) {
  47. printf("tgaCheck> Inavlid or unknown TGA format.\n");
  48. return -2;
  49. }
  50. return 0;
  51. }
  52. int tgaLoad(FILE *f, unsigned char **image, unsigned int *width, unsigned int *height, char *type) {
  53. tga_t header;
  54. char comment[256];
  55. unsigned char pixel[4];
  56. unsigned char *swap_row = NULL;
  57. unsigned char tmp, packet;
  58. bool must_flip = 0;
  59. unsigned int size;
  60. unsigned int i, j;
  61. assert(f != NULL);
  62. assert(image != NULL);
  63. assert(width != NULL);
  64. assert(height != NULL);
  65. assert(type != NULL);
  66. fseek(f, 0, SEEK_SET);
  67. // Read TGA header
  68. fread(&header.comment_lenght, 1, 1, f);
  69. fread(&header.colormap_type, 1, 1, f);
  70. fread(&header.image_type, 1, 1, f);
  71. fread(&header.colormap_index, 2, 1, f);
  72. fread(&header.colormap_lenght, 2, 1, f);
  73. fread(&header.colormap_bbp, 1, 1, f);
  74. fread(&tmp, 1, 1, f);
  75. header.origin_x = tmp;
  76. fread(&tmp, 1, 1, f);
  77. header.origin_x += tmp * 256;
  78. fread(&tmp, 1, 1, f);
  79. header.origin_y = tmp;
  80. fread(&tmp, 1, 1, f);
  81. header.origin_y += tmp * 256;
  82. fread(&tmp, 1, 1, f);
  83. header.width = tmp;
  84. fread(&tmp, 1, 1, f);
  85. header.width += tmp * 256;
  86. fread(&tmp, 1, 1, f);
  87. header.height = tmp;
  88. fread(&tmp, 1, 1, f);
  89. header.height += tmp * 256;
  90. fread(&header.bpp, 1, 1, f);
  91. fread(&header.desc_flags, 1, 1, f);
  92. *width = header.width;
  93. *height = header.height;
  94. switch (header.bpp) {
  95. case 32:
  96. *type = 2; //32;
  97. break;
  98. case 24:
  99. *type = 1; //24;
  100. break;
  101. case 8:
  102. default:
  103. *type = 0; //8;
  104. break;
  105. }
  106. #ifdef DEBUG_TGA
  107. printf("TGA [%ix%i@%ibpp, %it, %ix, %iy, %uf]\n",
  108. header.width, header.height, header.bpp, header.image_type,
  109. header.origin_x, header.origin_y,
  110. header.desc_flags);
  111. #endif
  112. // Comments can be 0 - 255
  113. if (header.comment_lenght) {
  114. fread(&comment, 1, header.comment_lenght, f);
  115. for (i = 0; i < 255; ++i) {
  116. if (!(comment[i] > 32 && comment[i] < 127))
  117. comment[i] = 183; // print a dot for invalid text
  118. }
  119. comment[255] = 0;
  120. printf("Comment: '%s'\n", comment);
  121. }
  122. *image = NULL;
  123. size = header.width * header.height;
  124. if (!size || (!(header.colormap_type == 0 && (header.image_type == 2 || header.image_type == 10)))) {
  125. fprintf(stderr, "tgaLoad> Unknown image format.\n");
  126. return -2;
  127. }
  128. // Mongoose: Added 'screen origin bit' support back here
  129. if (!(header.desc_flags & 32)) {
  130. must_flip = true;
  131. }
  132. switch (header.bpp) {
  133. case 32:
  134. size *= 4;
  135. *image = new unsigned char [size];
  136. switch (header.image_type) {
  137. case TGA_TYPE__COLOR_RLE:
  138. for (i = 0; i < size;) {
  139. fread(&packet, 1, 1, f);
  140. if (packet & 0x80) { // Run Length
  141. packet = (packet &0x7F) + 1;
  142. fread(&pixel, 4, 1, f);
  143. for (j = 0; j < packet; j++) {
  144. (*image)[i++] = pixel[2];
  145. (*image)[i++] = pixel[1];
  146. (*image)[i++] = pixel[0];
  147. (*image)[i++] = pixel[3];
  148. }
  149. } else { // RAW
  150. packet = (packet &0x7F) + 1;
  151. for (j = 0; j < packet; j++) {
  152. fread(&pixel, 4, 1, f);
  153. (*image)[i++] = pixel[2];
  154. (*image)[i++] = pixel[1];
  155. (*image)[i++] = pixel[0];
  156. (*image)[i++] = pixel[3];
  157. }
  158. }
  159. }
  160. break;
  161. case TGA_TYPE__COLOR:
  162. if (fread((*image), size, 1, f) < 1) {
  163. fprintf(stderr, "tgaLoad> Image fread failed.\n");
  164. delete [] *image;
  165. return -4;
  166. }
  167. for (i = 0; i < size; i += 4) {
  168. tmp = (*image)[i];
  169. (*image)[i] = (*image)[i + 2];
  170. (*image)[i + 2] = tmp;
  171. }
  172. break;
  173. default:
  174. ;
  175. }
  176. if (must_flip) {
  177. swap_row = new unsigned char [header.width * 4];
  178. for (i = 0, j = header.height-1; (int)i < header.height/2; i++, j--) {
  179. memcpy(swap_row, &(*image)[i*header.width*4], header.width*4);
  180. memcpy(&(*image)[i*header.width*4], &(*image)[j*header.width*4],
  181. header.width*4);
  182. memcpy(&(*image)[j*header.width*4], swap_row, header.width*4);
  183. }
  184. delete [] swap_row;
  185. }
  186. break;
  187. case 24:
  188. size *= 3;
  189. *image = new unsigned char [size];
  190. switch (header.image_type) {
  191. case TGA_TYPE__COLOR_RLE:
  192. for (i = 0; i < size;) {
  193. fread(&packet, 1, 1, f);
  194. if (packet & 0x80) { // Run Length
  195. packet = (packet &0x7F) + 1;
  196. fread(&pixel, 3, 1, f);
  197. for (j = 0; j < packet; j++) {
  198. (*image)[i++] = pixel[2];
  199. (*image)[i++] = pixel[1];
  200. (*image)[i++] = pixel[0];
  201. }
  202. } else { // RAW
  203. packet = (packet &0x7F) + 1;
  204. for (j = 0; j < packet; j++) {
  205. fread(&pixel, 3, 1, f);
  206. (*image)[i++] = pixel[2];
  207. (*image)[i++] = pixel[1];
  208. (*image)[i++] = pixel[0];
  209. }
  210. }
  211. }
  212. break;
  213. case TGA_TYPE__COLOR:
  214. if (fread((*image), size, 1, f) < 1) {
  215. fprintf(stderr, "tgaLoad> Image fread failed.\n");
  216. delete [] *image;
  217. return -4;
  218. }
  219. for (i = 0; i < size; i += 3) {
  220. tmp = (*image)[i];
  221. (*image)[i] = (*image)[i + 2];
  222. (*image)[i + 2] = tmp;
  223. }
  224. break;
  225. default:
  226. ;
  227. }
  228. if (must_flip) {
  229. swap_row = new unsigned char [header.width * 3];
  230. for (i = 0, j = header.height - 1; (int)i < header.height / 2; i++, j--) {
  231. memcpy(swap_row, &(*image)[i*header.width*3], header.width*3);
  232. memcpy(&(*image)[i*header.width*3], &(*image)[j*header.width*3],
  233. header.width*3);
  234. memcpy(&(*image)[j*header.width*3], swap_row, header.width*3);
  235. }
  236. delete [] swap_row;
  237. }
  238. break;
  239. case 8:
  240. printf("tgaLoad> 8bpp Not implemented\n");
  241. break;
  242. default:
  243. ;
  244. }
  245. #ifdef DEBUG_TGA
  246. char c;
  247. printf("TGA Comment: ");
  248. while (fread(&c, 1, 1, f) == 1) {
  249. printf("%c", c);
  250. }
  251. printf("\n");
  252. #endif
  253. return 0;
  254. }
  255. int tgaSave(FILE *f, unsigned char *image, unsigned int width, unsigned int height, char type) {
  256. tga_t header;
  257. unsigned int size;
  258. char comment[64];
  259. //unsigned int i;
  260. //unsigned char tmp;
  261. assert(f != NULL);
  262. assert(image != NULL);
  263. assert(width > 0);
  264. assert(height > 0);
  265. strncpy(comment, "OpenRaider TGA", 63);
  266. comment[63] = 0;
  267. header.comment_lenght = (unsigned char)strlen(comment);
  268. header.colormap_type = 0;
  269. // No colormaps
  270. header.colormap_index = 0;
  271. header.colormap_lenght = 0;
  272. header.colormap_bbp = 0;
  273. header.origin_x = header.origin_y = 0;
  274. header.width = (unsigned short)width;
  275. header.height = (unsigned short)height;
  276. header.desc_flags = 0;
  277. switch (type) {
  278. case 4:
  279. header.image_type = TGA_TYPE__COLOR;
  280. header.desc_flags = 32;
  281. header.bpp = 32;
  282. break;
  283. case 2:
  284. header.bpp = 32;
  285. break;
  286. case 1:
  287. header.image_type = TGA_TYPE__GREYSCALE;
  288. header.bpp = 8;
  289. break;
  290. default:
  291. header.image_type = TGA_TYPE__COLOR;
  292. header.bpp = 24;
  293. }
  294. // Write TGA header
  295. fwrite(&header.comment_lenght, 1, 1, f);
  296. fwrite(&header.colormap_type, 1, 1, f);
  297. fwrite(&header.image_type, 1, 1, f);
  298. fwrite(&header.colormap_index, 2, 1, f);
  299. fwrite(&header.colormap_lenght, 2, 1, f);
  300. fwrite(&header.colormap_bbp, 1, 1, f);
  301. fwrite(&header.origin_x, 2, 1, f);
  302. fwrite(&header.origin_y, 2, 1, f);
  303. fwrite(&header.width, 2, 1, f);
  304. fwrite(&header.height, 2, 1, f);
  305. fwrite(&header.bpp, 1, 1, f);
  306. fwrite(&header.desc_flags, 1, 1, f);
  307. // Write comment
  308. fwrite(&comment, 1, header.comment_lenght, f);
  309. switch (header.bpp) {
  310. case 32:
  311. size = header.width * header.height * 4;
  312. //for (i = 0; i < size; i += 4)
  313. //{
  314. // tmp = image[i];
  315. // image[i] = image[i + 2];
  316. // image[i + 2] = tmp;
  317. //}
  318. break;
  319. case 24:
  320. size = header.width * header.height * 3;
  321. //for (i = 0; i < size; i += 3)
  322. //{
  323. // tmp = image[i];
  324. // image[i] = image[i + 2];
  325. // image[i + 2] = tmp;
  326. //}
  327. break;
  328. case 8:
  329. default:
  330. size = header.width * header.height;
  331. break;
  332. }
  333. // Write image data
  334. if (fwrite(image, size, 1, f) < 1) {
  335. perror("tgaSave> Disk write failed.\n");
  336. return -2;
  337. }
  338. return 0;
  339. }