home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / gbmsrc.zip / gbmtga.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  17KB  |  723 lines

  1. /*
  2.  
  3. gbmtga.c - Truevision Targa/Vista support
  4.  
  5. Reads any uncompressed or runlength compresed type as 8 bit or 24 bit.
  6. Writes out only as 8 bit or 24 bit.
  7. Output options: 16,24,32, ydown,yup (default: 24 yup)
  8.  
  9. */
  10.  
  11. /*...sincludes:0:*/
  12. #include <stdio.h>
  13. #include <ctype.h>
  14. #include <stddef.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <memory.h>
  18. #include <malloc.h>
  19. #include "gbm.h"
  20. #include "gbmhelp.h"
  21.  
  22. /*...vgbm\46\h:0:*/
  23. /*...vgbmhelp\46\h:0:*/
  24. /*...e*/
  25.  
  26. /*...suseful:0:*/
  27. #define    low_byte(w)    ((byte)  (          (w)&0x00ff)    )
  28. #define    high_byte(w)    ((byte) (((unsigned)(w)&0xff00)>>8))
  29. #define    make_word(a,b)    (((word)a) + (((word)b) << 8))
  30. /*...e*/
  31.  
  32. static GBMFT tga_gbmft =
  33.     {
  34.     "Targa",
  35.     "Truevision Targa/Vista bitmap",
  36.     "TGA VST AFI",
  37.     GBM_FT_R8|GBM_FT_R24|
  38.     GBM_FT_W8|GBM_FT_W24,
  39.     };
  40.  
  41. #define    GBM_ERR_TGA_BAD_BPP    ((GBM_ERR) 400)
  42. #define    GBM_ERR_TGA_BAD_TYPE    ((GBM_ERR) 401)
  43. #define    GBM_ERR_TGA_BAD_PAL    ((GBM_ERR) 402)
  44.  
  45. /*...starga file header definition:0:*/
  46. /*
  47.  
  48. A Targa file is a header, followed by an identification string, followed by
  49. a color map, followed by the data for the image. Both the identification
  50. string and the color-map can be of zero length.
  51.  
  52. */
  53.  
  54. #define    TGA_NO_IMAGE    0        /* No image data included in file    */
  55. #define    TGA_UNCOMP_CM    1        /* Uncompressed, Color-Mapped (VDA/D */
  56.                     /* and Targa M-8 images)             */
  57. #define    TGA_UNCOMP_RGB    2        /* Uncompressed, RGB images (eg: ICB */
  58.                     /* Targa 16, 24 and 32)              */
  59. #define    TGA_UNCOMP_BW    3        /* Uncompressed, B/W images (eg:     */
  60.                     /* Targa 8 and Targa M-8 images)     */
  61. #define    TGA_RL_CM    9        /* Run-length, Color-Mapped (VDA/D   */
  62.                     /* and Targa M-8 images)             */
  63. #define    TGA_RL_RGB    10        /* Run-length, RGB images (eg: ICB   */
  64.                     /* Targa 16, 24 and 32)              */
  65. #define    TGA_RL_BW    11        /* Run-length, B/W images (eg: Targa */
  66.                     /* 8 and Targa M-8)                  */
  67. #define    TGA_COMP_CM    32        /* Compressed Color-Mapped (VDA/D)   */
  68.                     /* data using Huffman, Delta, and    */
  69.                     /* run length encoding               */
  70. #define    TGA_COMP_CM_4    33        /* Compressed Color-Mapped (VDA/D)   */
  71.                     /* data using Huffman, Delta, and    */
  72.                     /* run length encoding in 4 passes   */
  73.  
  74. #define    IDB_ATTRIBUTES    0x0f        /* How many attrib bits per pixel    */
  75.                     /* ie: 1 for T16, 8 for T32          */
  76. #define    IDB_ORIGIN    0x20        /* Origin in top left corner bit     */
  77.                     /* else its in bottom left corner    */
  78. #define    IDB_INTERLEAVE    0xc0        /* Interleave bits as defined below  */
  79. #define    IDB_NON_INT    0x00        /* Non-Interlaced                    */
  80. #define    IDB_2_WAY    0x40        /* 2 way (even/odd) interleaving     */
  81. #define    IDB_4_WAY    0x80        /* 4 way interleaving (eg: AT&T PC)  */
  82.  
  83. typedef struct
  84.     {
  85.     byte n_chars_in_id;        /* Length of identification text     */
  86.     byte color_map_present;        /* 0 means no, 1 yes                 */
  87.     byte image_type;        /* Type of image file, one of TGA_   */
  88.     byte color_map_start_low;    /* These 5 bytes are only valid if   */
  89.     byte color_map_start_high;    /* color_map_present is 1. They      */
  90.     byte color_map_length_low;    /* Specify the size of the color map */
  91.     byte color_map_length_high;    /* and where it starts from          */
  92.     byte color_map_entry_bits;    /* Bits per color map entry          */
  93.                     /* Typically 15, 16, 24 or 32        */
  94.     byte x_origin_low;
  95.     byte x_origin_high;
  96.     byte y_origin_low;
  97.     byte y_origin_high;
  98.     byte width_low;
  99.     byte width_high;
  100.     byte height_low;
  101.     byte height_high;
  102.     byte bpp;            /* Typically 16, 24 or 32            */
  103.     byte image_descriptor;        /* Split into IDB_ bits              */
  104.     } TGA_HEADER;
  105.  
  106. #define    SIZEOF_TGA_HEADER 18
  107. /*...e*/
  108. /*...sconverters:0:*/
  109. /*...st24_t32:0:*/
  110. static void t24_t32(byte *dest, const byte *src, int n)
  111.     {
  112.     while ( n-- )
  113.         {
  114.         *dest++ = *src++;
  115.         *dest++ = *src++;
  116.         *dest++ = *src++;
  117.         dest++;
  118.         }
  119.     }
  120. /*...e*/
  121. /*...st32_t24:0:*/
  122. static void t32_t24(byte *dest, const byte *src, int n)
  123.     {
  124.     while ( n-- )
  125.         {
  126.         *dest++ = *src++;
  127.         *dest++ = *src++;
  128.         *dest++ = *src++;
  129.         src++;
  130.         }
  131.     }
  132. /*...e*/
  133. /*...st24_t16:0:*/
  134. static void t24_t16(byte *dest, const byte *src, int n)
  135.     {
  136.     while ( n-- )
  137.         {
  138.         word    b = (word) (*src++ & 0xf8);
  139.         word    g = (word) (*src++ & 0xf8);
  140.         word    r = (word) (*src++ & 0xf8);
  141.         word    w;
  142.  
  143.         w = ((r << 7) | (g << 2) | (b >> 3));
  144.  
  145.         *dest++ = (byte)  w;
  146.         *dest++ = (byte) (w >> 8);
  147.         }
  148.     }
  149. /*...e*/
  150. /*...st16_t24:0:*/
  151. static void t16_t24(byte *dest, const byte *src, int n)
  152.     {
  153.     while ( n-- )
  154.         {
  155.         word l = *src++;
  156.         word h = *src++;
  157.         word w = l + (h << 8);
  158.  
  159.         *dest++ = (byte) ((w & 0x001fU) << 3);
  160.         *dest++ = (byte) ((w & 0x03e0U) >> 2);
  161.         *dest++ = (byte) ((w & 0x7c00U) >> 7);
  162.         }
  163.     }
  164. /*...e*/
  165. /*...e*/
  166. typedef struct
  167.     {
  168.     TGA_HEADER header;
  169.     } TGA_PRIV;
  170.  
  171. /*...stga_qft:0:*/
  172. GBM_ERR tga_qft(GBMFT *gbmft)
  173.     {
  174.     *gbmft = tga_gbmft;
  175.     return GBM_ERR_OK;
  176.     }
  177. /*...e*/
  178. /*...stga_rhdr:0:*/
  179. GBM_ERR tga_rhdr(const char *fn, int fd, GBM *gbm, const char *opt)
  180.     {
  181.     TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
  182.  
  183.     fn=fn; opt=opt; /* Suppress 'unref arg' compiler warnings */
  184.  
  185.     gbm_file_read(fd, (char *) &(priv->header), SIZEOF_TGA_HEADER);
  186.  
  187.     switch ( priv->header.image_type )
  188.         {
  189.         case TGA_RL_BW:
  190.         case TGA_UNCOMP_BW:
  191.             if ( priv->header.bpp != 8 )
  192.                 return GBM_ERR_TGA_BAD_BPP;
  193.             break;
  194.         case TGA_RL_CM:
  195.         case TGA_UNCOMP_CM:
  196.             if ( priv->header.bpp != 8 )
  197.                 return GBM_ERR_TGA_BAD_BPP;
  198.             if ( priv->header.color_map_entry_bits != 24 )
  199.                 return GBM_ERR_TGA_BAD_PAL;
  200.             break;
  201.         case TGA_RL_RGB:
  202.         case TGA_UNCOMP_RGB:
  203.             if ( priv->header.bpp != 16 &&
  204.                  priv->header.bpp != 24 &&
  205.                  priv->header.bpp != 32 )
  206.                 return GBM_ERR_TGA_BAD_BPP;
  207.             break;
  208.         default:
  209.             return GBM_ERR_TGA_BAD_TYPE;
  210.         }
  211.  
  212.     gbm->w = make_word(priv->header.width_low , priv->header.width_high );
  213.     gbm->h = make_word(priv->header.height_low, priv->header.height_high);
  214.  
  215.     if ( gbm->w <= 0 || gbm->h <= 0 )
  216.         return GBM_ERR_BAD_SIZE;
  217.  
  218.     gbm->bpp = ( priv->header.bpp == 8 ) ? 8 : 24;
  219.  
  220.     return GBM_ERR_OK;
  221.     }
  222. /*...e*/
  223. /*...stga_rpal:0:*/
  224. GBM_ERR tga_rpal(int fd, GBM *gbm, GBMRGB *gbmrgb)
  225.     {
  226.     TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
  227.  
  228.     switch ( priv->header.image_type )
  229.         {
  230. /*...sTGA_UNCOMP_BW\44\ TGA_RL_BW:16:*/
  231. case TGA_UNCOMP_BW:
  232. case TGA_RL_BW:
  233.     {
  234.     int i;
  235.     for (  i = 0; i < 0x100; i++ )
  236.         gbmrgb[i].b =
  237.         gbmrgb[i].g =
  238.         gbmrgb[i].r = (byte) i;
  239.     }
  240.     break;
  241. /*...e*/
  242. /*...sTGA_UNCOMP_CM\44\ TGA_RL_CM:16:*/
  243. case TGA_UNCOMP_CM:
  244. case TGA_RL_CM:
  245.     {
  246.     int color_map_start, color_map_length, i;
  247.  
  248.     gbm_file_lseek(fd, (long) (SIZEOF_TGA_HEADER+priv->header.n_chars_in_id), SEEK_SET);
  249.  
  250.     color_map_start  = make_word(priv->header.color_map_start_low , priv->header.color_map_start_high );
  251.     color_map_length = make_word(priv->header.color_map_length_low, priv->header.color_map_length_high);
  252.  
  253.     memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
  254.     for ( i = color_map_start; i < color_map_start + color_map_length; i++ )
  255.         {
  256.         byte b[3];
  257.  
  258.         if ( gbm_file_read(fd, (char *) b, 3) != 3 )
  259.             return GBM_ERR_READ;
  260.         gbmrgb[i].b = b[0];
  261.         gbmrgb[i].g = b[1];
  262.         gbmrgb[i].r = b[2];
  263.         }
  264.     }
  265.     break;
  266. /*...e*/
  267.         }
  268.  
  269.     return GBM_ERR_OK;
  270.     }
  271. /*...e*/
  272. /*...stga_rdata:0:*/
  273. GBM_ERR tga_rdata(int fd, GBM *gbm, byte *data)
  274.     {
  275.     TGA_PRIV *priv = (TGA_PRIV *) gbm->priv;
  276.     byte *p;
  277.     int i, stride;
  278.  
  279.     gbm_file_lseek(fd, (long) (SIZEOF_TGA_HEADER + priv->header.n_chars_in_id), SEEK_SET);
  280.  
  281.     if ( priv->header.color_map_present )
  282.         {
  283.         int color_map_length;
  284.         int bpp_pal = priv->header.color_map_entry_bits;
  285.             /* Valid values are 32, 24, 16 and sometimes 15 */
  286.  
  287.         if ( bpp_pal == 15 ) bpp_pal = 16;
  288.  
  289.         color_map_length = make_word(priv->header.color_map_length_low, priv->header.color_map_length_high);
  290.         gbm_file_lseek(fd, (long) ((color_map_length * bpp_pal) / 8L), SEEK_CUR);
  291.         }
  292.  
  293.     stride = ((gbm->w*gbm->bpp + 31) / 32) * 4;
  294.     p = data;
  295.     if ( (priv->header.image_descriptor & IDB_ORIGIN) != 0 )
  296.         {
  297.         p += (gbm->h-1) * stride;
  298.         stride = -stride;
  299.         }
  300.  
  301.     switch ( priv->header.image_type )
  302.         {
  303. /*...sTGA_RL_BW\44\ TGA_RL_CM\44\ TGA_RL_RGB:16:*/
  304. case TGA_RL_CM:
  305. case TGA_RL_BW:
  306. case TGA_RL_RGB:
  307.     {
  308.     AHEAD *ahead;
  309.     int x = 0, y = 0;
  310.     if ( (ahead = gbm_create_ahead(fd)) == NULL )
  311.         return GBM_ERR_MEM;
  312.     switch ( priv->header.bpp )
  313.         {
  314. /*...s8:32:*/
  315. case 8:
  316.     while ( y < gbm->h )
  317.         {
  318.         int i, cnt = gbm_read_ahead(ahead);
  319.         if ( cnt == -1 )
  320.             {
  321.             gbm_destroy_ahead(ahead);
  322.             return GBM_ERR_READ;
  323.             }
  324.         if ( cnt & 0x80 )
  325.             {
  326.             byte v = (byte) gbm_read_ahead(ahead);
  327.             for ( i = 0x80; i <= cnt; i++ )
  328.                 {
  329.                 data[x++] = v;
  330.                 if ( x == gbm->w )
  331.                     { x = 0; y++; data += stride; }
  332.                 }
  333.             }
  334.         else
  335.             for ( i = 0; i <= cnt; i++ )
  336.                 {
  337.                 data[x++] = (byte) gbm_read_ahead(ahead);
  338.                 if ( x == gbm->w )
  339.                     { x = 0; y++; data += stride; }
  340.                 }
  341.         }
  342.     break;
  343. /*...e*/
  344. /*...s16:32:*/
  345. /*
  346. We have 3 bytes per pixel in the data array, indexed by p.
  347. We will read 2 bytes per pixel into the right hand 2/3 of each line.
  348. Then we will expand leftwards to fill the full width afterwards.
  349. */
  350.  
  351. case 16:
  352.  
  353.     p += gbm->w;
  354.  
  355.     while ( y < gbm->h )
  356.         {
  357.         int i, cnt = gbm_read_ahead(ahead);
  358.         if ( cnt == -1 )
  359.             {
  360.             gbm_destroy_ahead(ahead);
  361.             return GBM_ERR_READ;
  362.             }
  363.         if ( cnt & 0x80 )
  364.             {
  365.             byte v1 = (byte) gbm_read_ahead(ahead);
  366.             byte v2 = (byte) gbm_read_ahead(ahead);
  367.             for ( i = 0x80; i <= cnt; i++ )
  368.                 {
  369.                 p[x++] = v1;
  370.                 p[x++] = v2;
  371.                 if ( x == gbm->w*2 )
  372.                     { x = 0; y++; p += stride; }
  373.                 }
  374.             }
  375.         else
  376.             for ( i = 0; i <= cnt; i++ )
  377.                 {
  378.                 p[x++] = (byte) gbm_read_ahead(ahead);
  379.                 p[x++] = (byte) gbm_read_ahead(ahead);
  380.                 if ( x == gbm->w*2 )
  381.                     { x = 0; y++; p += stride; }
  382.                 }
  383.         }
  384.  
  385.     if ( stride < 0 )
  386.         stride = -stride;
  387.     for ( y = 0, p = data; y < gbm->h; y++, p += stride )
  388.         t16_t24(p, p+gbm->w, gbm->w);
  389.  
  390.     break;
  391. /*...e*/
  392. /*...s24:32:*/
  393. case 24:
  394.     while ( y < gbm->h )
  395.         {
  396.         int i, cnt = gbm_read_ahead(ahead);
  397.         if ( cnt == -1 )
  398.             {
  399.             gbm_destroy_ahead(ahead);
  400.             return GBM_ERR_READ;
  401.             }
  402.         if ( cnt & 0x80 )
  403.             {
  404.             byte v1 = (byte) gbm_read_ahead(ahead);
  405.             byte v2 = (byte) gbm_read_ahead(ahead);
  406.             byte v3 = (byte) gbm_read_ahead(ahead);
  407.             for ( i = 0x80; i <= cnt; i++ )
  408.                 {
  409.                 p[x++] = v1;
  410.                 p[x++] = v2;
  411.                 p[x++] = v3;
  412.                 if ( x == gbm->w*3 )
  413.                     { x = 0; y++; p += stride; }
  414.                 }
  415.             }
  416.         else
  417.             for ( i = 0; i <= cnt; i++ )
  418.                 {
  419.                 p[x++] = (byte) gbm_read_ahead(ahead);
  420.                 p[x++] = (byte) gbm_read_ahead(ahead);
  421.                 p[x++] = (byte) gbm_read_ahead(ahead);
  422.                 if ( x == gbm->w*3 )
  423.                     { x = 0; y++; p += stride; }
  424.                 }
  425.         }
  426.     break;
  427. /*...e*/
  428. /*...s32:32:*/
  429. case 32:
  430.     while ( y < gbm->h )
  431.         {
  432.         int i, cnt = gbm_read_ahead(ahead);
  433.         if ( cnt == -1 )
  434.             {
  435.             gbm_destroy_ahead(ahead);
  436.             return GBM_ERR_READ;
  437.             }
  438.         if ( cnt & 0x80 )
  439.             {
  440.             byte v1 = (byte) gbm_read_ahead(ahead);
  441.             byte v2 = (byte) gbm_read_ahead(ahead);
  442.             byte v3 = (byte) gbm_read_ahead(ahead);
  443.             gbm_read_ahead(ahead); /* Discard alpha channel */
  444.             for ( i = 0x80; i <= cnt; i++ )
  445.                 {
  446.                 p[x++] = v1;
  447.                 p[x++] = v2;
  448.                 p[x++] = v3;
  449.                 if ( x == gbm->w*3 )
  450.                     { x = 0; y++; p += stride; }
  451.                 }
  452.             }
  453.         else
  454.             for ( i = 0; i <= cnt; i++ )
  455.                 {
  456.                 p[x++] = (byte) gbm_read_ahead(ahead);
  457.                 p[x++] = (byte) gbm_read_ahead(ahead);
  458.                 p[x++] = (byte) gbm_read_ahead(ahead);
  459.                 gbm_read_ahead(ahead); /* Discard alpha channel */
  460.                 if ( x == gbm->w*3 )
  461.                     { x = 0; y++; p += stride; }
  462.                 }
  463.         }
  464.     break;
  465. /*...e*/
  466.         }
  467.     gbm_destroy_ahead(ahead);
  468.     }
  469.     break;
  470. /*...e*/
  471. /*...sTGA_UNCOMP_BW\44\ TGA_UNCOMP_CM\44\ TGA_UNCOMP_RGB:16:*/
  472. case TGA_UNCOMP_BW:
  473. case TGA_UNCOMP_CM:
  474. case TGA_UNCOMP_RGB:
  475.     switch ( priv->header.bpp )
  476.         {
  477. /*...s8:32:*/
  478. case 8:
  479.     for ( i = 0; i < gbm->h; i++, p += stride )
  480.         if ( gbm_file_read(fd, p, gbm->w) != gbm->w )
  481.             return GBM_ERR_READ;
  482.     break;
  483. /*...e*/
  484. /*...s16:32:*/
  485. case 16:
  486.     for ( i = 0; i < gbm->h; i++, p += stride )
  487.         {
  488.         if ( gbm_file_read(fd, p+gbm->w, gbm->w * 2) != gbm->w * 2 )
  489.             return GBM_ERR_READ;
  490.         t16_t24(p, p+gbm->w, gbm->w);
  491.         }
  492.     break;
  493. /*...e*/
  494. /*...s24:32:*/
  495. case 24:
  496.     for ( i = 0; i < gbm->h; i++, p += stride )
  497.         if ( gbm_file_read(fd, p, gbm->w * 3) != gbm->w * 3 )
  498.             return GBM_ERR_READ;
  499.     break;
  500. /*...e*/
  501. /*...s32:32:*/
  502. case 32:
  503.     {
  504.     byte *linebuf;
  505.     if ( (linebuf = malloc((size_t) (gbm->w * 4))) == NULL )
  506.         return GBM_ERR_MEM;
  507.  
  508.     for ( i = 0; i < gbm->h; i++, p += stride )
  509.         {
  510.         if ( gbm_file_read(fd, linebuf, gbm->w * 4) != gbm->w * 4 )
  511.             {
  512.             free(linebuf);
  513.             return GBM_ERR_READ;
  514.             }
  515.         t32_t24(p, linebuf, gbm->w);
  516.         }
  517.  
  518.     free(linebuf);
  519.     }
  520.     break;
  521. /*...e*/
  522.         }
  523.     break;
  524. /*...e*/
  525.         }
  526.  
  527.     return GBM_ERR_OK;
  528.     }
  529. /*...e*/
  530. /*...stga_w:0:*/
  531. #define    SW3(a,b,c)    ((a)*4+(b)*2+(c))
  532.  
  533. GBM_ERR tga_w(const char *fn, int fd, const GBM *gbm, const GBMRGB *gbmrgb, const byte *data, const char *opt)
  534.     {
  535.     TGA_HEADER tga_header;
  536.     int i, stride, obpp;
  537.     const byte *p;
  538.     BOOLEAN o16   = ( gbm_find_word(opt, "16"   ) != NULL );
  539.     BOOLEAN o24   = ( gbm_find_word(opt, "24"   ) != NULL );
  540.     BOOLEAN o32   = ( gbm_find_word(opt, "32"   ) != NULL );
  541.     BOOLEAN yup   = ( gbm_find_word(opt, "yup"  ) != NULL );
  542.     BOOLEAN ydown = ( gbm_find_word(opt, "ydown") != NULL );
  543.  
  544.     fn=fn; /* Suppress 'unref arg' compiler warning */
  545.  
  546.     if ( gbm->bpp == 24 )
  547.         switch ( SW3(o16,o24,o32) )
  548.             {
  549.             case SW3(1,0,0):    obpp = 16;    break;
  550.             case SW3(0,0,0):
  551.             case SW3(0,1,0):    obpp = 24;    break;
  552.             case SW3(0,0,1):    obpp = 32;    break;
  553.             default:        return GBM_ERR_BAD_OPTION;
  554.             }
  555.     else
  556.         {
  557.         if ( o16 || o24 || o32 )
  558.             return GBM_ERR_BAD_OPTION;
  559.         obpp = 8;
  560.         }
  561.  
  562.     if ( yup && ydown )
  563.         return GBM_ERR_BAD_OPTION;
  564.  
  565.     tga_header.n_chars_in_id         = 0;
  566.     tga_header.image_type            = ( obpp == 8 ) ? TGA_UNCOMP_CM : TGA_UNCOMP_RGB;
  567.     tga_header.x_origin_low          = low_byte(0);
  568.     tga_header.x_origin_high         = high_byte(0);
  569.     tga_header.y_origin_low          = low_byte(0);
  570.     tga_header.y_origin_high         = high_byte(0);
  571.     tga_header.color_map_start_low   = low_byte(0);
  572.     tga_header.color_map_start_high  = high_byte(0);
  573.     if ( gbm->bpp == 8 )
  574.         {
  575.         tga_header.color_map_present     = (byte) 1;
  576.         tga_header.color_map_length_low  = low_byte(0x100);
  577.         tga_header.color_map_length_high = high_byte(0x100);
  578.         tga_header.color_map_entry_bits  = 24;
  579.         }
  580.     else
  581.         {
  582.         tga_header.color_map_present     = (byte) 0;
  583.         tga_header.color_map_length_low  = low_byte(0);
  584.         tga_header.color_map_length_high = high_byte(0);
  585.         tga_header.color_map_entry_bits  = 0;
  586.         }
  587.     tga_header.width_low             = low_byte(gbm->w);
  588.     tga_header.width_high            = high_byte(gbm->w);
  589.     tga_header.height_low            = low_byte(gbm->h);
  590.     tga_header.height_high           = high_byte(gbm->h);
  591.     tga_header.bpp                   = (byte) obpp;
  592.     tga_header.image_descriptor      = IDB_NON_INT;
  593.  
  594.     if ( ydown )
  595.         tga_header.image_descriptor |= IDB_ORIGIN;
  596.  
  597.     gbm_file_write(fd, (char *) &tga_header, SIZEOF_TGA_HEADER);
  598.  
  599.     switch ( obpp )
  600.         {
  601. /*...s8:16:*/
  602. case 8:
  603.     for ( i = 0; i < 0x100; i++ )
  604.         {
  605.         byte    b[3];
  606.  
  607.         b[0] = gbmrgb[i].b;
  608.         b[1] = gbmrgb[i].g;
  609.         b[2] = gbmrgb[i].r;
  610.         gbm_file_write(fd, b, 3);
  611.         }
  612.  
  613.     stride = ((gbm->w + 3) & ~3);
  614.     p = data;
  615.  
  616.     if ( ydown )
  617.         {
  618.         p += ((gbm->h - 1) * stride);
  619.         stride = -stride;
  620.         }
  621.  
  622.     for ( i = 0; i < gbm->h; i++ )
  623.         {
  624.         gbm_file_write(fd, p, gbm->w);
  625.         p += stride;
  626.         }
  627.     break;
  628. /*...e*/
  629. /*...s16:16:*/
  630. case 16:
  631.     {
  632.     byte    *linebuf;
  633.  
  634.     if ( (linebuf = malloc((size_t) (gbm->w * 2))) == NULL )
  635.         return GBM_ERR_MEM;
  636.  
  637.     stride = ((gbm->w * 3 + 3) & ~3);
  638.     p = data;
  639.  
  640.     if ( ydown )
  641.         {
  642.         p += ((gbm->h - 1) * stride);
  643.         stride = -stride;
  644.         }
  645.  
  646.     for ( i = 0; i < gbm->h; i++ )
  647.         {
  648.         t24_t16(linebuf, p, gbm->w);
  649.         gbm_file_write(fd, linebuf, gbm->w * 2);
  650.         p += stride;
  651.         }
  652.  
  653.     free(linebuf);
  654.     }
  655.     break;
  656. /*...e*/
  657. /*...s24:16:*/
  658. case 24:
  659.     stride = ((gbm->w * 3 + 3) & ~3);
  660.     p = data;
  661.  
  662.     if ( ydown )
  663.         {
  664.         p += ((gbm->h - 1) * stride);
  665.         stride = -stride;
  666.         }
  667.  
  668.     for ( i = 0; i < gbm->h; i++ )
  669.         {
  670.         gbm_file_write(fd, p, gbm->w * 3);
  671.         p += stride;
  672.         }
  673.     break;
  674. /*...e*/
  675. /*...s32:16:*/
  676. case 32:
  677.     {
  678.     byte    *linebuf;
  679.  
  680.     if ( (linebuf = malloc((size_t) (gbm->w * 4))) == NULL )
  681.         return GBM_ERR_MEM;
  682.  
  683.     stride = ((gbm->w * 3 + 3) & ~3);
  684.     p = data;
  685.  
  686.     if ( ydown )
  687.         {
  688.         p += ((gbm->h - 1) * stride);
  689.         stride = -stride;
  690.         }
  691.  
  692.     for ( i = 0; i < gbm->h; i++ )
  693.         {
  694.         t24_t32(linebuf, p, gbm->w);
  695.         gbm_file_write(fd, linebuf, gbm->w * 4);
  696.         p += stride;
  697.         }
  698.  
  699.     free(linebuf);
  700.     }
  701.     break;
  702. /*...e*/
  703.         }
  704.  
  705.     return GBM_ERR_OK;
  706.     }
  707. /*...e*/
  708. /*...stga_err:0:*/
  709. const char *tga_err(GBM_ERR rc)
  710.     {
  711.     switch ( (int) rc )
  712.         {
  713.         case GBM_ERR_TGA_BAD_BPP:
  714.             return "bits per pixel not 8, 16, 24 or 32";
  715.         case GBM_ERR_TGA_BAD_TYPE:
  716.             return "unsupported compression type for bits per pixel";
  717.         case GBM_ERR_TGA_BAD_PAL:
  718.             return "color map entry size not 24 bits per pixel";
  719.         }
  720.     return NULL;
  721.     }
  722. /*...e*/
  723.