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) {
47 for (RGBAPixel *pixel = row - image.width; pixel != row; ++pixel) {
48 decode(istream, *pixel);
53 template<typename PixelDecoder>
54 void image_decode(PointerInputStream &istream, PixelDecoder &decode, RGBAImage &image, const Flip01 &)
56 RGBAPixel *end = image.pixels + (image.height * image.width);
57 for (RGBAPixel *row = image.pixels; row != end; row += image.width) {
58 for (RGBAPixel *pixel = row; pixel != row + image.width; ++pixel) {
59 decode(istream, *pixel);
64 template<typename PixelDecoder>
65 void image_decode(PointerInputStream &istream, PixelDecoder &decode, RGBAImage &image, const Flip10 &)
67 RGBAPixel *end = image.pixels + (image.height * image.width);
68 for (RGBAPixel *row = end; row != image.pixels; row -= image.width) {
69 for (RGBAPixel *pixel = row; pixel != row - image.width;) {
70 decode(istream, *--pixel);
75 template<typename PixelDecoder>
76 void image_decode(PointerInputStream &istream, PixelDecoder &decode, RGBAImage &image, const Flip11 &)
78 RGBAPixel *end = image.pixels + (image.height * image.width);
79 for (RGBAPixel *row = image.pixels; row != end; row += image.width) {
80 for (RGBAPixel *pixel = row + image.width; pixel != row;) {
81 decode(istream, *--pixel);
86 inline void istream_read_gray(PointerInputStream &istream, RGBAPixel &pixel)
88 istream.read(&pixel.blue, 1);
89 pixel.red = pixel.green = pixel.blue;
93 inline void istream_read_rgb(PointerInputStream &istream, RGBAPixel &pixel)
95 istream.read(&pixel.blue, 1);
96 istream.read(&pixel.green, 1);
97 istream.read(&pixel.red, 1);
101 inline void istream_read_rgba(PointerInputStream &istream, RGBAPixel &pixel)
103 istream.read(&pixel.blue, 1);
104 istream.read(&pixel.green, 1);
105 istream.read(&pixel.red, 1);
106 istream.read(&pixel.alpha, 1);
109 class TargaDecodeGrayPixel {
111 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
113 istream_read_gray(istream, pixel);
117 template<typename Flip>
118 void targa_decode_grayscale(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
120 TargaDecodeGrayPixel decode;
121 image_decode(istream, decode, image, flip);
124 class TargaDecodeRGBPixel {
126 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
128 istream_read_rgb(istream, pixel);
132 template<typename Flip>
133 void targa_decode_rgb(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
135 TargaDecodeRGBPixel decode;
136 image_decode(istream, decode, image, flip);
139 class TargaDecodeRGBAPixel {
141 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
143 istream_read_rgba(istream, pixel);
147 template<typename Flip>
148 void targa_decode_rgba(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
150 TargaDecodeRGBAPixel decode;
151 image_decode(istream, decode, image, flip);
154 typedef byte TargaPacket;
155 typedef byte TargaPacketSize;
157 inline void targa_packet_read_istream(TargaPacket &packet, PointerInputStream &istream)
159 istream.read(&packet, 1);
162 inline bool targa_packet_is_rle(const TargaPacket &packet)
164 return (packet & 0x80) != 0;
167 inline TargaPacketSize targa_packet_size(const TargaPacket &packet)
169 return 1 + (packet & 0x7f);
173 class TargaDecodeGrayPixelRLE {
174 TargaPacketSize m_packetSize;
176 TargaPacket m_packet;
178 TargaDecodeGrayPixelRLE() : m_packetSize(0)
182 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
184 if (m_packetSize == 0) {
185 targa_packet_read_istream(m_packet, istream);
186 m_packetSize = targa_packet_size(m_packet);
188 if (targa_packet_is_rle(m_packet)) {
189 istream_read_gray(istream, m_pixel);
193 if (targa_packet_is_rle(m_packet)) {
196 istream_read_gray(istream, pixel);
203 template<typename Flip>
204 void targa_decode_rle_grayscale(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
206 TargaDecodeGrayPixelRLE decode;
207 image_decode(istream, decode, image, flip);
210 class TargaDecodeRGBPixelRLE {
211 TargaPacketSize m_packetSize;
213 TargaPacket m_packet;
215 TargaDecodeRGBPixelRLE() : m_packetSize(0)
219 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
221 if (m_packetSize == 0) {
222 targa_packet_read_istream(m_packet, istream);
223 m_packetSize = targa_packet_size(m_packet);
225 if (targa_packet_is_rle(m_packet)) {
226 istream_read_rgb(istream, m_pixel);
230 if (targa_packet_is_rle(m_packet)) {
233 istream_read_rgb(istream, pixel);
240 template<typename Flip>
241 void targa_decode_rle_rgb(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
243 TargaDecodeRGBPixelRLE decode;
244 image_decode(istream, decode, image, flip);
247 class TargaDecodeRGBAPixelRLE {
248 TargaPacketSize m_packetSize;
250 TargaPacket m_packet;
252 TargaDecodeRGBAPixelRLE() : m_packetSize(0)
256 void operator()(PointerInputStream &istream, RGBAPixel &pixel)
258 if (m_packetSize == 0) {
259 targa_packet_read_istream(m_packet, istream);
260 m_packetSize = targa_packet_size(m_packet);
262 if (targa_packet_is_rle(m_packet)) {
263 istream_read_rgba(istream, m_pixel);
267 if (targa_packet_is_rle(m_packet)) {
270 istream_read_rgba(istream, pixel);
277 template<typename Flip>
278 void targa_decode_rle_rgba(PointerInputStream &istream, RGBAImage &image, const Flip &flip)
280 TargaDecodeRGBAPixelRLE decode;
281 image_decode(istream, decode, image, flip);
285 unsigned char id_length, colormap_type, image_type;
286 unsigned short colormap_index, colormap_length;
287 unsigned char colormap_size;
288 unsigned short x_origin, y_origin, width, height;
289 unsigned char pixel_size, attributes;
292 inline void targa_header_read_istream(TargaHeader &targa_header, PointerInputStream &istream)
294 targa_header.id_length = istream_read_byte(istream);
295 targa_header.colormap_type = istream_read_byte(istream);
296 targa_header.image_type = istream_read_byte(istream);
298 targa_header.colormap_index = istream_read_int16_le(istream);
299 targa_header.colormap_length = istream_read_int16_le(istream);
300 targa_header.colormap_size = istream_read_byte(istream);
301 targa_header.x_origin = istream_read_int16_le(istream);
302 targa_header.y_origin = istream_read_int16_le(istream);
303 targa_header.width = istream_read_int16_le(istream);
304 targa_header.height = istream_read_int16_le(istream);
305 targa_header.pixel_size = istream_read_byte(istream);
306 targa_header.attributes = istream_read_byte(istream);
308 if (targa_header.id_length != 0) {
309 istream.seek(targa_header.id_length); // skip TARGA image comment
313 template<typename Type>
317 ScopeDelete(const ScopeDelete &);
319 ScopeDelete &operator=(const ScopeDelete &);
322 ScopeDelete(Type *value) : m_value(value)
331 Type *get_pointer() const
337 template<typename Flip>
338 Image *Targa_decodeImageData(const TargaHeader &targa_header, PointerInputStream &istream, const Flip &flip)
340 RGBAImage *image = new RGBAImage(targa_header.width, targa_header.height);
342 if (targa_header.image_type == 2 || targa_header.image_type == 3) {
343 switch (targa_header.pixel_size) {
345 targa_decode_grayscale(istream, *image, flip);
348 targa_decode_rgb(istream, *image, flip);
351 targa_decode_rgba(istream, *image, flip);
354 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
358 } else if (targa_header.image_type == 10 || targa_header.image_type == 11) {
359 switch (targa_header.pixel_size) {
361 targa_decode_rle_grayscale(istream, *image, flip);
364 targa_decode_rle_rgb(istream, *image, flip);
367 targa_decode_rle_rgba(istream, *image, flip);
370 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
379 const unsigned int TGA_FLIP_HORIZONTAL = 0x10;
380 const unsigned int TGA_FLIP_VERTICAL = 0x20;
382 Image *LoadTGABuff(const byte *buffer)
384 PointerInputStream istream(buffer);
385 TargaHeader targa_header;
387 targa_header_read_istream(targa_header, istream);
389 if (targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 &&
390 targa_header.image_type != 11) {
391 globalErrorStream() << "LoadTGA: TGA type " << targa_header.image_type << " not supported\n";
392 globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), 10 (RGB), and 11 (gray) TGA images supported\n";
396 if (targa_header.colormap_type != 0) {
397 globalErrorStream() << "LoadTGA: colormaps not supported\n";
401 if (((targa_header.image_type == 2 || targa_header.image_type == 10) && targa_header.pixel_size != 32 &&
402 targa_header.pixel_size != 24) ||
403 ((targa_header.image_type == 3 || targa_header.image_type == 11) && targa_header.pixel_size != 8)) {
404 globalErrorStream() << "LoadTGA: Only 32, 24 or 8 bit images supported\n";
408 if (!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
409 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL)) {
410 return Targa_decodeImageData(targa_header, istream, Flip00());
412 if (!bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
413 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL)) {
414 return Targa_decodeImageData(targa_header, istream, Flip01());
416 if (bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
417 && !bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL)) {
418 return Targa_decodeImageData(targa_header, istream, Flip10());
420 if (bitfield_enabled(targa_header.attributes, TGA_FLIP_HORIZONTAL)
421 && bitfield_enabled(targa_header.attributes, TGA_FLIP_VERTICAL)) {
422 return Targa_decodeImageData(targa_header, istream, Flip11());
429 Image *LoadTGA(ArchiveFile &file)
431 ScopedArchiveBuffer buffer(file);
432 return LoadTGABuff(buffer.buffer);