2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
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.
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.
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
24 #include "ifilesystem.h"
26 #include "idatastream.h"
28 typedef unsigned char byte;
32 #include "generic/bitfield.h"
34 #include "bytestreamutils.h"
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
42 template<typename PixelDecoder>
43 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip00&)
45 RGBAPixel* end = image.pixels + (image.height * image.width);
46 for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
48 for(RGBAPixel* pixel = row - image.width; pixel != row; ++pixel)
50 decode(istream, *pixel);
55 template<typename PixelDecoder>
56 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip01&)
58 RGBAPixel* end = image.pixels + (image.height * image.width);
59 for(RGBAPixel* row = image.pixels; row != end; row += image.width)
61 for(RGBAPixel* pixel = row; pixel != row + image.width; ++pixel)
63 decode(istream, *pixel);
68 template<typename PixelDecoder>
69 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip10&)
71 RGBAPixel* end = image.pixels + (image.height * image.width);
72 for(RGBAPixel* row = end; row != image.pixels; row -= image.width)
74 for(RGBAPixel* pixel = row; pixel != row - image.width;)
76 decode(istream, *--pixel);
81 template<typename PixelDecoder>
82 void image_decode(PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip11&)
84 RGBAPixel* end = image.pixels + (image.height * image.width);
85 for(RGBAPixel* row = image.pixels; row != end; row += image.width)
87 for(RGBAPixel* pixel = row + image.width; pixel != row;)
89 decode(istream, *--pixel);
94 inline void istream_read_gray(PointerInputStream& istream, RGBAPixel& pixel)
96 istream.read(&pixel.blue, 1);
97 pixel.red = pixel.green = pixel.blue;
101 inline void istream_read_rgb(PointerInputStream& istream, RGBAPixel& pixel)
103 istream.read(&pixel.blue, 1);
104 istream.read(&pixel.green, 1);
105 istream.read(&pixel.red, 1);
109 inline void istream_read_rgba(PointerInputStream& istream, RGBAPixel& pixel)
111 istream.read(&pixel.blue, 1);
112 istream.read(&pixel.green, 1);
113 istream.read(&pixel.red, 1);
114 istream.read(&pixel.alpha, 1);
117 class TargaDecodeGrayPixel
120 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
122 istream_read_gray(istream, pixel);
126 template<typename Flip>
127 void targa_decode_grayscale(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
129 TargaDecodeGrayPixel decode;
130 image_decode(istream, decode, image, flip);
133 class TargaDecodeRGBPixel
136 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
138 istream_read_rgb(istream, pixel);
142 template<typename Flip>
143 void targa_decode_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
145 TargaDecodeRGBPixel decode;
146 image_decode(istream, decode, image, flip);
149 class TargaDecodeRGBAPixel
152 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
154 istream_read_rgba(istream, pixel);
158 template<typename Flip>
159 void targa_decode_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
161 TargaDecodeRGBAPixel decode;
162 image_decode(istream, decode, image, flip);
165 typedef byte TargaPacket;
166 typedef byte TargaPacketSize;
168 inline void targa_packet_read_istream(TargaPacket& packet, PointerInputStream& istream)
170 istream.read(&packet, 1);
173 inline bool targa_packet_is_rle(const TargaPacket& packet)
175 return (packet & 0x80) != 0;
178 inline TargaPacketSize targa_packet_size(const TargaPacket& packet)
180 return 1 + (packet & 0x7f);
184 class TargaDecodeRGBPixelRLE
186 TargaPacketSize m_packetSize;
188 TargaPacket m_packet;
190 TargaDecodeRGBPixelRLE() : m_packetSize(0)
193 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
195 if(m_packetSize == 0)
197 targa_packet_read_istream(m_packet, istream);
198 m_packetSize = targa_packet_size(m_packet);
200 if(targa_packet_is_rle(m_packet))
202 istream_read_rgb(istream, m_pixel);
206 if(targa_packet_is_rle(m_packet))
212 istream_read_rgb(istream, pixel);
219 template<typename Flip>
220 void targa_decode_rle_rgb(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
222 TargaDecodeRGBPixelRLE decode;
223 image_decode(istream, decode, image, flip);
226 class TargaDecodeRGBAPixelRLE
228 TargaPacketSize m_packetSize;
230 TargaPacket m_packet;
232 TargaDecodeRGBAPixelRLE() : m_packetSize(0)
235 void operator()(PointerInputStream& istream, RGBAPixel& pixel)
237 if(m_packetSize == 0)
239 targa_packet_read_istream(m_packet, istream);
240 m_packetSize = targa_packet_size(m_packet);
242 if(targa_packet_is_rle(m_packet))
244 istream_read_rgba(istream, m_pixel);
248 if(targa_packet_is_rle(m_packet))
254 istream_read_rgba(istream, pixel);
261 template<typename Flip>
262 void targa_decode_rle_rgba(PointerInputStream& istream, RGBAImage& image, const Flip& flip)
264 TargaDecodeRGBAPixelRLE decode;
265 image_decode(istream, decode, image, flip);
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;
277 inline void targa_header_read_istream(TargaHeader& targa_header, PointerInputStream& istream)
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);
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);
293 if (targa_header.id_length != 0)
294 istream.seek(targa_header.id_length); // skip TARGA image comment
297 template<typename Type>
301 ScopeDelete(const ScopeDelete&);
302 ScopeDelete& operator=(const ScopeDelete&);
304 ScopeDelete(Type* value) : m_value(value)
311 Type* get_pointer() const
317 template<typename Flip>
318 Image* Targa_decodeImageData(const TargaHeader& targa_header, PointerInputStream& istream, const Flip& flip)
320 RGBAImage* image = new RGBAImage(targa_header.width, targa_header.height);
322 if (targa_header.image_type == 2 || targa_header.image_type == 3)
324 switch (targa_header.pixel_size)
327 targa_decode_grayscale(istream, *image, flip);
330 targa_decode_rgb(istream, *image, flip);
333 targa_decode_rgba(istream, *image, flip);
336 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
341 else if (targa_header.image_type == 10)
343 switch (targa_header.pixel_size)
346 targa_decode_rle_rgb(istream, *image, flip);
349 targa_decode_rle_rgba(istream, *image, flip);
352 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
361 const unsigned int TGA_FLIP_HORIZONTAL = 0x10;
362 const unsigned int TGA_FLIP_VERTICAL = 0x20;
364 Image* LoadTGABuff(const byte* buffer)
366 PointerInputStream istream(buffer);
367 TargaHeader targa_header;
369 targa_header_read_istream(targa_header, istream);
371 if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3)
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";
378 if (targa_header.colormap_type != 0)
380 globalErrorStream() << "LoadTGA: colormaps not supported\n";
384 if ((targa_header.pixel_size != 32 && targa_header.pixel_size != 24)
385 && targa_header.image_type != 3)
387 globalErrorStream() << "LoadTGA: Only 32 or 24 bit images supported\n";
391 if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
392 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
394 return Targa_decodeImageData(targa_header, istream, Flip00());
396 if(!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
397 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
399 return Targa_decodeImageData(targa_header, istream, Flip01());
401 if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
402 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
404 return Targa_decodeImageData(targa_header, istream, Flip10());
406 if(bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
407 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL))
409 return Targa_decodeImageData(targa_header, istream, Flip11());
416 Image* LoadTGA(ArchiveFile& file)
418 ScopedArchiveBuffer buffer(file);
419 return LoadTGABuff(buffer.buffer);