TARGA.CPP 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699
  1. /*
  2. ** Command & Conquer Red Alert(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /****************************************************************************
  19. *
  20. * C O N F I D E N T I A L --- W E S T W O O D S T U D I O S
  21. *
  22. *----------------------------------------------------------------------------
  23. *
  24. * FILE
  25. * targa.c
  26. *
  27. * DESCRIPTION
  28. * Targa Image File reader. (32-Bit protected mode)
  29. *
  30. * PROGRAMMER
  31. * Denzil E. Long, Jr.
  32. *
  33. * DATE
  34. * January 26, 1995
  35. *
  36. *----------------------------------------------------------------------------
  37. *
  38. * PUBLIC
  39. * OpenTarga - Open Targa image file.
  40. * CloseTarga - Close Targa image file.
  41. * LoadTarga - Load Targa image file.
  42. * XFlipTarga - X flip the image.
  43. * YFlipTarga - Y flip the image.
  44. *
  45. * PRIVATE
  46. * DecodeImageData - Decompress Targa image data.
  47. *
  48. ****************************************************************************/
  49. #include <stdio.h>
  50. #include <malloc.h>
  51. #include <mem.h>
  52. #include <io.h>
  53. #include <fcntl.h>
  54. #include <sys\stat.h>
  55. #include "targa.h"
  56. /* Private data declerations. */
  57. static long DecodeImageData(TGAHandle *, char *);
  58. static void InvertImageData(TGAHeader *, char *);
  59. /****************************************************************************
  60. *
  61. * NAME
  62. * OpenTarga - Open Targa image file.
  63. *
  64. * SYNOPSIS
  65. * TGAHandle = OpenTarga(Name, Mode)
  66. *
  67. * TGAHandle *OpenTarga(char *, unsigned short);
  68. *
  69. * FUNCTION
  70. * Open a Targa image file and read in its header. The file stream will
  71. * positioned after the ID field (if there is one).
  72. *
  73. * INPUTS
  74. * Name - Pointer to name of Targa file.
  75. * Mode - Access mode.
  76. *
  77. * RESULT
  78. * TGAHandle - Pointer to initialized TGAHandle or NULL if error.
  79. *
  80. ****************************************************************************/
  81. TGAHandle *OpenTarga(char *name, unsigned short mode)
  82. {
  83. TGAHandle *tga;
  84. long size;
  85. long error = 0;
  86. /* Allocate TGAHandle */
  87. if ((tga = (TGAHandle *)malloc(sizeof(TGAHandle))) != NULL) {
  88. /* Initialize TGAHandle structure. */
  89. memset((void *)tga, 0, sizeof(TGAHandle));
  90. tga->mode = mode;
  91. switch (mode) {
  92. /* Open targa file for read. */
  93. case TGA_READMODE:
  94. if ((tga->fh = open(name, (O_RDONLY|O_BINARY))) != -1) {
  95. /* Read in header. */
  96. size = read(tga->fh, &tga->header, sizeof(TGAHeader));
  97. if (size != sizeof(TGAHeader)) {
  98. error = 1;
  99. }
  100. /* Skip the ID field */
  101. if (!error && (tga->header.IDLength != 0)) {
  102. if (lseek(tga->fh, tga->header.IDLength, SEEK_CUR) == -1) {
  103. error = 1;
  104. }
  105. }
  106. } else {
  107. error = 1;
  108. }
  109. break;
  110. /* Open targa file for write. */
  111. case TGA_WRITEMODE:
  112. if ((tga->fh = open(name, (O_CREAT|O_TRUNC|O_WRONLY|O_BINARY),
  113. (S_IREAD|S_IWRITE))) == -1) {
  114. error = 1;
  115. } else {
  116. printf("\r");
  117. }
  118. break;
  119. /* Open targa file for read/write.*/
  120. case TGA_RDWRMODE:
  121. if ((tga->fh = open(name, (O_RDWR|O_BINARY),
  122. (S_IREAD|S_IWRITE))) != -1) {
  123. /* Read in header. */
  124. size = read(tga->fh, &tga->header, sizeof(TGAHeader));
  125. if (size != sizeof(TGAHeader)) {
  126. error = 1;
  127. }
  128. /* Skip the ID field */
  129. if (!error && (tga->header.IDLength != 0)) {
  130. if (lseek(tga->fh, tga->header.IDLength, SEEK_CUR) == -1) {
  131. error = 1;
  132. }
  133. }
  134. } else {
  135. error = 1;
  136. }
  137. break;
  138. }
  139. /* Close on any error! */
  140. if (error) {
  141. CloseTarga(tga);
  142. tga = NULL;
  143. }
  144. }
  145. return (tga);
  146. }
  147. /****************************************************************************
  148. *
  149. * NAME
  150. * CloseTarga - Close Targa image file.
  151. *
  152. * SYNOPSIS
  153. * CloseTarga(TGAHandle)
  154. *
  155. * void CloseTarga(TGAHandle *);
  156. *
  157. * FUNCTION
  158. * Close the Targa image file and free its handle.
  159. *
  160. * INPUTS
  161. * TGAHandle - Pointer to TGAHandle returned by OpenTarga().
  162. *
  163. * RESULT
  164. * NONE
  165. *
  166. ****************************************************************************/
  167. void CloseTarga(TGAHandle *tga)
  168. {
  169. /* Ensure valid handle. */
  170. if (tga) {
  171. /* Close the file if it is open. */
  172. if (tga->fh != -1) close(tga->fh);
  173. /* Free TGAHandle */
  174. free(tga);
  175. }
  176. }
  177. /****************************************************************************
  178. *
  179. * NAME
  180. * LoadTarga - Load Targa Image File.
  181. *
  182. * SYNOPSIS
  183. * Error = LoadTarga(Name, Palette, ImageBuffer)
  184. *
  185. * long LoadTarga(char *, char *, char *);
  186. *
  187. * FUNCTION
  188. * Open and load the Targa into the specified buffers. If either buffer
  189. * pointer is NULL then that field will not be processed.
  190. *
  191. * INPUTS
  192. * Name - Name of Targa image file to load.
  193. * Palette - Pointer to buffer to load the palette into.
  194. * ImageBuffer - Pointer to buffer to load the image data into.
  195. *
  196. * RESULT
  197. * Error - 0 if successful, or TGAERR_??? error code.
  198. *
  199. ****************************************************************************/
  200. long LoadTarga(char *name, char *palette, char *image)
  201. {
  202. TGAHandle *tga;
  203. long size;
  204. long depth;
  205. long i,n;
  206. char c;
  207. long error = 0;
  208. /* Open the Targa */
  209. if ((tga = OpenTarga(name, TGA_READMODE)) != NULL) {
  210. /* Process ColorMap (palette) */
  211. if (tga->header.ColorMapType == 1) {
  212. depth = (tga->header.CMapDepth >> 3);
  213. size = (tga->header.CMapLength * depth);
  214. /* Load the palette from the TGA if a palette buffer is provided
  215. * otherwise we will skip it.
  216. */
  217. if ((palette != NULL) && (tga->header.CMapLength > 0)) {
  218. /* Adjust palette to the starting color entry. */
  219. palette += (tga->header.CMapStart * depth);
  220. /* Read in the palette. */
  221. if (read(tga->fh, palette, size) == size) {
  222. /* Swap the byte ordering of the palette entries. */
  223. for (i = 0; i < tga->header.CMapLength; i++) {
  224. #if(0)
  225. for (n = 0; n < depth; n++) {
  226. c = *(palette + n);
  227. *(palette + n) = *(palette + ((depth - 1) - n));
  228. *(palette + ((depth - 1) - n)) = c;
  229. }
  230. #else
  231. c = *palette;
  232. *palette = *(palette + (depth - 1));
  233. *(palette + (depth - 1)) = c;
  234. #endif
  235. /* Next entry */
  236. palette += depth;
  237. }
  238. } else {
  239. error = TGAERR_READ;
  240. }
  241. } else {
  242. if (lseek(tga->fh, size, SEEK_CUR) == -1) {
  243. error = TGAERR_READ;
  244. }
  245. }
  246. }
  247. /* Load the image data from the TGA if an image buffer is provided
  248. * otherwise we are done.
  249. */
  250. if (!error && (image != NULL)) {
  251. depth = (tga->header.PixelDepth >> 3);
  252. size = ((tga->header.Width * tga->header.Height) * depth);
  253. switch (tga->header.ImageType) {
  254. case TGA_CMAPPED:
  255. if (read(tga->fh, image, size) != size) {
  256. error = TGAERR_READ;
  257. }
  258. break;
  259. case TGA_TRUECOLOR:
  260. if (read(tga->fh, image, size) == size) {
  261. InvertImageData(&tga->header, image);
  262. } else {
  263. error = TGAERR_READ;
  264. }
  265. break;
  266. case TGA_CMAPPED_ENCODED:
  267. error = DecodeImageData(tga, image);
  268. break;
  269. case TGA_TRUECOLOR_ENCODED:
  270. if ((error = DecodeImageData(tga, image)) == NULL) {
  271. InvertImageData(&tga->header, image);
  272. }
  273. break;
  274. default:
  275. error = TGAERR_NOTSUPPORTED;
  276. break;
  277. }
  278. /* Arrange the image so that the origin position (coordinate 0,0)
  279. * is the upperleft hand corner of the image.
  280. */
  281. if (!error) {
  282. if (tga->header.ImageDescriptor & TGAF_XORIGIN) {
  283. XFlipTarga(&tga->header, image);
  284. }
  285. if ((tga->header.ImageDescriptor & TGAF_YORIGIN) == 0) {
  286. YFlipTarga(&tga->header, image);
  287. }
  288. }
  289. }
  290. /* Close the Targa */
  291. CloseTarga(tga);
  292. } else {
  293. error = TGAERR_OPEN;
  294. }
  295. return (error);
  296. }
  297. /****************************************************************************
  298. *
  299. * NAME
  300. * SaveTarga - Save a Targa Image File.
  301. *
  302. * SYNOPSIS
  303. * Error = SaveTarga(Name, TGAHeader, Palette, ImageBuffer)
  304. *
  305. * long SaveTarga(char *, TGAHeader *, char *, char *);
  306. *
  307. * FUNCTION
  308. *
  309. * INPUTS
  310. * Name - Pointer to name of file to save.
  311. * TGAHeader - Pointer to initialized targa header structure.
  312. * Palette - Pointer to palette.
  313. * ImageBuffer - Pointer to raw image data.
  314. *
  315. * RESULT
  316. * Error - 0 if successful, or TGAERR_??? error code.
  317. *
  318. ****************************************************************************/
  319. long SaveTarga(char *name, TGAHeader *tgahd, char *palette, char *image)
  320. {
  321. TGAHandle *tga;
  322. long size;
  323. long depth;
  324. char *temppal;
  325. char *ptr;
  326. long i,n;
  327. char c;
  328. long error = 0;
  329. /* Open the Targa for write. */
  330. if ((tga = OpenTarga(name, TGA_WRITEMODE)) != NULL) {
  331. /* Write the header. */
  332. if (write(tga->fh, tgahd, sizeof(TGAHeader)) != sizeof(TGAHeader)) {
  333. error = TGAERR_WRITE;
  334. }
  335. /* Write the palette. */
  336. if (!error && (palette != NULL) && (tgahd->CMapLength > 0)) {
  337. /* Adjust palette to the starting color entry. */
  338. depth = (tgahd->CMapDepth >> 3);
  339. palette += (tgahd->CMapStart * depth);
  340. size = (tgahd->CMapLength * depth);
  341. /* Allocate temporary buffer for palette manipulation. */
  342. if ((temppal = (char *)malloc(size)) != NULL) {
  343. memcpy(temppal, palette, size);
  344. ptr = temppal;
  345. /* Swap the byte ordering of the palette entries. */
  346. for (i = 0; i < tga->header.CMapLength; i++) {
  347. for (n = 0; n < (depth >> 1); n++) {
  348. c = *(ptr + n);
  349. *(ptr + n) = *(ptr + (depth - n));
  350. *(ptr + (depth - n)) = c;
  351. }
  352. /* Next entry */
  353. palette += depth;
  354. }
  355. /* Write the palette. */
  356. if (write(tga->fh, temppal, size) != size) {
  357. error = TGAERR_WRITE;
  358. }
  359. /* Free temporary palette buffer. */
  360. free(temppal);
  361. } else {
  362. error = TGAERR_NOMEM;
  363. }
  364. }
  365. /* Invert truecolor data. */
  366. if (tgahd->ImageType == TGA_TRUECOLOR) {
  367. InvertImageData(tgahd, image);
  368. }
  369. /* Write the image. */
  370. if (!error && (image != NULL)) {
  371. depth = (tgahd->PixelDepth >> 3);
  372. size = (((tgahd->Width * tgahd->Height)) * depth);
  373. if (write(tga->fh, image, size) != size) {
  374. error = TGAERR_WRITE;
  375. }
  376. }
  377. /* Close targa file. */
  378. CloseTarga(tga);
  379. } else {
  380. error = TGAERR_OPEN;
  381. }
  382. return (error);
  383. }
  384. /****************************************************************************
  385. *
  386. * NAME
  387. * XFlipTarga - X flip the image.
  388. *
  389. * SYNOPSIS
  390. * XFlipTarga(TGAHeader, Image)
  391. *
  392. * void XFlipTarga(TGAHeader *, char *);
  393. *
  394. * FUNCTION
  395. * Flip the image in memory on its X axis. (left to right)
  396. *
  397. * INPUTS
  398. * TGAHeader - Pointer to initialized TGAHeader structure.
  399. * Image - Pointer to image buffer.
  400. *
  401. * RESULT
  402. * NONE
  403. *
  404. ****************************************************************************/
  405. void XFlipTarga(TGAHeader *tga, char *image)
  406. {
  407. char *ptr,*ptr1;
  408. long x,y,d;
  409. char v,v1;
  410. char depth;
  411. /* Pixel depth in bytes. */
  412. depth = (tga->PixelDepth >> 3);
  413. for (y = 0; y < tga->Height; y++) {
  414. ptr = (image + ((tga->Width * depth) * y));
  415. ptr1 = (ptr + ((tga->Width * depth) - depth));
  416. for (x = 0; x < (tga->Width / 2); x++) {
  417. for (d = 0; d < depth; d++) {
  418. v = *(ptr + d);
  419. v1 = *(ptr1 + d);
  420. *(ptr + d) = v1;
  421. *(ptr1 + d) = v;
  422. }
  423. ptr += depth;
  424. ptr1 -= depth;
  425. }
  426. }
  427. }
  428. /****************************************************************************
  429. *
  430. * NAME
  431. * YFlipTarga - Y flip the image.
  432. *
  433. * SYNOPSIS
  434. * YFlipTarga(TGAHeader, Image)
  435. *
  436. * void YFlipTarga(TGAHeader *, char *);
  437. *
  438. * FUNCTION
  439. * Flip the image in memory on its Y axis. (top to bottom)
  440. *
  441. * INPUTS
  442. * TGAHeader - Pointer to initialized TGAHeader structure.
  443. * Image - Pointer to image buffer.
  444. *
  445. * RESULT
  446. * NONE
  447. *
  448. ****************************************************************************/
  449. void YFlipTarga(TGAHeader *tga, char *image)
  450. {
  451. char *ptr,*ptr1;
  452. long x,y;
  453. char v,v1;
  454. char depth;
  455. /* Pixel depth in bytes. */
  456. depth = (tga->PixelDepth >> 3);
  457. for (y = 0; y < (tga->Height >> 1); y++) {
  458. /* Compute address of lines to exchange. */
  459. ptr = (image + ((tga->Width * y) * depth));
  460. ptr1 = (image + ((tga->Width * (tga->Height - 1)) * depth));
  461. ptr1 -= ((tga->Width * y) * depth);
  462. /* Exchange all the pixels on this scan line. */
  463. for (x = 0; x < (tga->Width * depth); x++) {
  464. v = *ptr;
  465. v1 = *ptr1;
  466. *ptr = v1;
  467. *ptr1 = v;
  468. ptr++;
  469. ptr1++;
  470. }
  471. }
  472. }
  473. /****************************************************************************
  474. *
  475. * NAME
  476. * DecodeImageData - Decompress Targa image data.
  477. *
  478. * SYNOPSIS
  479. * Error = DecodeImageData(TGAHandle, ImageBuffer)
  480. *
  481. * long DecodeImageData(TGAHandle *, char *);
  482. *
  483. * FUNCTION
  484. * Decode the RLE compressed image data into the specified buffer from
  485. * the file I/O stream.
  486. *
  487. * INPUTS
  488. * TGAHandle - Pointer to TGAHandle returned by OpenTarga().
  489. * ImageBuffer - Pointer to buffer to decompress image into.
  490. *
  491. * RESULT
  492. * Error - 0 if successful, or TGAERR_??? error code.
  493. *
  494. ****************************************************************************/
  495. static long DecodeImageData(TGAHandle *tga, char *image)
  496. {
  497. char *packet;
  498. unsigned char count;
  499. unsigned char depth;
  500. unsigned long pixel_count;
  501. unsigned long size;
  502. unsigned long c,i;
  503. long error = 0;
  504. /* Compute pixel depth in bytes. */
  505. depth = (tga->header.PixelDepth >> 3);
  506. /* Total number of pixels compressed in this image. */
  507. pixel_count = (tga->header.Width * tga->header.Height);
  508. /* Allocate packet buffer to hold maximum encoded data run. */
  509. if ((packet = (char *)malloc(128 * depth)) != NULL) {
  510. while ((pixel_count > 0) && !error) {
  511. /* Read count. */
  512. if (read(tga->fh, &count, 1) == 1) {
  513. /* If bit 8 of the count is set then we have a run of pixels,
  514. * otherwise the data is raw pixels.
  515. */
  516. if (count & 0x80) {
  517. count &= 0x7F;
  518. count++;
  519. /* Read in run pixel. */
  520. if (read(tga->fh, packet, depth) == depth) {
  521. /* Repeat the pixel for the run count in the image buffer. */
  522. for (c = 0; c < count; c++) {
  523. for (i = 0; i < depth; i++) {
  524. *image++ = *(packet + i);
  525. }
  526. }
  527. } else {
  528. error = TGAERR_READ;
  529. }
  530. } else {
  531. count++;
  532. size = (count * depth);
  533. /* Read in raw pixels. */
  534. if (read(tga->fh, packet, size) == size) {
  535. /* Copy the raw pixel data into the image buffer. */
  536. memcpy(image, packet, size);
  537. image += size;
  538. } else {
  539. error = TGAERR_READ;
  540. }
  541. }
  542. /* Adjust the pixel count. */
  543. pixel_count -= count;
  544. } else {
  545. error = TGAERR_READ;
  546. }
  547. }
  548. /* Free packet buffer. */
  549. free(packet);
  550. } else {
  551. error = TGAERR_NOMEM;
  552. }
  553. return (error);
  554. }
  555. /****************************************************************************
  556. *
  557. * NAME
  558. * InvertImageData - Invert TrueColor image data.
  559. *
  560. * SYNOPSIS
  561. * InvertImageData(TGAHeader, ImageData)
  562. *
  563. * void InvertImageData(TGAHeader *, char *);
  564. *
  565. * FUNCTION
  566. *
  567. * INPUTS
  568. * TGAHeader - Pointer to initialized TGAHeader structure.
  569. * ImageData - Pointer to TrueColor image data.
  570. *
  571. * RESULT
  572. * NONE
  573. *
  574. ****************************************************************************/
  575. static void InvertImageData(TGAHeader *tga, char *image)
  576. {
  577. long depth;
  578. long pixel_count;
  579. long i;
  580. char c;
  581. /* Compute the pixel depth in bytes. */
  582. depth = (tga->PixelDepth >> 3);
  583. /* Total number of pixels in this image. */
  584. pixel_count = (tga->Width * tga->Height);
  585. /* 16-bit pixel layout is different that 24-bit and 32-bit. */
  586. if (depth > 2) {
  587. while (pixel_count > 0) {
  588. for (i = 0; i < (depth / 2); i++) {
  589. c = *(image + i);
  590. *(image + i) = *(image + ((depth - 1) - i));
  591. *(image + ((depth - 1) - i)) = c;
  592. }
  593. /* Next pixel */
  594. pixel_count--;
  595. image += depth;
  596. }
  597. } else {
  598. }
  599. }