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

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