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