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 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  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(const char *filename) {
  38. char buffer[10];
  39. assert(filename != NULL);
  40. assert(filename[0] != '\0');
  41. FILE *f = fopen(filename, "rb");
  42. if (!f) {
  43. printf("tgaCheck> File not found\n");
  44. return -1;
  45. }
  46. /* Read the header */
  47. fseek(f, 0, SEEK_SET);
  48. fread(buffer, 8, 1, f);
  49. // buffer[1] = 0 - Means not color mapped (1 would mean mapped)
  50. if (!(buffer[1] == 0 && (buffer[2] == TGA_TYPE__COLOR ||
  51. //buffer[2] == TGA_TYPE__GREYSCALE ||
  52. buffer[2] == TGA_TYPE__COLOR_RLE))) {
  53. printf("tgaCheck> Inavlid or unknown TGA format.\n");
  54. fclose(f);
  55. return -2;
  56. }
  57. fclose(f);
  58. return 0;
  59. }
  60. int tgaLoad(const char *filename, unsigned char **image, unsigned int *width, unsigned int *height, char *type) {
  61. tga_t header;
  62. char comment[256];
  63. unsigned char pixel[4];
  64. unsigned char *swap_row = NULL;
  65. unsigned char tmp, packet;
  66. bool must_flip = 0;
  67. unsigned int size;
  68. unsigned int i, j;
  69. assert(filename != NULL);
  70. assert(filename[0] != '\0');
  71. assert(image != NULL);
  72. assert(width != NULL);
  73. assert(height != NULL);
  74. assert(type != NULL);
  75. FILE *f = fopen(filename, "rb");
  76. if (!f) {
  77. printf("tgaLoad> File not found\n");
  78. return -1;
  79. }
  80. fseek(f, 0, SEEK_SET);
  81. // Read TGA header
  82. fread(&header.comment_lenght, 1, 1, f);
  83. fread(&header.colormap_type, 1, 1, f);
  84. fread(&header.image_type, 1, 1, f);
  85. fread(&header.colormap_index, 2, 1, f);
  86. fread(&header.colormap_lenght, 2, 1, f);
  87. fread(&header.colormap_bbp, 1, 1, f);
  88. fread(&tmp, 1, 1, f);
  89. header.origin_x = tmp;
  90. fread(&tmp, 1, 1, f);
  91. header.origin_x += tmp * 256;
  92. fread(&tmp, 1, 1, f);
  93. header.origin_y = tmp;
  94. fread(&tmp, 1, 1, f);
  95. header.origin_y += tmp * 256;
  96. fread(&tmp, 1, 1, f);
  97. header.width = tmp;
  98. fread(&tmp, 1, 1, f);
  99. header.width += tmp * 256;
  100. fread(&tmp, 1, 1, f);
  101. header.height = tmp;
  102. fread(&tmp, 1, 1, f);
  103. header.height += tmp * 256;
  104. fread(&header.bpp, 1, 1, f);
  105. fread(&header.desc_flags, 1, 1, f);
  106. *width = header.width;
  107. *height = header.height;
  108. switch (header.bpp) {
  109. case 32:
  110. *type = 2; //32;
  111. break;
  112. case 24:
  113. *type = 1; //24;
  114. break;
  115. case 8:
  116. default:
  117. *type = 0; //8;
  118. break;
  119. }
  120. #ifdef DEBUG_TGA
  121. printf("TGA [%ix%i@%ibpp, %it, %ix, %iy, %uf]\n",
  122. header.width, header.height, header.bpp, header.image_type,
  123. header.origin_x, header.origin_y,
  124. header.desc_flags);
  125. #endif
  126. // Comments can be 0 - 255
  127. if (header.comment_lenght) {
  128. fread(&comment, 1, header.comment_lenght, f);
  129. for (i = 0; i < 255; ++i) {
  130. if (!(comment[i] > 32 && comment[i] < 127))
  131. comment[i] = '.'; // print a dot for invalid text
  132. }
  133. comment[255] = 0;
  134. printf("Comment: '%s'\n", comment);
  135. }
  136. *image = NULL;
  137. size = header.width * header.height;
  138. if (!size || (!(header.colormap_type == 0 && (header.image_type == 2 || header.image_type == 10)))) {
  139. fprintf(stderr, "tgaLoad> Unknown image format.\n");
  140. fclose(f);
  141. return -2;
  142. }
  143. // Mongoose: Added 'screen origin bit' support back here
  144. if (!(header.desc_flags & 32)) {
  145. must_flip = true;
  146. }
  147. switch (header.bpp) {
  148. case 32:
  149. size *= 4;
  150. *image = new unsigned char [size];
  151. switch (header.image_type) {
  152. case TGA_TYPE__COLOR_RLE:
  153. for (i = 0; i < size;) {
  154. fread(&packet, 1, 1, f);
  155. if (packet & 0x80) { // Run Length
  156. packet = (packet &0x7F) + 1;
  157. fread(&pixel, 4, 1, f);
  158. for (j = 0; j < packet; j++) {
  159. (*image)[i++] = pixel[2];
  160. (*image)[i++] = pixel[1];
  161. (*image)[i++] = pixel[0];
  162. (*image)[i++] = pixel[3];
  163. }
  164. } else { // RAW
  165. packet = (packet &0x7F) + 1;
  166. for (j = 0; j < packet; j++) {
  167. fread(&pixel, 4, 1, f);
  168. (*image)[i++] = pixel[2];
  169. (*image)[i++] = pixel[1];
  170. (*image)[i++] = pixel[0];
  171. (*image)[i++] = pixel[3];
  172. }
  173. }
  174. }
  175. break;
  176. case TGA_TYPE__COLOR:
  177. if (fread((*image), size, 1, f) < 1) {
  178. fprintf(stderr, "tgaLoad> Image fread failed.\n");
  179. delete [] *image;
  180. fclose(f);
  181. return -4;
  182. }
  183. for (i = 0; i < size; i += 4) {
  184. tmp = (*image)[i];
  185. (*image)[i] = (*image)[i + 2];
  186. (*image)[i + 2] = tmp;
  187. }
  188. break;
  189. default:
  190. ;
  191. }
  192. if (must_flip) {
  193. swap_row = new unsigned char [header.width * 4];
  194. for (i = 0, j = header.height-1; (int)i < header.height/2; i++, j--) {
  195. memcpy(swap_row, &(*image)[i*header.width*4], header.width*4);
  196. memcpy(&(*image)[i*header.width*4], &(*image)[j*header.width*4],
  197. header.width*4);
  198. memcpy(&(*image)[j*header.width*4], swap_row, header.width*4);
  199. }
  200. delete [] swap_row;
  201. }
  202. break;
  203. case 24:
  204. size *= 3;
  205. *image = new unsigned char [size];
  206. switch (header.image_type) {
  207. case TGA_TYPE__COLOR_RLE:
  208. for (i = 0; i < size;) {
  209. fread(&packet, 1, 1, f);
  210. if (packet & 0x80) { // Run Length
  211. packet = (packet &0x7F) + 1;
  212. fread(&pixel, 3, 1, f);
  213. for (j = 0; j < packet; j++) {
  214. (*image)[i++] = pixel[2];
  215. (*image)[i++] = pixel[1];
  216. (*image)[i++] = pixel[0];
  217. }
  218. } else { // RAW
  219. packet = (packet &0x7F) + 1;
  220. for (j = 0; j < packet; j++) {
  221. fread(&pixel, 3, 1, f);
  222. (*image)[i++] = pixel[2];
  223. (*image)[i++] = pixel[1];
  224. (*image)[i++] = pixel[0];
  225. }
  226. }
  227. }
  228. break;
  229. case TGA_TYPE__COLOR:
  230. if (fread((*image), size, 1, f) < 1) {
  231. fprintf(stderr, "tgaLoad> Image fread failed.\n");
  232. delete [] *image;
  233. fclose(f);
  234. return -4;
  235. }
  236. for (i = 0; i < size; i += 3) {
  237. tmp = (*image)[i];
  238. (*image)[i] = (*image)[i + 2];
  239. (*image)[i + 2] = tmp;
  240. }
  241. break;
  242. default:
  243. ;
  244. }
  245. if (must_flip) {
  246. swap_row = new unsigned char [header.width * 3];
  247. for (i = 0, j = header.height - 1; (int)i < header.height / 2; i++, j--) {
  248. memcpy(swap_row, &(*image)[i*header.width*3], header.width*3);
  249. memcpy(&(*image)[i*header.width*3], &(*image)[j*header.width*3],
  250. header.width*3);
  251. memcpy(&(*image)[j*header.width*3], swap_row, header.width*3);
  252. }
  253. delete [] swap_row;
  254. }
  255. break;
  256. case 8:
  257. printf("tgaLoad> 8bpp Not implemented\n");
  258. break;
  259. default:
  260. ;
  261. }
  262. #ifdef DEBUG_TGA
  263. char c;
  264. printf("TGA Comment: ");
  265. while (fread(&c, 1, 1, f) == 1) {
  266. printf("%c", c);
  267. }
  268. printf("\n");
  269. #endif
  270. fclose(f);
  271. return 0;
  272. }
  273. int tgaSave(const char *filename, unsigned char *image, unsigned int width, unsigned int height, char type) {
  274. tga_t header;
  275. unsigned int size;
  276. char comment[64];
  277. //unsigned int i;
  278. //unsigned char tmp;
  279. assert(filename != NULL);
  280. assert(filename[0] != '\0');
  281. assert(image != NULL);
  282. assert(width > 0);
  283. assert(height > 0);
  284. FILE *f = fopen(filename, "wb");
  285. if (!f) {
  286. printf("tgaSave> File not found\n");
  287. return -1;
  288. }
  289. strncpy(comment, "OpenRaider TGA", 63);
  290. comment[63] = 0;
  291. header.comment_lenght = (unsigned char)strlen(comment);
  292. header.colormap_type = 0;
  293. // No colormaps
  294. header.colormap_index = 0;
  295. header.colormap_lenght = 0;
  296. header.colormap_bbp = 0;
  297. header.origin_x = header.origin_y = 0;
  298. header.width = (unsigned short)width;
  299. header.height = (unsigned short)height;
  300. header.desc_flags = 0;
  301. switch (type) {
  302. case 4:
  303. header.image_type = TGA_TYPE__COLOR;
  304. header.desc_flags = 32;
  305. header.bpp = 32;
  306. break;
  307. case 2:
  308. header.bpp = 32;
  309. break;
  310. case 1:
  311. header.image_type = TGA_TYPE__GREYSCALE;
  312. header.bpp = 8;
  313. break;
  314. default:
  315. header.image_type = TGA_TYPE__COLOR;
  316. header.bpp = 24;
  317. }
  318. // Write TGA header
  319. fwrite(&header.comment_lenght, 1, 1, f);
  320. fwrite(&header.colormap_type, 1, 1, f);
  321. fwrite(&header.image_type, 1, 1, f);
  322. fwrite(&header.colormap_index, 2, 1, f);
  323. fwrite(&header.colormap_lenght, 2, 1, f);
  324. fwrite(&header.colormap_bbp, 1, 1, f);
  325. fwrite(&header.origin_x, 2, 1, f);
  326. fwrite(&header.origin_y, 2, 1, f);
  327. fwrite(&header.width, 2, 1, f);
  328. fwrite(&header.height, 2, 1, f);
  329. fwrite(&header.bpp, 1, 1, f);
  330. fwrite(&header.desc_flags, 1, 1, f);
  331. // Write comment
  332. fwrite(&comment, 1, header.comment_lenght, f);
  333. switch (header.bpp) {
  334. case 32:
  335. size = header.width * header.height * 4;
  336. //for (i = 0; i < size; i += 4)
  337. //{
  338. // tmp = image[i];
  339. // image[i] = image[i + 2];
  340. // image[i + 2] = tmp;
  341. //}
  342. break;
  343. case 24:
  344. size = header.width * header.height * 3;
  345. //for (i = 0; i < size; i += 3)
  346. //{
  347. // tmp = image[i];
  348. // image[i] = image[i + 2];
  349. // image[i + 2] = tmp;
  350. //}
  351. break;
  352. case 8:
  353. default:
  354. size = header.width * header.height;
  355. break;
  356. }
  357. // Write image data
  358. if (fwrite(image, size, 1, f) < 1) {
  359. perror("tgaSave> Disk write failed.\n");
  360. fclose(f);
  361. return -2;
  362. }
  363. fclose(f);
  364. return 0;
  365. }