textures, overlay images, libimago
[demo_prior] / libs / imago2 / src / file_tga.c
1 /*
2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2017 John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by 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 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 /* -- Targa (tga) module -- */
20
21 #include <string.h>
22 #include <stdlib.h>
23 #include "imago2.h"
24 #include "ftype_module.h"
25 #include "byteord.h"
26
27 enum {
28         IMG_NONE,
29         IMG_CMAP,
30         IMG_RGBA,
31         IMG_BW,
32
33         IMG_RLE_CMAP = 9,
34         IMG_RLE_RGBA,
35         IMG_RLE_BW
36 };
37
38 #define IS_RLE(x)       ((x) >= IMG_RLE_CMAP)
39 #define IS_RGBA(x)      ((x) == IMG_RGBA || (x) == IMG_RLE_RGBA)
40
41
42 struct tga_header {
43         uint8_t idlen;                  /* id field length */
44         uint8_t cmap_type;              /* color map type (0:no color map, 1:color map present) */
45         uint8_t img_type;               /* image type:
46                                                          * 0: no image data
47                                                          *      1: uncomp. color-mapped          9: RLE color-mapped
48                                                          *      2: uncomp. true color           10: RLE true color
49                                                          *      3: uncomp. black/white          11: RLE black/white */
50         uint16_t cmap_first;    /* color map first entry index */
51         uint16_t cmap_len;              /* color map length */
52         uint8_t cmap_entry_sz;  /* color map entry size */
53         uint16_t img_x;                 /* X-origin of the image */
54         uint16_t img_y;                 /* Y-origin of the image */
55         uint16_t img_width;             /* image width */
56         uint16_t img_height;    /* image height */
57         uint8_t img_bpp;                /* bits per pixel */
58         uint8_t img_desc;               /* descriptor:
59                                                          * bits 0 - 3: alpha or overlay bits
60                                                          * bits 5 & 4: origin (0 = bottom/left, 1 = top/right)
61                                                          * bits 7 & 6: data interleaving */
62 };
63
64 struct tga_footer {
65         uint32_t ext_off;               /* extension area offset */
66         uint32_t devdir_off;    /* developer directory offset */
67         char sig[18];                           /* signature with . and \0 */
68 };
69
70
71 static int check(struct img_io *io);
72 static int read_tga(struct img_pixmap *img, struct img_io *io);
73 static int write_tga(struct img_pixmap *img, struct img_io *io);
74 static int read_pixel(struct img_io *io, int rdalpha, unsigned char *pix);
75
76 int img_register_tga(void)
77 {
78         static struct ftype_module mod = {".tga:.targa", check, read_tga, write_tga};
79         return img_register_module(&mod);
80 }
81
82
83 static int check(struct img_io *io)
84 {
85         struct tga_footer foot;
86         int res = -1;
87         long pos = io->seek(0, SEEK_CUR, io->uptr);
88         io->seek(-18, SEEK_END, io->uptr);
89
90         if(io->read(foot.sig, 17, io->uptr) < 17) {
91                 io->seek(pos, SEEK_SET, io->uptr);
92                 return -1;
93         }
94
95         if(memcmp(foot.sig, "TRUEVISION-XFILE.", 17) == 0) {
96                 res = 0;
97         }
98         io->seek(pos, SEEK_SET, io->uptr);
99         return res;
100 }
101
102 static int iofgetc(struct img_io *io)
103 {
104         int c = 0;
105         return io->read(&c, 1, io->uptr) < 1 ? -1 : c;
106 }
107
108 static int read_tga(struct img_pixmap *img, struct img_io *io)
109 {
110         struct tga_header hdr;
111         unsigned long x, y;
112         int i, c;
113         int rle_mode = 0, rle_pix_left = 0;
114         int rdalpha;
115         int pixel_bytes;
116
117         /* read header */
118         hdr.idlen = iofgetc(io);
119         hdr.cmap_type = iofgetc(io);
120         hdr.img_type = iofgetc(io);
121         hdr.cmap_first = img_read_int16_le(io);
122         hdr.cmap_len = img_read_int16_le(io);
123         hdr.cmap_entry_sz = iofgetc(io);
124         hdr.img_x = img_read_int16_le(io);
125         hdr.img_y = img_read_int16_le(io);
126         hdr.img_width = img_read_int16_le(io);
127         hdr.img_height = img_read_int16_le(io);
128         hdr.img_bpp = iofgetc(io);
129         if((c = iofgetc(io)) == -1) {
130                 return -1;
131         }
132         hdr.img_desc = c;
133
134         if(!IS_RGBA(hdr.img_type)) {
135                 fprintf(stderr, "libimago: only true color tga images are supported\n");
136                 return -1;
137         }
138
139         io->seek(hdr.idlen, SEEK_CUR, io->uptr);        /* skip the image ID */
140
141         /* skip the color map if it exists */
142         if(hdr.cmap_type == 1) {
143                 io->seek(hdr.cmap_len * hdr.cmap_entry_sz / 8, SEEK_CUR, io->uptr);
144         }
145
146         x = hdr.img_width;
147         y = hdr.img_height;
148         rdalpha = hdr.img_desc & 0xf;
149         pixel_bytes = rdalpha ? 4 : 3;
150
151         if(img_set_pixels(img, x, y, rdalpha ? IMG_FMT_RGBA32 : IMG_FMT_RGB24, 0) == -1) {
152                 return -1;
153         }
154
155         for(i=0; i<y; i++) {
156                 unsigned char *ptr;
157                 int j, k;
158
159                 ptr = (unsigned char*)img->pixels + ((hdr.img_desc & 0x20) ? i : y - (i + 1)) * x * pixel_bytes;
160
161                 for(j=0; j<x; j++) {
162                         /* if the image is raw, then just read the next pixel */
163                         if(!IS_RLE(hdr.img_type)) {
164                                 if(read_pixel(io, rdalpha, ptr) == -1) {
165                                         return -1;
166                                 }
167                         } else {
168                                 /* otherwise, for RLE... */
169
170                                 /* if we have pixels left in the packet ... */
171                                 if(rle_pix_left) {
172                                         /* if it's a raw packet, read the next pixel, otherwise keep the same */
173                                         if(!rle_mode) {
174                                                 if(read_pixel(io, rdalpha, ptr) == -1) {
175                                                         return -1;
176                                                 }
177                                         } else {
178                                                 for(k=0; k<pixel_bytes; k++) {
179                                                         ptr[k] = ptr[k - pixel_bytes];
180                                                 }
181                                         }
182                                         --rle_pix_left;
183                                 } else {
184                                         /* read RLE packet header */
185                                         unsigned char phdr = iofgetc(io);
186                                         rle_mode = (phdr & 128);                /* last bit shows the mode for this packet (1: rle, 0: raw) */
187                                         rle_pix_left = (phdr & ~128);   /* the rest gives the count of pixels minus one (we also read one here, so no +1) */
188                                         /* and read the first pixel of the packet */
189                                         if(read_pixel(io, rdalpha, ptr) == -1) {
190                                                 return -1;
191                                         }
192                                 }
193                         }
194
195                         ptr += pixel_bytes;
196                 }
197         }
198
199         return 0;
200 }
201
202 static int write_tga(struct img_pixmap *img, struct img_io *io)
203 {
204         return -1;      /* TODO */
205 }
206
207 static int read_pixel(struct img_io *io, int rdalpha, unsigned char *pix)
208 {
209         int r, g, b, a;
210         if((b = iofgetc(io)) == -1 || (g = iofgetc(io)) == -1 || (r = iofgetc(io)) == -1) {
211                 return -1;
212         }
213
214         pix[0] = r;
215         pix[1] = g;
216         pix[2] = b;
217
218         if(rdalpha) {
219                 if((a = iofgetc(io)) == -1) {
220                         return -1;
221                 }
222                 pix[3] = a;
223         }
224         return 0;
225 }