Open Source Tomb Raider Engine
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mtk_tga.cpp 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. /*================================================================
  2. *
  3. * Project : Freyja
  4. * Author : Mongoose
  5. * Website : http://www.westga.edu/~stu7440/
  6. * Email : stu7440@westga.edu
  7. * Object :
  8. * License : GPL See file COPYING, also (C) 2000 Mongoose
  9. * Comments: TGA plug-in
  10. *
  11. * TODO: type should pass more info
  12. * 2 bits for RGBA | RGB | GREY
  13. * val for depth
  14. *
  15. * This file was generated using Mongoose's C++
  16. * template generator script. <stu7440@westga.edu>
  17. *
  18. *-- History ------------------------------------------------
  19. *
  20. * 2001-10-25:
  21. * Mongoose - support for screen origin bit
  22. *
  23. * 2000-10-15:
  24. * Mongoose - Created
  25. ================================================================*/
  26. #include <string.h>
  27. #include <stdarg.h>
  28. #include <mtk_tga.h>
  29. #ifdef DEBUG_MEMORY
  30. #include <memory_test.h>
  31. #endif
  32. int mtk_image__tga_check(FILE *f)
  33. {
  34. char buffer[10];
  35. if (!f)
  36. {
  37. perror("tga_check> Passed invalid file.\n");
  38. return -1;
  39. }
  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. {
  48. printf("tga_check> Inavlid or unknown TGA format.\n");
  49. return -2;
  50. }
  51. return 0;
  52. }
  53. int mtk_image__tga_load(FILE *f, unsigned char **image,
  54. unsigned int *width, unsigned int *height, char *type)
  55. {
  56. mtk_image_tga_t header;
  57. char comment[256];
  58. unsigned char pixel[4];
  59. unsigned char *swap_row = NULL;
  60. unsigned char tmp, packet;
  61. bool must_flip = 0;
  62. unsigned int size;
  63. unsigned int i, j;
  64. if (!f)
  65. {
  66. fprintf(stderr, "mtk_image__tga_load> Invalid parameters.\n");
  67. return -1;
  68. }
  69. fseek(f, 0, SEEK_SET);
  70. // Read TGA header
  71. fread(&header.comment_lenght, 1, 1, f);
  72. fread(&header.colormap_type, 1, 1, f);
  73. fread(&header.image_type, 1, 1, f);
  74. fread(&header.colormap_index, 2, 1, f);
  75. fread(&header.colormap_lenght, 2, 1, f);
  76. fread(&header.colormap_bbp, 1, 1, f);
  77. fread(&tmp, 1, 1, f);
  78. header.origin_x = tmp;
  79. fread(&tmp, 1, 1, f);
  80. header.origin_x += tmp * 256;
  81. fread(&tmp, 1, 1, f);
  82. header.origin_y = tmp;
  83. fread(&tmp, 1, 1, f);
  84. header.origin_y += tmp * 256;
  85. fread(&tmp, 1, 1, f);
  86. header.width = tmp;
  87. fread(&tmp, 1, 1, f);
  88. header.width += tmp * 256;
  89. fread(&tmp, 1, 1, f);
  90. header.height = tmp;
  91. fread(&tmp, 1, 1, f);
  92. header.height += tmp * 256;
  93. fread(&header.bpp, 1, 1, f);
  94. fread(&header.desc_flags, 1, 1, f);
  95. *width = header.width;
  96. *height = header.height;
  97. switch (header.bpp)
  98. {
  99. case 32:
  100. *type = 2;//32;
  101. break;
  102. case 24:
  103. *type = 1;//24;
  104. break;
  105. case 8:
  106. *type = 0;//8;
  107. break;
  108. default:
  109. *type = 0;
  110. }
  111. #ifdef DEBUG_TGA
  112. printf("TGA [%ix%i@%ibpp, %it, %ix, %iy, %uf]\n",
  113. header.width, header.height, header.bpp, header.image_type,
  114. header.origin_x, header.origin_y,
  115. header.desc_flags);
  116. #endif
  117. // Comments can be 0 - 255
  118. if (header.comment_lenght)
  119. {
  120. fread(&comment, 1, header.comment_lenght, f);
  121. for (i = 0; i < 255; ++i)
  122. {
  123. if (comment[i] > 32 && comment[i] < 127)
  124. {
  125. }
  126. else
  127. {
  128. comment[i] = 183; // print a dot for invalid text
  129. }
  130. }
  131. comment[255] = 0;
  132. printf("Comment: '%s'\n", comment);
  133. }
  134. size = header.width * header.height;
  135. if (!size || (!(header.colormap_type == 0 &&
  136. (header.image_type == 2 || header.image_type == 10))))
  137. {
  138. fprintf(stderr, "mtk_image__tga_load> Unknown image format.\n");
  139. return -2;
  140. }
  141. *image = NULL;
  142. // Mongoose: Added 'screen origin bit' support back here
  143. if (!(header.desc_flags & 32))
  144. {
  145. must_flip = true;
  146. }
  147. switch (header.bpp)
  148. {
  149. case 32:
  150. size *= 4;
  151. *image = new unsigned char [size];
  152. switch (header.image_type)
  153. {
  154. case TGA_TYPE__COLOR_RLE:
  155. for (i = 0; i < size;)
  156. {
  157. fread(&packet, 1, 1, f);
  158. if (packet & 0x80) // Run Lenght
  159. {
  160. packet = (packet &0x7F) + 1;
  161. fread(&pixel, 4, 1, f);
  162. for (j = 0; j < packet; j++)
  163. {
  164. (*image)[i++] = pixel[2];
  165. (*image)[i++] = pixel[1];
  166. (*image)[i++] = pixel[0];
  167. (*image)[i++] = pixel[3];
  168. }
  169. }
  170. else // RAW
  171. {
  172. packet = (packet &0x7F) + 1;
  173. for (j = 0; j < packet; j++)
  174. {
  175. fread(&pixel, 4, 1, f);
  176. (*image)[i++] = pixel[2];
  177. (*image)[i++] = pixel[1];
  178. (*image)[i++] = pixel[0];
  179. (*image)[i++] = pixel[3];
  180. }
  181. }
  182. }
  183. break;
  184. case TGA_TYPE__COLOR:
  185. if (fread((*image), size, 1, f) < 1)
  186. {
  187. fprintf(stderr, "mtk_image__tga_load> Image fread failed.\n");
  188. delete [] *image;
  189. return -4;
  190. }
  191. for (i = 0; i < size; i += 4)
  192. {
  193. tmp = (*image)[i];
  194. (*image)[i] = (*image)[i + 2];
  195. (*image)[i + 2] = tmp;
  196. }
  197. break;
  198. default:
  199. ;
  200. }
  201. if (must_flip)
  202. {
  203. swap_row = new unsigned char [header.width * 4];
  204. for (i = 0, j = header.height-1; (int)i < header.height/2; i++, j--)
  205. {
  206. memcpy(swap_row, &(*image)[i*header.width*4], header.width*4);
  207. memcpy(&(*image)[i*header.width*4], &(*image)[j*header.width*4],
  208. header.width*4);
  209. memcpy(&(*image)[j*header.width*4], swap_row, header.width*4);
  210. }
  211. delete [] swap_row;
  212. }
  213. break;
  214. case 24:
  215. size *= 3;
  216. *image = new unsigned char [size];
  217. switch (header.image_type)
  218. {
  219. case TGA_TYPE__COLOR_RLE:
  220. for (i = 0; i < size;)
  221. {
  222. fread(&packet, 1, 1, f);
  223. if (packet & 0x80) // Run Lenght
  224. {
  225. packet = (packet &0x7F) + 1;
  226. fread(&pixel, 3, 1, f);
  227. for (j = 0; j < packet; j++)
  228. {
  229. (*image)[i++] = pixel[2];
  230. (*image)[i++] = pixel[1];
  231. (*image)[i++] = pixel[0];
  232. }
  233. }
  234. else // RAW
  235. {
  236. packet = (packet &0x7F) + 1;
  237. for (j = 0; j < packet; j++)
  238. {
  239. fread(&pixel, 3, 1, f);
  240. (*image)[i++] = pixel[2];
  241. (*image)[i++] = pixel[1];
  242. (*image)[i++] = pixel[0];
  243. }
  244. }
  245. }
  246. break;
  247. case TGA_TYPE__COLOR:
  248. if (fread((*image), size, 1, f) < 1)
  249. {
  250. fprintf(stderr, "mtk_image__tga_load> Image fread failed.\n");
  251. delete [] *image;
  252. return -4;
  253. }
  254. for (i = 0; i < size; i += 3)
  255. {
  256. tmp = (*image)[i];
  257. (*image)[i] = (*image)[i + 2];
  258. (*image)[i + 2] = tmp;
  259. }
  260. break;
  261. default:
  262. ;
  263. }
  264. if (must_flip)
  265. {
  266. swap_row = new unsigned char [header.width * 3];
  267. for (i = 0, j = header.height - 1; (int)i < header.height / 2; i++, j--)
  268. {
  269. memcpy(swap_row, &(*image)[i*header.width*3], header.width*3);
  270. memcpy(&(*image)[i*header.width*3], &(*image)[j*header.width*3],
  271. header.width*3);
  272. memcpy(&(*image)[j*header.width*3], swap_row, header.width*3);
  273. }
  274. delete [] swap_row;
  275. }
  276. break;
  277. case 8:
  278. printf("tga_load> 8bpp Not implemented\n");
  279. break;
  280. default:
  281. ;
  282. }
  283. #ifdef DEBUG_TGA
  284. char c;
  285. printf("Comment:\n");
  286. while (fread(&c, 1, 1, f) == 1)
  287. {
  288. printf("%c", c);
  289. }
  290. printf("\n");
  291. #endif
  292. return 0;
  293. }
  294. int mtk_image__tga_save(FILE *f, unsigned char *image,
  295. unsigned int width, unsigned int height, char type)
  296. {
  297. mtk_image_tga_t header;
  298. unsigned int size;
  299. // unsigned int i;
  300. // unsigned char tmp;
  301. char comment[64];
  302. if (!f || !image || !width || !height)
  303. {
  304. fprintf(stderr, "mtk_image__tga_save> Invalid parameters.\n");
  305. return -1;
  306. }
  307. // Mongoose 2002.01.10, Heh, kind of silly
  308. strncpy(comment, "Mongoose TGA 20030711", 63);
  309. comment[63] = 0;
  310. header.comment_lenght = strlen(comment);
  311. header.colormap_type = 0;
  312. // No colormaps
  313. header.colormap_index = 0;
  314. header.colormap_lenght = 0;
  315. header.colormap_bbp = 0;
  316. header.origin_x = header.origin_y = 0;
  317. header.width = width;
  318. header.height = height;
  319. header.desc_flags = 0;
  320. switch (type)
  321. {
  322. case 4:
  323. header.image_type = TGA_TYPE__COLOR;
  324. header.desc_flags = 32;
  325. case 2:
  326. header.bpp = 32;
  327. break;
  328. case 1:
  329. header.image_type = TGA_TYPE__GREYSCALE;
  330. header.bpp = 8;
  331. break;
  332. default:
  333. header.image_type = TGA_TYPE__COLOR;
  334. header.bpp = 24;
  335. }
  336. // Write TGA header
  337. fwrite(&header.comment_lenght, 1, 1, f);
  338. fwrite(&header.colormap_type, 1, 1, f);
  339. fwrite(&header.image_type, 1, 1, f);
  340. fwrite(&header.colormap_index, 2, 1, f);
  341. fwrite(&header.colormap_lenght, 2, 1, f);
  342. fwrite(&header.colormap_bbp, 1, 1, f);
  343. fwrite(&header.origin_x, 2, 1, f);
  344. fwrite(&header.origin_y, 2, 1, f);
  345. fwrite(&header.width, 2, 1, f);
  346. fwrite(&header.height, 2, 1, f);
  347. fwrite(&header.bpp, 1, 1, f);
  348. fwrite(&header.desc_flags, 1, 1, f);
  349. // Write comment
  350. fwrite(&comment, 1, header.comment_lenght, f);
  351. size = header.width * header.height;
  352. switch (header.bpp)
  353. {
  354. case 32:
  355. size = header.width * header.height * 4;
  356. //for (i = 0; i < size; i += 4)
  357. //{
  358. // tmp = image[i];
  359. // image[i] = image[i + 2];
  360. // image[i + 2] = tmp;
  361. //}
  362. break;
  363. case 24:
  364. size = header.width * header.height * 3;
  365. //for (i = 0; i < size; i += 3)
  366. //{
  367. // tmp = image[i];
  368. // image[i] = image[i + 2];
  369. // image[i + 2] = tmp;
  370. //}
  371. break;
  372. case 8:
  373. size = header.width * header.height;
  374. break;
  375. }
  376. // Write image data
  377. if (fwrite(image, size, 1, f) < 1)
  378. {
  379. perror("mtk_image__tga_save> Disk write failed.\n");
  380. return -2;
  381. }
  382. return 0;
  383. }
  384. int mtk_image__tga_save_filename(unsigned char *image,
  385. unsigned int width, unsigned int height,
  386. char type,
  387. char *s, ...)
  388. {
  389. char buffer[1024];
  390. FILE *f;
  391. int v;
  392. va_list args;
  393. va_start(args, s);
  394. vsnprintf(buffer, 1023, s, args);
  395. va_end(args);
  396. f = fopen(buffer, "wb");
  397. if (!f)
  398. {
  399. perror(buffer);
  400. return -1;
  401. }
  402. v = mtk_image__tga_save(f, image, width, height, type);
  403. fclose(f);
  404. return v;
  405. }
  406. #ifdef UNIT_TEST_TGA
  407. int main(int argc, char *argv[])
  408. {
  409. FILE *f;
  410. unsigned char *image;
  411. unsigned int width;
  412. unsigned int height;
  413. char type;
  414. if (argc > 1)
  415. {
  416. f = fopen(argv[1], "r");
  417. if (!f)
  418. {
  419. perror("Failed to open file> ");
  420. return -1;
  421. }
  422. if (!mtk_image__tga_check(f))
  423. {
  424. if (!mtk_image__tga_load(f, &image, &width, &height, &type))
  425. {
  426. printf("Loaded %s successfully!\n", argv[1]);
  427. delete [] image;
  428. }
  429. }
  430. fclose(f);
  431. } else {
  432. printf("Usage: %s testfile.tga\n", argv[0]);
  433. }
  434. return 0;
  435. }
  436. #endif