Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.     IMGLIB:  An example image loading library for use with SDL
  3.     Copyright (C) 1999  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library 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 GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     5635-34 Springhouse Dr.
  21.     Pleasanton, CA 94588 (USA)
  22.     slouken@devolution.com
  23. */
  24.  
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28.  
  29. #include "SDL_endian.h"
  30.  
  31. #include "SDL_image.h"
  32.  
  33. #ifdef LOAD_TGA
  34.  
  35. /*
  36.  * A TGA loader for the SDL library
  37.  * Supports: Reading 8, 15, 16, 24 and 32bpp images, with alpha or colourkey,
  38.  *           uncompressed or RLE encoded.
  39.  *
  40.  * 2000-06-10 Mattias Engdegård <f91-men@nada.kth.se>: initial version
  41.  * 2000-06-26 Mattias Engdegård <f91-men@nada.kth.se>: read greyscale TGAs
  42.  * 2000-08-09 Mattias Engdegård <f91-men@nada.kth.se>: alpha inversion removed
  43.  */
  44.  
  45. struct TGAheader {
  46.     Uint8 infolen;              /* length of info field */
  47.     Uint8 has_cmap;             /* 1 if image has colormap, 0 otherwise */
  48.     Uint8 type;
  49.  
  50.     Uint8 cmap_start[2];        /* index of first colormap entry */
  51.     Uint8 cmap_len[2];          /* number of entries in colormap */
  52.     Uint8 cmap_bits;            /* bits per colormap entry */
  53.  
  54.     Uint8 yorigin[2];           /* image origin (ignored here) */
  55.     Uint8 xorigin[2];
  56.     Uint8 width[2];             /* image size */
  57.     Uint8 height[2];
  58.     Uint8 pixel_bits;           /* bits/pixel */
  59.     Uint8 flags;
  60. };
  61.  
  62. enum tga_type {
  63.     TGA_TYPE_INDEXED = 1,
  64.     TGA_TYPE_RGB = 2,
  65.     TGA_TYPE_BW = 3,
  66.     TGA_TYPE_RLE_INDEXED = 9,
  67.     TGA_TYPE_RLE_RGB = 10,
  68.     TGA_TYPE_RLE_BW = 11
  69. };
  70.  
  71. #define TGA_INTERLEAVE_MASK     0xc0
  72. #define TGA_INTERLEAVE_NONE     0x00
  73. #define TGA_INTERLEAVE_2WAY     0x40
  74. #define TGA_INTERLEAVE_4WAY     0x80
  75.  
  76. #define TGA_ORIGIN_MASK         0x30
  77. #define TGA_ORIGIN_LEFT         0x00
  78. #define TGA_ORIGIN_RIGHT        0x10
  79. #define TGA_ORIGIN_LOWER        0x00
  80. #define TGA_ORIGIN_UPPER        0x20
  81.  
  82. /* read/write unaligned little-endian 16-bit ints */
  83. #define LE16(p) ((p)[0] + ((p)[1] << 8))
  84. #define SETLE16(p, v) ((p)[0] = (v), (p)[1] = (v) >> 8)
  85.  
  86. static void unsupported(void)
  87. {
  88.     IMG_SetError("unsupported TGA format");
  89. }
  90.  
  91. /* Load a TGA type image from an SDL datasource */
  92. SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
  93. {
  94.     struct TGAheader hdr;
  95.     int rle = 0;
  96.     int alpha = 0;
  97.     int indexed = 0;
  98.     int grey = 0;
  99.     int ckey = -1;
  100.     int ncols, w, h;
  101.     SDL_Surface *img;
  102.     Uint32 rmask, gmask, bmask, amask;
  103.     Uint8 *dst;
  104.     int i;
  105.     int bpp;
  106.     int lstep;
  107.     Uint32 pixel;
  108.     int count, rep;
  109.  
  110.     if(!SDL_RWread(src, &hdr, sizeof(hdr), 1))
  111.         goto error;
  112.     ncols = LE16(hdr.cmap_len);
  113.     switch(hdr.type) {
  114.     case TGA_TYPE_RLE_INDEXED:
  115.         rle = 1;
  116.         /* fallthrough */
  117.     case TGA_TYPE_INDEXED:
  118.         if(!hdr.has_cmap || hdr.pixel_bits != 8 || ncols > 256)
  119.             goto error;
  120.         indexed = 1;
  121.         break;
  122.  
  123.     case TGA_TYPE_RLE_RGB:
  124.         rle = 1;
  125.         /* fallthrough */
  126.     case TGA_TYPE_RGB:
  127.         indexed = 0;
  128.         break;
  129.  
  130.     case TGA_TYPE_RLE_BW:
  131.         rle = 1;
  132.         /* fallthrough */
  133.     case TGA_TYPE_BW:
  134.         if(hdr.pixel_bits != 8)
  135.             goto error;
  136.         /* Treat greyscale as 8bpp indexed images */
  137.         indexed = grey = 1;
  138.         break;
  139.  
  140.     default:
  141.         unsupported();
  142.         return NULL;
  143.     }
  144.  
  145.     bpp = (hdr.pixel_bits + 7) >> 3;
  146.     rmask = gmask = bmask = amask = 0;
  147.     switch(hdr.pixel_bits) {
  148.     case 8:
  149.         if(!indexed) {
  150.             unsupported();
  151.             return NULL;
  152.         }
  153.         break;
  154.  
  155.     case 15:
  156.     case 16:
  157.         /* 15 and 16bpp both seem to use 5 bits/plane. The extra alpha bit
  158.            is ignored for now. */
  159.         rmask = 0x7c00;
  160.         gmask = 0x03e0;
  161.         bmask = 0x001f;
  162.         break;
  163.  
  164.     case 32:
  165.         alpha = 1;
  166.         /* fallthrough */
  167.     case 24:
  168.         if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
  169.             int s = alpha ? 0 : 8;
  170.             amask = 0x000000ff >> s;
  171.             rmask = 0x0000ff00 >> s;
  172.             gmask = 0x00ff0000 >> s;
  173.             bmask = 0xff000000 >> s;
  174.         } else {
  175.             amask = alpha ? 0xff000000 : 0;
  176.             rmask = 0x00ff0000;
  177.             gmask = 0x0000ff00;
  178.             bmask = 0x000000ff;
  179.         }
  180.         break;
  181.  
  182.     default:
  183.         unsupported();
  184.         return NULL;
  185.     }
  186.  
  187.     if((hdr.flags & TGA_INTERLEAVE_MASK) != TGA_INTERLEAVE_NONE
  188.        || hdr.flags & TGA_ORIGIN_RIGHT) {
  189.         unsupported();
  190.         return NULL;
  191.     }
  192.    
  193.     SDL_RWseek(src, hdr.infolen, SEEK_CUR); /* skip info field */
  194.  
  195.     w = LE16(hdr.width);
  196.     h = LE16(hdr.height);
  197.     img = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h,
  198.                                bpp * 8,
  199.                                rmask, gmask, bmask, amask);
  200.  
  201.     if(hdr.has_cmap) {
  202.         int palsiz = ncols * ((hdr.cmap_bits + 7) >> 3);
  203.         if(indexed && !grey) {
  204.             Uint8 *pal = malloc(palsiz), *p = pal;
  205.             SDL_Color *colors = img->format->palette->colors;
  206.             img->format->palette->ncolors = ncols;
  207.             SDL_RWread(src, pal, palsiz, 1);
  208.             for(i = 0; i < ncols; i++) {
  209.                 switch(hdr.cmap_bits) {
  210.                 case 15:
  211.                 case 16:
  212.                     {
  213.                         Uint16 c = p[0] + (p[1] << 8);
  214.                         p += 2;
  215.                         colors[i].r = (c >> 7) & 0xf8;
  216.                         colors[i].g = (c >> 2) & 0xf8;
  217.                         colors[i].b = c << 3;
  218.                     }
  219.                     break;
  220.                 case 24:
  221.                 case 32:
  222.                     colors[i].b = *p++;
  223.                     colors[i].g = *p++;
  224.                     colors[i].r = *p++;
  225.                     if(hdr.cmap_bits == 32 && *p++ < 128)
  226.                         ckey = i;
  227.                     break;
  228.                 }
  229.             }
  230.             free(pal);
  231.             if(ckey >= 0)
  232.                 SDL_SetColorKey(img, SDL_SRCCOLORKEY, ckey);
  233.         } else {
  234.             /* skip unneeded colormap */
  235.             SDL_RWseek(src, palsiz, SEEK_CUR);
  236.         }
  237.     }
  238.  
  239.     if(grey) {
  240.         SDL_Color *colors = img->format->palette->colors;
  241.         for(i = 0; i < 256; i++)
  242.             colors[i].r = colors[i].g = colors[i].b = i;
  243.         img->format->palette->ncolors = 256;
  244.     }
  245.  
  246.     if(hdr.flags & TGA_ORIGIN_UPPER) {
  247.         lstep = img->pitch;
  248.         dst = img->pixels;
  249.     } else {
  250.         lstep = -img->pitch;
  251.         dst = (Uint8 *)img->pixels + (h - 1) * img->pitch;
  252.     }
  253.  
  254.     /* The RLE decoding code is slightly convoluted since we can't rely on
  255.        spans not to wrap across scan lines */
  256.     count = rep = 0;
  257.     for(i = 0; i < h; i++) {
  258.         if(rle) {
  259.             int x = 0;
  260.             for(;;) {
  261.                 Uint8 c;
  262.  
  263.                 if(count) {
  264.                     int n = count;
  265.                     if(n > w - x)
  266.                         n = w - x;
  267.                     SDL_RWread(src, dst + x * bpp, n * bpp, 1);
  268.                     count -= n;
  269.                     x += n;
  270.                     if(x == w)
  271.                         break;
  272.                 } else if(rep) {
  273.                     int n = rep;
  274.                     if(n > w - x)
  275.                         n = w - x;
  276.                     rep -= n;
  277.                     while(n--) {
  278.                         memcpy(dst + x * bpp, &pixel, bpp);
  279.                         x++;
  280.                     }
  281.                     if(x == w)
  282.                         break;
  283.                 }
  284.  
  285.                 SDL_RWread(src, &c, 1, 1);
  286.                 if(c & 0x80) {
  287.                     SDL_RWread(src, &pixel, bpp, 1);
  288.                     rep = (c & 0x7f) + 1;
  289.                 } else {
  290.                     count = c + 1;
  291.                 }
  292.             }
  293.  
  294.         } else {
  295.             SDL_RWread(src, dst, w * bpp, 1);
  296.         }
  297.         if(SDL_BYTEORDER == SDL_BIG_ENDIAN && bpp == 2) {
  298.             /* swap byte order */
  299.             int x;
  300.             Uint16 *p = (Uint16 *)dst;
  301.             for(x = 0; x < w; x++)
  302.                 p[x] = SDL_Swap16(p[x]);
  303.         }
  304.         dst += lstep;
  305.     }
  306.     return img;
  307.  
  308. error:
  309.     IMG_SetError("Error reading TGA data");
  310.     return NULL;
  311. }
  312.  
  313. #else
  314.  
  315. /* dummy TGA load routine */
  316. SDL_Surface *IMG_LoadTGA_RW(SDL_RWops *src)
  317. {
  318.         return(NULL);
  319. }
  320.  
  321. #endif /* LOAD_TGA */
  322.