1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #include "tga.h"
23
24 #include "ifilesystem.h"
25 #include "iarchive.h"
26 #include "idatastream.h"
27
28 typedef unsigned char byte;
29
30 #include <stdlib.h>
31
32 #include "generic/bitfield.h"
33 #include "imagelib.h"
34 #include "bytestreamutils.h"
35
36 // represents x,y origin of tga image being decoded
37 class Flip00 {}; // no flip
38 class Flip01 {}; // vertical flip only
39 class Flip10 {}; // horizontal flip only
40 class Flip11 {}; // both
41
42 template<typename PixelDecoder>
image_decode(PointerInputStream & istream,PixelDecoder & decode,RGBAImage & image,const Flip00 &)43 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip00&)
44 {
45 RGBAPixel* end = image.pixels + (image.height * image.width);
46 for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
47 {
48 for(RGBAPixel* pixel = row - image.width; pixel != row; ++pixel)
49 {
50 decode(istream, *pixel);
51 }
52 }
53 }
54
55 template<typename PixelDecoder>
image_decode(PointerInputStream & istream,PixelDecoder & decode,RGBAImage & image,const Flip01 &)56 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip01&)
57 {
58 RGBAPixel* end = image.pixels + (image.height * image.width);
59 for(RGBAPixel* row = image.pixels; row != end; row += image.width)
60 {
61 for(RGBAPixel* pixel = row; pixel != row + image.width; ++pixel)
62 {
63 decode(istream, *pixel);
64 }
65 }
66 }
67
68 template<typename PixelDecoder>
image_decode(PointerInputStream & istream,PixelDecoder & decode,RGBAImage & image,const Flip10 &)69 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip10&)
70 {
71 RGBAPixel* end = image.pixels + (image.height * image.width);
72 for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
73 {
74 for(RGBAPixel* pixel = row; pixel != row - image.width;)
75 {
76 decode(istream, *--pixel);
77 }
78 }
79 }
80
81 template<typename PixelDecoder>
image_decode(PointerInputStream & istream,PixelDecoder & decode,RGBAImage & image,const Flip11 &)82 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip11&)
83 {
84 RGBAPixel* end = image.pixels + (image.height * image.width);
85 for(RGBAPixel* row = image.pixels; row != end; row += image.width)
86 {
87 for(RGBAPixel* pixel = row + image.width; pixel != row;)
88 {
89 decode(istream, *--pixel);
90 }
91 }
92 }
93
istream_read_gray(PointerInputStream & istream,RGBAPixel & pixel)94 inline void istream_read_gray(PointerInputStream& istream, RGBAPixel& pixel)
95 {
96 istream.read(&pixel.blue, 1);
97 pixel.red = pixel.green = pixel.blue;
98 pixel.alpha = 0xff;
99 }
100
istream_read_rgb(PointerInputStream & istream,RGBAPixel & pixel)101 inline void istream_read_rgb(PointerInputStream& istream, RGBAPixel& pixel)
102 {
103 istream.read(&pixel.blue, 1);
104 istream.read(&pixel.green, 1);
105 istream.read(&pixel.red, 1);
106 pixel.alpha = 0xff;
107 }
108
istream_read_rgba(PointerInputStream & istream,RGBAPixel & pixel)109 inline void istream_read_rgba(PointerInputStream& istream, RGBAPixel& pixel)
110 {
111 istream.read(&pixel.blue, 1);
112 istream.read(&pixel.green, 1);
113 istream.read(&pixel.red, 1);
114 istream.read(&pixel.alpha, 1);
115 }
116
117 class TargaDecodeGrayPixel
118 {
119 public:
operator ()(PointerInputStream & istream,RGBAPixel & pixel)120 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
121 {
122 istream_read_gray(istream, pixel);
123 }
124 };
125
126 template<typename Flip>
targa_decode_grayscale(PointerInputStream & istream,RGBAImage & image,const Flip & flip)127 void targa_decode_grayscale(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
128 {
129 TargaDecodeGrayPixel decode;
130 image_decode(istream, decode, image, flip);
131 }
132
133 class TargaDecodeRGBPixel
134 {
135 public:
operator ()(PointerInputStream & istream,RGBAPixel & pixel)136 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
137 {
138 istream_read_rgb(istream, pixel);
139 }
140 };
141
142 template<typename Flip>
targa_decode_rgb(PointerInputStream & istream,RGBAImage & image,const Flip & flip)143 void targa_decode_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
144 {
145 TargaDecodeRGBPixel decode;
146 image_decode(istream, decode, image, flip);
147 }
148
149 class TargaDecodeRGBAPixel
150 {
151 public:
operator ()(PointerInputStream & istream,RGBAPixel & pixel)152 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
153 {
154 istream_read_rgba(istream, pixel);
155 }
156 };
157
158 template<typename Flip>
targa_decode_rgba(PointerInputStream & istream,RGBAImage & image,const Flip & flip)159 void targa_decode_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
160 {
161 TargaDecodeRGBAPixel decode;
162 image_decode(istream, decode, image, flip);
163 }
164
165 typedef byte TargaPacket;
166 typedef byte TargaPacketSize;
167
targa_packet_read_istream(TargaPacket & packet,PointerInputStream & istream)168 inline void targa_packet_read_istream(TargaPacket& packet, PointerInputStream& istream)
169 {
170 istream.read(&packet, 1);
171 }
172
targa_packet_is_rle(const TargaPacket & packet)173 inline bool targa_packet_is_rle(const TargaPacket& packet)
174 {
175 return (packet & 0x80) != 0;
176 }
177
targa_packet_size(const TargaPacket & packet)178 inline TargaPacketSize targa_packet_size(const TargaPacket& packet)
179 {
180 return 1 + (packet & 0x7f);
181 }
182
183
184 class TargaDecodeRGBPixelRLE
185 {
186 TargaPacketSize m_packetSize;
187 RGBAPixel m_pixel;
188 TargaPacket m_packet;
189 public:
TargaDecodeRGBPixelRLE()190 TargaDecodeRGBPixelRLE() : m_packetSize(0)
191 {
192 }
operator ()(PointerInputStream & istream,RGBAPixel & pixel)193 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
194 {
195 if(m_packetSize == 0)
196 {
197 targa_packet_read_istream(m_packet, istream);
198 m_packetSize = targa_packet_size(m_packet);
199
200 if(targa_packet_is_rle(m_packet))
201 {
202 istream_read_rgb(istream, m_pixel);
203 }
204 }
205
206 if(targa_packet_is_rle(m_packet))
207 {
208 pixel = m_pixel;
209 }
210 else
211 {
212 istream_read_rgb(istream, pixel);
213 }
214
215 --m_packetSize;
216 }
217 };
218
219 template<typename Flip>
targa_decode_rle_rgb(PointerInputStream & istream,RGBAImage & image,const Flip & flip)220 void targa_decode_rle_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
221 {
222 TargaDecodeRGBPixelRLE decode;
223 image_decode(istream, decode, image, flip);
224 }
225
226 class TargaDecodeRGBAPixelRLE
227 {
228 TargaPacketSize m_packetSize;
229 RGBAPixel m_pixel;
230 TargaPacket m_packet;
231 public:
TargaDecodeRGBAPixelRLE()232 TargaDecodeRGBAPixelRLE() : m_packetSize(0)
233 {
234 }
operator ()(PointerInputStream & istream,RGBAPixel & pixel)235 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
236 {
237 if(m_packetSize == 0)
238 {
239 targa_packet_read_istream(m_packet, istream);
240 m_packetSize = targa_packet_size(m_packet);
241
242 if(targa_packet_is_rle(m_packet))
243 {
244 istream_read_rgba(istream, m_pixel);
245 }
246 }
247
248 if(targa_packet_is_rle(m_packet))
249 {
250 pixel = m_pixel;
251 }
252 else
253 {
254 istream_read_rgba(istream, pixel);
255 }
256
257 --m_packetSize;
258 }
259 };
260
261 template<typename Flip>
targa_decode_rle_rgba(PointerInputStream & istream,RGBAImage & image,const Flip & flip)262 void targa_decode_rle_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
263 {
264 TargaDecodeRGBAPixelRLE decode;
265 image_decode(istream, decode, image, flip);
266 }
267
268 struct TargaHeader
269 {
270 unsigned char id_length, colormap_type, image_type;
271 unsigned short colormap_index, colormap_length;
272 unsigned char colormap_size;
273 unsigned short x_origin, y_origin, width, height;
274 unsigned char pixel_size, attributes;
275 };
276
targa_header_read_istream(TargaHeader & targa_header,PointerInputStream & istream)277 inline void targa_header_read_istream(TargaHeader& targa_header, PointerInputStream& istream)
278 {
279 targa_header.id_length = istream_read_byte(istream);
280 targa_header.colormap_type = istream_read_byte(istream);
281 targa_header.image_type = istream_read_byte(istream);
282
283 targa_header.colormap_index = istream_read_int16_le(istream);
284 targa_header.colormap_length = istream_read_int16_le(istream);
285 targa_header.colormap_size = istream_read_byte(istream);
286 targa_header.x_origin = istream_read_int16_le(istream);
287 targa_header.y_origin = istream_read_int16_le(istream);
288 targa_header.width = istream_read_int16_le(istream);
289 targa_header.height = istream_read_int16_le(istream);
290 targa_header.pixel_size = istream_read_byte(istream);
291 targa_header.attributes = istream_read_byte(istream);
292
293 if (targa_header.id_length != 0)
294 istream.seek(targa_header.id_length); // skip TARGA image comment
295 }
296
297 template<typename Type>
298 class ScopeDelete
299 {
300 Type* m_value;
301 ScopeDelete(const ScopeDelete&);
302 ScopeDelete& operator=(const ScopeDelete&);
303 public:
ScopeDelete(Type * value)304 ScopeDelete(Type* value) : m_value(value)
305 {
306 }
~ScopeDelete()307 ~ScopeDelete()
308 {
309 delete m_value;
310 }
get_pointer() const311 Type* get_pointer() const
312 {
313 return m_value;
314 }
315 };
316
317 template<typename Flip>
Targa_decodeImageData(const TargaHeader & targa_header,PointerInputStream & istream,const Flip & flip)318 Image* Targa_decodeImageData(const TargaHeader& targa_header, PointerInputStream& istream, const Flip& flip)
319 {
320 RGBAImage* image = new RGBAImage(targa_header.width, targa_header.height);
321
322 if (targa_header.image_type == 2 || targa_header.image_type == 3)
323 {
324 switch (targa_header.pixel_size)
325 {
326 case 8:
327 targa_decode_grayscale(istream, *image, flip);
328 break;
329 case 24:
330 targa_decode_rgb(istream, *image, flip);
331 break;
332 case 32:
333 targa_decode_rgba(istream, *image, flip);
334 break;
335 default:
336 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
337 image->release();
338 return 0;
339 }
340 }
341 else if (targa_header.image_type == 10)
342 {
343 switch (targa_header.pixel_size)
344 {
345 case 24:
346 targa_decode_rle_rgb(istream, *image, flip);
347 break;
348 case 32:
349 targa_decode_rle_rgba(istream, *image, flip);
350 break;
351 default:
352 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
353 image->release();
354 return 0;
355 }
356 }
357
358 return image;
359 }
360
361 const unsigned int TGA_FLIP_HORIZONTAL = 0x10;
362 const unsigned int TGA_FLIP_VERTICAL = 0x20;
363
LoadTGABuff(const byte * buffer)364 Image* LoadTGABuff(const byte* buffer)
365 {
366 PointerInputStream istream(buffer);
367 TargaHeader targa_header;
368
369 targa_header_read_istream(targa_header, istream);
370
371 if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)
372 {
373 globalErrorStream() << "LoadTGA: TGA type " << targa_header.image_type << " not supported\n";
374 globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), and 10 (RGB) TGA images supported\n";
375 return 0;
376 }
377
378 if (targa_header.colormap_type != 0)
379 {
380 globalErrorStream() << "LoadTGA: colormaps not supported\n";
381 return 0;
382 }
383
384 if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)
385 && targa_header.image_type != 3)
386 {
387 globalErrorStream() << "LoadTGA: Only 32 or 24 bit images supported\n";
388 return 0;
389 }
390
391 if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
392 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
393 {
394 return Targa_decodeImageData(targa_header, istream, Flip00());
395 }
396 if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
397 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
398 {
399 return Targa_decodeImageData(targa_header, istream, Flip01());
400 }
401 if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
402 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
403 {
404 return Targa_decodeImageData(targa_header, istream, Flip10());
405 }
406 if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
407 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
408 {
409 return Targa_decodeImageData(targa_header, istream, Flip11());
410 }
411
412 // unreachable
413 return 0;
414 }
415
LoadTGA(ArchiveFile & file)416 Image* LoadTGA(ArchiveFile& file)
417 {
418 ScopedArchiveBuffer buffer(file);
419 return LoadTGABuff(buffer.buffer);
420 }
421