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& ){
44 RGBAPixel* end = image.pixels + ( image.height * image.width );
45 for ( RGBAPixel* row = end; row != image.pixels; row -= image.width )
47 for ( RGBAPixel* pixel = row - image.width; pixel != row; ++pixel )
49 decode( istream, *pixel );
54 template<typename PixelDecoder>
55 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 )
59 for ( RGBAPixel* pixel = row; pixel != row + image.width; ++pixel )
61 decode( istream, *pixel );
66 template<typename PixelDecoder>
67 void image_decode( PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip10& ){
68 RGBAPixel* end = image.pixels + ( image.height * image.width );
69 for ( RGBAPixel* row = end; row != image.pixels; row -= image.width )
71 for ( RGBAPixel* pixel = row; pixel != row - image.width; )
73 decode( istream, *--pixel );
78 template<typename PixelDecoder>
79 void image_decode( PointerInputStream& istream, PixelDecoder& decode, RGBAImage& image, const Flip11& ){
80 RGBAPixel* end = image.pixels + ( image.height * image.width );
81 for ( RGBAPixel* row = image.pixels; row != end; row += image.width )
83 for ( RGBAPixel* pixel = row + image.width; pixel != row; )
85 decode( istream, *--pixel );
90 inline void istream_read_gray( PointerInputStream& istream, RGBAPixel& pixel ){
91 istream.read( &pixel.blue, 1 );
92 pixel.red = pixel.green = pixel.blue;
96 inline void istream_read_rgb( PointerInputStream& istream, RGBAPixel& pixel ){
97 istream.read( &pixel.blue, 1 );
98 istream.read( &pixel.green, 1 );
99 istream.read( &pixel.red, 1 );
103 inline void istream_read_rgba( PointerInputStream& istream, RGBAPixel& pixel ){
104 istream.read( &pixel.blue, 1 );
105 istream.read( &pixel.green, 1 );
106 istream.read( &pixel.red, 1 );
107 istream.read( &pixel.alpha, 1 );
110 class TargaDecodeGrayPixel
113 void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
114 istream_read_gray( istream, pixel );
118 template<typename Flip>
119 void targa_decode_grayscale( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
120 TargaDecodeGrayPixel decode;
121 image_decode( istream, decode, image, flip );
124 class TargaDecodeRGBPixel
127 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 ){
134 TargaDecodeRGBPixel decode;
135 image_decode( istream, decode, image, flip );
138 class TargaDecodeRGBAPixel
141 void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
142 istream_read_rgba( istream, pixel );
146 template<typename Flip>
147 void targa_decode_rgba( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
148 TargaDecodeRGBAPixel decode;
149 image_decode( istream, decode, image, flip );
152 typedef byte TargaPacket;
153 typedef byte TargaPacketSize;
155 inline void targa_packet_read_istream( TargaPacket& packet, PointerInputStream& istream ){
156 istream.read( &packet, 1 );
159 inline bool targa_packet_is_rle( const TargaPacket& packet ){
160 return ( packet & 0x80 ) != 0;
163 inline TargaPacketSize targa_packet_size( const TargaPacket& packet ){
164 return 1 + ( packet & 0x7f );
168 class TargaDecodeGrayPixelRLE
170 TargaPacketSize m_packetSize;
172 TargaPacket m_packet;
174 TargaDecodeGrayPixelRLE() : m_packetSize( 0 ){
176 void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
177 if ( m_packetSize == 0 ) {
178 targa_packet_read_istream( m_packet, istream );
179 m_packetSize = targa_packet_size( m_packet );
181 if ( targa_packet_is_rle( m_packet ) ) {
182 istream_read_gray( istream, m_pixel );
186 if ( targa_packet_is_rle( m_packet ) ) {
191 istream_read_gray( istream, pixel );
198 template<typename Flip>
199 void targa_decode_rle_grayscale( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
200 TargaDecodeGrayPixelRLE decode;
201 image_decode( istream, decode, image, flip );
204 class TargaDecodeRGBPixelRLE
206 TargaPacketSize m_packetSize;
208 TargaPacket m_packet;
210 TargaDecodeRGBPixelRLE() : m_packetSize( 0 ){
212 void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
213 if ( m_packetSize == 0 ) {
214 targa_packet_read_istream( m_packet, istream );
215 m_packetSize = targa_packet_size( m_packet );
217 if ( targa_packet_is_rle( m_packet ) ) {
218 istream_read_rgb( istream, m_pixel );
222 if ( targa_packet_is_rle( m_packet ) ) {
227 istream_read_rgb( istream, pixel );
234 template<typename Flip>
235 void targa_decode_rle_rgb( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
236 TargaDecodeRGBPixelRLE decode;
237 image_decode( istream, decode, image, flip );
240 class TargaDecodeRGBAPixelRLE
242 TargaPacketSize m_packetSize;
244 TargaPacket m_packet;
246 TargaDecodeRGBAPixelRLE() : m_packetSize( 0 ){
248 void operator()( PointerInputStream& istream, RGBAPixel& pixel ){
249 if ( m_packetSize == 0 ) {
250 targa_packet_read_istream( m_packet, istream );
251 m_packetSize = targa_packet_size( m_packet );
253 if ( targa_packet_is_rle( m_packet ) ) {
254 istream_read_rgba( istream, m_pixel );
258 if ( targa_packet_is_rle( m_packet ) ) {
263 istream_read_rgba( istream, pixel );
270 template<typename Flip>
271 void targa_decode_rle_rgba( PointerInputStream& istream, RGBAImage& image, const Flip& flip ){
272 TargaDecodeRGBAPixelRLE decode;
273 image_decode( istream, decode, image, flip );
278 unsigned char id_length, colormap_type, image_type;
279 unsigned short colormap_index, colormap_length;
280 unsigned char colormap_size;
281 unsigned short x_origin, y_origin, width, height;
282 unsigned char pixel_size, attributes;
285 inline void targa_header_read_istream( TargaHeader& targa_header, PointerInputStream& istream ){
286 targa_header.id_length = istream_read_byte( istream );
287 targa_header.colormap_type = istream_read_byte( istream );
288 targa_header.image_type = istream_read_byte( istream );
290 targa_header.colormap_index = istream_read_int16_le( istream );
291 targa_header.colormap_length = istream_read_int16_le( istream );
292 targa_header.colormap_size = istream_read_byte( istream );
293 targa_header.x_origin = istream_read_int16_le( istream );
294 targa_header.y_origin = istream_read_int16_le( istream );
295 targa_header.width = istream_read_int16_le( istream );
296 targa_header.height = istream_read_int16_le( istream );
297 targa_header.pixel_size = istream_read_byte( istream );
298 targa_header.attributes = istream_read_byte( istream );
300 if ( targa_header.id_length != 0 ) {
301 istream.seek( targa_header.id_length ); // skip TARGA image comment
305 template<typename Type>
309 ScopeDelete( const ScopeDelete& );
310 ScopeDelete& operator=( const ScopeDelete& );
312 ScopeDelete( Type* value ) : m_value( value ){
317 Type* get_pointer() const {
322 template<typename Flip>
323 Image* Targa_decodeImageData( const TargaHeader& targa_header, PointerInputStream& istream, const Flip& flip ){
324 RGBAImage* image = new RGBAImage( targa_header.width, targa_header.height );
326 if ( targa_header.image_type == 2 || targa_header.image_type == 3 ) {
327 switch ( targa_header.pixel_size )
330 targa_decode_grayscale( istream, *image, flip );
333 targa_decode_rgb( istream, *image, flip );
336 targa_decode_rgba( istream, *image, flip );
339 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
344 else if ( targa_header.image_type == 10 || targa_header.image_type == 11 ) {
345 switch ( targa_header.pixel_size )
348 targa_decode_rle_grayscale( istream, *image, flip );
351 targa_decode_rle_rgb( istream, *image, flip );
354 targa_decode_rle_rgba( istream, *image, flip );
357 globalErrorStream() << "LoadTGA: illegal pixel_size '" << targa_header.pixel_size << "'\n";
366 const unsigned int TGA_FLIP_HORIZONTAL = 0x10;
367 const unsigned int TGA_FLIP_VERTICAL = 0x20;
369 Image* LoadTGABuff( const byte* buffer ){
370 PointerInputStream istream( buffer );
371 TargaHeader targa_header;
373 targa_header_read_istream( targa_header, istream );
375 if ( targa_header.image_type != 2 && targa_header.image_type != 10 && targa_header.image_type != 3 && targa_header.image_type != 11 ) {
376 globalErrorStream() << "LoadTGA: TGA type " << targa_header.image_type << " not supported\n";
377 globalErrorStream() << "LoadTGA: Only type 2 (RGB), 3 (gray), 10 (RGB), and 11 (gray) TGA images supported\n";
381 if ( targa_header.colormap_type != 0 ) {
382 globalErrorStream() << "LoadTGA: colormaps not supported\n";
386 if ( ( ( targa_header.image_type == 2 || targa_header.image_type == 10 ) && targa_header.pixel_size != 32 && targa_header.pixel_size != 24 ) ||
387 ( ( targa_header.image_type == 3 || targa_header.image_type == 11 ) && targa_header.pixel_size != 8 ) ) {
388 globalErrorStream() << "LoadTGA: Only 32, 24 or 8 bit images supported\n";
392 if ( !bitfield_enabled( targa_header.attributes, TGA_FLIP_HORIZONTAL )
393 && !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 ) ) {
398 return Targa_decodeImageData( targa_header, istream, Flip01() );
400 if ( bitfield_enabled( targa_header.attributes, TGA_FLIP_HORIZONTAL )
401 && !bitfield_enabled( targa_header.attributes, TGA_FLIP_VERTICAL ) ) {
402 return Targa_decodeImageData( targa_header, istream, Flip10() );
404 if ( bitfield_enabled( targa_header.attributes, TGA_FLIP_HORIZONTAL )
405 && bitfield_enabled( targa_header.attributes, TGA_FLIP_VERTICAL ) ) {
406 return Targa_decodeImageData( targa_header, istream, Flip11() );
413 Image* LoadTGA( ArchiveFile& file ){
414 ScopedArchiveBuffer buffer( file );
415 return LoadTGABuff( buffer.buffer );