Panda3D
pnmFileTypeTGA.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pnmFileTypeTGA.cxx
10 * @author drose
11 * @date 2001-04-27
12 */
13
14// Much code in this file is borrowed from Netpbm, specifically tgatoppm.c and
15// ppmtotga.c.
16
17/* tgatoppm.c - read a TrueVision Targa file and write a portable pixmap
18**
19** Partially based on tga2rast, version 1.0, by Ian MacPhedran.
20**
21** Copyright (C) 1989 by Jef Poskanzer.
22**
23** Permission to use, copy, modify, and distribute this software and its
24** documentation for any purpose and without fee is hereby granted, provided
25** that the above copyright notice appear in all copies and that both that
26** copyright notice and this permission notice appear in supporting
27** documentation. This software is provided "as is" without express or
28** implied warranty.
29*/
30
31/* ppmtotga.c - read a portable pixmap and produce a TrueVision Targa file
32**
33** Copyright (C) 1989, 1991 by Mark Shand and Jef Poskanzer
34**
35** Permission to use, copy, modify, and distribute this software and its
36** documentation for any purpose and without fee is hereby granted, provided
37** that the above copyright notice appear in all copies and that both that
38** copyright notice and this permission notice appear in supporting
39** documentation. This software is provided "as is" without express or
40** implied warranty.
41*/
42
43#include "pnmFileTypeTGA.h"
44
45#ifdef HAVE_TGA
46
48
49#include "pnmFileTypeRegistry.h"
50#include "bamReader.h"
51#include "pnmimage_base.h"
52
53#include <string.h>
54
55using std::istream;
56using std::ostream;
57using std::string;
58
59static const char * const extensions_tga[] = {
60 "tga"
61};
62static const int num_extensions_tga = sizeof(extensions_tga) / sizeof(const char *);
63
64TypeHandle PNMFileTypeTGA::_type_handle;
65
66
67/* Header definition. */
68struct ImageHeader {
69 unsigned char IDLength; /* length of Identifier String */
70 unsigned char CoMapType; /* 0 = no map */
71 unsigned char ImgType; /* image type (see below for values) */
72 unsigned char Index_lo, Index_hi; /* index of first color map entry */
73 unsigned char Length_lo, Length_hi; /* number of entries in color map */
74 unsigned char CoSize; /* size of color map entry (15,16,24,32) */
75 unsigned char X_org_lo, X_org_hi; /* x origin of image */
76 unsigned char Y_org_lo, Y_org_hi; /* y origin of image */
77 unsigned char Width_lo, Width_hi; /* width of image */
78 unsigned char Height_lo, Height_hi; /* height of image */
79 unsigned char PixelSize; /* pixel size (8,16,24,32) */
80 unsigned char AttBits; /* 4 bits, number of attribute bits per pixel */
81 unsigned char Rsrvd; /* 1 bit, reserved */
82 unsigned char OrgBit; /* 1 bit, origin: 0=lower left, 1=upper left */
83 unsigned char IntrLve; /* 2 bits, interleaving flag */
84 };
85
86typedef char ImageIDField[256];
87
88/* Max number of colors allowed for colormapped output. */
89#define TGA_MAXCOLORS 257
90
91/* Definitions for image types. */
92#define TGA_Null 0
93#define TGA_Map 1
94#define TGA_RGB 2
95#define TGA_Mono 3
96#define TGA_RLEMap 9
97#define TGA_RLERGB 10
98#define TGA_RLEMono 11
99#define TGA_CompMap 32
100#define TGA_CompMap4 33
101
102/* Definitions for interleave flag. */
103#define TGA_IL_None 0
104#define TGA_IL_Two 1
105#define TGA_IL_Four 2
106
107/**
108 *
109 */
110PNMFileTypeTGA::
111PNMFileTypeTGA() {
112}
113
114/**
115 * Returns a few words describing the file type.
116 */
117string PNMFileTypeTGA::
118get_name() const {
119 return "Targa";
120}
121
122/**
123 * Returns the number of different possible filename extensions_tga associated
124 * with this particular file type.
125 */
126int PNMFileTypeTGA::
127get_num_extensions() const {
128 return num_extensions_tga;
129}
130
131/**
132 * Returns the nth possible filename extension associated with this particular
133 * file type, without a leading dot.
134 */
135string PNMFileTypeTGA::
136get_extension(int n) const {
137 nassertr(n >= 0 && n < num_extensions_tga, string());
138 return extensions_tga[n];
139}
140
141/**
142 * Returns a suitable filename extension (without a leading dot) to suggest
143 * for files of this type, or empty string if no suggestions are available.
144 */
145string PNMFileTypeTGA::
146get_suggested_extension() const {
147 return "tga";
148}
149
150/**
151 * Allocates and returns a new PNMReader suitable for reading from this file
152 * type, if possible. If reading from this file type is not supported,
153 * returns NULL.
154 */
155PNMReader *PNMFileTypeTGA::
156make_reader(istream *file, bool owns_file, const string &magic_number) {
157 init_pnm();
158 return new Reader(this, file, owns_file, magic_number);
159}
160
161/**
162 * Allocates and returns a new PNMWriter suitable for reading from this file
163 * type, if possible. If writing files of this type is not supported, returns
164 * NULL.
165 */
166PNMWriter *PNMFileTypeTGA::
167make_writer(ostream *file, bool owns_file) {
168 init_pnm();
169 return new Writer(this, file, owns_file);
170}
171
172
173/**
174 *
175 */
176PNMFileTypeTGA::Reader::
177Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
178 PNMReader(type, file, owns_file)
179{
180 tga_head = new ImageHeader;
181 RLE_count = 0;
182 RLE_flag = 0;
183 ColorMap = nullptr;
184 AlphaMap = nullptr;
185
186 Red = 0;
187 Grn = 0;
188 Blu = 0;
189 Alpha = 0;
190 l = 0;
191
192 /* Read the Targa file header. */
193 readtga( file, tga_head, magic_number );
194 /*
195 {
196 pm_message( "IDLength = %d", (int) tga_head->IDLength );
197 pm_message( "CoMapType = %d", (int) tga_head->CoMapType );
198 pm_message( "ImgType = %d", (int) tga_head->ImgType );
199 pm_message( "Index_lo = %d", (int) tga_head->Index_lo );
200 pm_message( "Index_hi = %d", (int) tga_head->Index_hi );
201 pm_message( "Length_lo = %d", (int) tga_head->Length_lo );
202 pm_message( "Length_hi = %d", (int) tga_head->Length_hi );
203 pm_message( "CoSize = %d", (int) tga_head->CoSize );
204 pm_message( "X_org_lo = %d", (int) tga_head->X_org_lo );
205 pm_message( "X_org_hi = %d", (int) tga_head->X_org_hi );
206 pm_message( "Y_org_lo = %d", (int) tga_head->Y_org_lo );
207 pm_message( "Y_org_hi = %d", (int) tga_head->Y_org_hi );
208 pm_message( "Width_lo = %d", (int) tga_head->Width_lo );
209 pm_message( "Width_hi = %d", (int) tga_head->Width_hi );
210 pm_message( "Height_lo = %d", (int) tga_head->Height_lo );
211 pm_message( "Height_hi = %d", (int) tga_head->Height_hi );
212 pm_message( "PixelSize = %d", (int) tga_head->PixelSize );
213 pm_message( "AttBits = %d", (int) tga_head->AttBits );
214 pm_message( "Rsrvd = %d", (int) tga_head->Rsrvd );
215 pm_message( "OrgBit = %d", (int) tga_head->OrgBit );
216 pm_message( "IntrLve = %d", (int) tga_head->IntrLve );
217 }
218 */
219 rows = ( (int) tga_head->Height_lo ) + ( (int) tga_head->Height_hi ) * 256;
220 cols = ( (int) tga_head->Width_lo ) + ( (int) tga_head->Width_hi ) * 256;
221
222 switch ( tga_head->ImgType )
223 {
224 case TGA_Map:
225 case TGA_RGB:
226 case TGA_Mono:
227 case TGA_RLEMap:
228 case TGA_RLERGB:
229 case TGA_RLEMono:
230 break;
231
232 default:
233 pm_error( "unknown Targa image type %d", tga_head->ImgType );
234 }
235
236 int size;
237
238 if ( tga_head->ImgType == TGA_Map ||
239 tga_head->ImgType == TGA_RLEMap ||
240 tga_head->ImgType == TGA_CompMap ||
241 tga_head->ImgType == TGA_CompMap4 )
242 { /* Color-mapped image */
243 if ( tga_head->CoMapType != 1 )
244 pm_error(
245 "mapped image (type %d) with color map type != 1",
246 tga_head->ImgType );
247 mapped = 1;
248 /* Figure maxval from CoSize. */
249 size = tga_head->CoSize;
250 }
251 else
252 { /* Not colormap, so figure maxval from PixelSize. */
253 mapped = 0;
254 size = tga_head->PixelSize;
255 }
256
257 switch ( size ) {
258 case 8:
259 _num_channels = 1;
260 _maxval = 255;
261 break;
262
263 case 24:
264 _num_channels = 3;
265 _maxval = 255;
266 break;
267
268 case 32:
269 _num_channels = 4;
270 _maxval = 255;
271 break;
272
273 case 15:
274 case 16:
275 _num_channels = 3;
276 _maxval = 31;
277 break;
278
279 default:
280 pm_error("unknown pixel size - %d", size );
281 }
282
283 /* If required, read the color map information. */
284 if ( tga_head->CoMapType != 0 )
285 {
286 unsigned int temp1, temp2;
287 temp1 = tga_head->Index_lo + tga_head->Index_hi * 256;
288 temp2 = tga_head->Length_lo + tga_head->Length_hi * 256;
289 int num_colors = temp1 + temp2 + 1;
290 nassertv(ColorMap == nullptr && AlphaMap == nullptr);
291 ColorMap = (pixel *)PANDA_MALLOC_ARRAY(num_colors * sizeof(pixel));
292 AlphaMap = (gray *)PANDA_MALLOC_ARRAY(num_colors * sizeof(gray));
293 for ( unsigned int i = temp1; i < ( temp1 + temp2 ); ++i )
294 get_map_entry( file, &ColorMap[i], (int) tga_head->CoSize,
295 &AlphaMap[i]);
296 }
297
298 /* Check run-length encoding. */
299 if ( tga_head->ImgType == TGA_RLEMap ||
300 tga_head->ImgType == TGA_RLERGB ||
301 tga_head->ImgType == TGA_RLEMono )
302 rlencoded = 1;
303 else
304 rlencoded = 0;
305
306 _x_size = cols;
307 _y_size = rows;
308 // _num_channels = 3;
309
310}
311
312/**
313 *
314 */
315PNMFileTypeTGA::Reader::
316~Reader() {
317 delete tga_head;
318 if (ColorMap != nullptr) {
319 PANDA_FREE_ARRAY(ColorMap);
320 }
321 if (AlphaMap != nullptr) {
322 PANDA_FREE_ARRAY(AlphaMap);
323 }
324}
325
326/**
327 * Reads in an entire image all at once, storing it in the pre-allocated
328 * _x_size * _y_size array and alpha pointers. (If the image type has no
329 * alpha channel, alpha is ignored.) Returns the number of rows correctly
330 * read.
331 *
332 * Derived classes need not override this if they instead provide
333 * supports_read_row() and read_row(), below.
334 */
335int PNMFileTypeTGA::Reader::
336read_data(xel *array, xelval *alpha) {
337 int truerow = 0;
338 int baserow = 0;
339 for ( int row = 0; row < rows; ++row )
340 {
341 int realrow = truerow;
342 if ( tga_head->OrgBit == 0 )
343 realrow = rows - realrow - 1;
344
345 for ( int col = 0; col < cols; ++col )
346 get_pixel( _file, &(array[realrow * cols + col]),
347 (int) tga_head->PixelSize,
348 &(alpha[realrow * cols + col]) );
349 if ( tga_head->IntrLve == TGA_IL_Four )
350 truerow += 4;
351 else if ( tga_head->IntrLve == TGA_IL_Two )
352 truerow += 2;
353 else
354 ++truerow;
355 if ( truerow >= rows )
356 truerow = ++baserow;
357 }
358
359 return rows;
360}
361
362/**
363 *
364 */
365PNMFileTypeTGA::Writer::
366Writer(PNMFileType *type, ostream *file, bool owns_file) :
367 PNMWriter(type, file, owns_file)
368{
369 tgaHeader = new ImageHeader;
370 chv = nullptr;
371 cht = nullptr;
372 runlength = nullptr;
373}
374
375/**
376 *
377 */
378PNMFileTypeTGA::Writer::
379~Writer() {
380 delete tgaHeader;
381
382 if (chv != nullptr) {
383 ppm_freecolorhist(chv);
384 }
385 if (cht != nullptr) {
386 ppm_freecolorhash(cht);
387 }
388 if (runlength != nullptr) {
389 pm_freerow((char *)runlength);
390 }
391}
392
393/**
394 * Writes out an entire image all at once, including the header, based on the
395 * image data stored in the given _x_size * _y_size array and alpha pointers.
396 * (If the image type has no alpha channel, alpha is ignored.) Returns the
397 * number of rows correctly written.
398 *
399 * It is the user's responsibility to fill in the header data via calls to
400 * set_x_size(), set_num_channels(), etc., or copy_header_from(), before
401 * calling write_data().
402 *
403 * It is important to delete the PNMWriter class after successfully writing
404 * the data. Failing to do this may result in some data not getting flushed!
405 *
406 * Derived classes need not override this if they instead provide
407 * supports_streaming() and write_row(), below.
408 */
409int PNMFileTypeTGA::Writer::
410write_data(xel *array, xelval *) {
411 // We don't presently support writing 4-channel tga files (since ppmtotga
412 // doesn't support this).
413 rle_flag = tga_rle;
414
415 int row, col;
416 int i;
417 pixel* pP;
418
419 cols = _x_size;
420 rows = _y_size;
421
422 if (is_grayscale() && tga_grayscale) {
423 // We allow grayscale TGA files, and this is a grayscale image, so...
424 tgaHeader->ImgType = TGA_Mono;
425
426 // There's no real point in colormapping a grayscale image.
427 pnmimage_tga_cat.info()
428 << "writing grayscale.\n";
429
430 } else {
431 // This will be an RGB image.
432 tgaHeader->ImgType = TGA_RGB;
433
434 if (tga_colormap) {
435 // It may even be colormapped if there are few enough colors.
436 pnmimage_tga_cat.info()
437 << "computing colormap...\n";
438 chv = ppm_computecolorhist(&array, cols * rows, 1, TGA_MAXCOLORS, &ncolors );
439 if ( chv == nullptr ) {
440 pnmimage_tga_cat.info()
441 << "too many colors, writing RGB.\n";
442 } else {
443 pnmimage_tga_cat.info()
444 << ncolors << " colors found.\n";
445 tgaHeader->ImgType = TGA_Map;
446 }
447 }
448 }
449
450 if ( rle_flag )
451 {
452 switch ( tgaHeader->ImgType )
453 {
454 case TGA_Mono:
455 tgaHeader->ImgType = TGA_RLEMono;
456 break;
457 case TGA_Map:
458 tgaHeader->ImgType = TGA_RLEMap;
459 break;
460 case TGA_RGB:
461 tgaHeader->ImgType = TGA_RLERGB;
462 break;
463 default:
464 pm_error( "can't happen" );
465 }
466 runlength = (int*) pm_allocrow( cols, sizeof(int) );
467 }
468
469 tgaHeader->IDLength = 0;
470 tgaHeader->Index_lo = 0;
471 tgaHeader->Index_hi = 0;
472 if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
473 {
474 /* Make a hash table for fast color lookup. */
475 cht = ppm_colorhisttocolorhash( chv, ncolors );
476
477 tgaHeader->CoMapType = 1;
478 tgaHeader->Length_lo = ncolors % 256;
479 tgaHeader->Length_hi = ncolors / 256;
480 tgaHeader->CoSize = 24;
481 }
482 else
483 {
484 tgaHeader->CoMapType = 0;
485 tgaHeader->Length_lo = 0;
486 tgaHeader->Length_hi = 0;
487 tgaHeader->CoSize = 0;
488 }
489 if ( tgaHeader->ImgType == TGA_RGB || tgaHeader->ImgType == TGA_RLERGB )
490 tgaHeader->PixelSize = 24;
491 else
492 tgaHeader->PixelSize = 8;
493 tgaHeader->X_org_lo = tgaHeader->X_org_hi = 0;
494 tgaHeader->Y_org_lo = tgaHeader->Y_org_hi = 0;
495 tgaHeader->Width_lo = cols % 256;
496 tgaHeader->Width_hi = cols / 256;
497 tgaHeader->Height_lo = rows % 256;
498 tgaHeader->Height_hi = rows / 256;
499 tgaHeader->AttBits = 0;
500 tgaHeader->Rsrvd = 0;
501 tgaHeader->IntrLve = 0;
502 tgaHeader->OrgBit = 0;
503
504 /* Write out the Targa header. */
505 writetga( tgaHeader, nullptr );
506
507 if ( tgaHeader->ImgType == TGA_Map || tgaHeader->ImgType == TGA_RLEMap )
508 {
509 /* Write out the Targa colormap. */
510 for ( i = 0; i < ncolors; ++i )
511 put_map_entry( &chv[i].color, tgaHeader->CoSize, _maxval );
512 }
513
514 /* Write out the pixels */
515 for ( row = 0; row < rows; ++row )
516 {
517 int realrow = row;
518 if ( tgaHeader->OrgBit == 0 )
519 realrow = rows - realrow - 1;
520 if ( rle_flag )
521 {
522 compute_runlengths( cols, &array[realrow * cols], runlength );
523 for ( col = 0; col < cols; )
524 {
525 if ( runlength[col] > 0 )
526 {
527 _file->put( 0x80 + runlength[col] - 1 );
528 put_pixel(&(array[realrow * cols + col]),
529 tgaHeader->ImgType, _maxval, cht );
530 col += runlength[col];
531 }
532 else if ( runlength[col] < 0 )
533 {
534 _file->put( -runlength[col] - 1 );
535 for ( i = 0; i < -runlength[col]; ++i )
536 put_pixel(&(array[realrow * cols + (col + i)]),
537 tgaHeader->ImgType, _maxval, cht );
538 col += -runlength[col];
539 }
540 else
541 pm_error( "can't happen" );
542 }
543 }
544 else
545 {
546 for ( col = 0, pP = &array[realrow * cols]; col < cols; ++col, ++pP )
547 put_pixel( pP, tgaHeader->ImgType, _maxval, cht );
548 }
549 }
550
551 return rows;
552}
553
554
555
556/**
557 * Registers the current object as something that can be read from a Bam file.
558 */
559void PNMFileTypeTGA::
560register_with_read_factory() {
562 register_factory(get_class_type(), make_PNMFileTypeTGA);
563}
564
565/**
566 * This method is called by the BamReader when an object of this type is
567 * encountered in a Bam file; it should allocate and return a new object with
568 * all the data read.
569 *
570 * In the case of the PNMFileType objects, since these objects are all shared,
571 * we just pull the object from the registry.
572 */
573TypedWritable *PNMFileTypeTGA::
574make_PNMFileTypeTGA(const FactoryParams &params) {
576}
577
578void PNMFileTypeTGA::Reader::
579readtga( istream *ifp, struct ImageHeader *tgaP, const string &magic_number ) {
580 unsigned char flags;
581 ImageIDField junk;
582
583 if (magic_number.length() > 0) {
584 tgaP->IDLength = (unsigned char)magic_number[0];
585 } else {
586 tgaP->IDLength = getbyte( ifp );
587 }
588 if (magic_number.length() > 1) {
589 tgaP->CoMapType = (unsigned char)magic_number[1];
590 } else {
591 tgaP->CoMapType = getbyte( ifp );
592 }
593 if (magic_number.length() > 2) {
594 tgaP->ImgType = (unsigned char)magic_number[2];
595 } else {
596 tgaP->ImgType = getbyte( ifp );
597 }
598 if (magic_number.length() > 3) {
599 tgaP->Index_lo = (unsigned char)magic_number[3];
600 } else {
601 tgaP->Index_lo = getbyte( ifp );
602 }
603 tgaP->Index_hi = getbyte( ifp );
604 tgaP->Length_lo = getbyte( ifp );
605 tgaP->Length_hi = getbyte( ifp );
606 tgaP->CoSize = getbyte( ifp );
607 tgaP->X_org_lo = getbyte( ifp );
608 tgaP->X_org_hi = getbyte( ifp );
609 tgaP->Y_org_lo = getbyte( ifp );
610 tgaP->Y_org_hi = getbyte( ifp );
611 tgaP->Width_lo = getbyte( ifp );
612 tgaP->Width_hi = getbyte( ifp );
613 tgaP->Height_lo = getbyte( ifp );
614 tgaP->Height_hi = getbyte( ifp );
615 tgaP->PixelSize = getbyte( ifp );
616 flags = getbyte( ifp );
617 tgaP->AttBits = flags & 0xf;
618 tgaP->Rsrvd = ( flags & 0x10 ) >> 4;
619 tgaP->OrgBit = ( flags & 0x20 ) >> 5;
620 tgaP->IntrLve = ( flags & 0xc0 ) >> 6;
621
622 if ( tgaP->IDLength != 0 )
623 ifp->read(junk, (int) tgaP->IDLength);
624 }
625
626void PNMFileTypeTGA::Reader::
627get_map_entry( istream *ifp, pixel *Value, int Size, gray *Alpha ) {
628 unsigned char j, k;
629 unsigned char r = 0, g = 0, b = 0, a = 0;
630
631 /* Read appropriate number of bytes, break into rgb & put in map. */
632 switch ( Size )
633 {
634 case 8: /* Grey scale, read and triplicate. */
635 r = g = b = getbyte( ifp );
636 a = 0;
637 break;
638
639 case 16: /* 5 bits each of red green and blue. */
640 case 15: /* Watch for byte order. */
641 j = getbyte( ifp );
642 k = getbyte( ifp );
643 r = ( k & 0x7C ) >> 2;
644 g = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
645 b = j & 0x1F;
646 a = 0;
647 break;
648
649 case 32: /* 8 bits each of blue, green, red, and alpha */
650 case 24: /* 8 bits each of blue green and red. */
651 b = getbyte( ifp );
652 g = getbyte( ifp );
653 r = getbyte( ifp );
654 if ( Size == 32 )
655 a = getbyte( ifp );
656 else
657 a = 0;
658 break;
659
660 default:
661 pm_error( "unknown colormap pixel size (#2) - %d", Size );
662 }
663 PPM_ASSIGN( *Value, r, g, b );
664 *Alpha = a;
665}
666
667
668
669void PNMFileTypeTGA::Reader::
670get_pixel( istream *ifp, pixel *dest, int Size, gray *alpha_p) {
671 unsigned char j, k;
672
673 /* Check if run length encoded. */
674 if ( rlencoded )
675 {
676 if ( RLE_count == 0 )
677 { /* Have to restart run. */
678 unsigned char i;
679 i = getbyte( ifp );
680 RLE_flag = ( i & 0x80 );
681 if ( RLE_flag == 0 )
682 /* Stream of unencoded pixels. */
683 RLE_count = i + 1;
684 else
685 /* Single pixel replicated. */
686 RLE_count = i - 127;
687 /* Decrement count & get pixel. */
688 --RLE_count;
689 }
690 else
691 { /* Have already read count & (at least) first pixel. */
692 --RLE_count;
693 if ( RLE_flag != 0 )
694 /* Replicated pixels. */
695 goto PixEncode;
696 }
697 }
698 /* Read appropriate number of bytes, break into RGB. */
699 switch ( Size )
700 {
701 case 8: /* Grey scale, read and triplicate. */
702 Red = Grn = Blu = l = getbyte( ifp );
703 Alpha = 0;
704 break;
705
706 case 16: /* 5 bits each of red green and blue. */
707 case 15: /* Watch byte order. */
708 j = getbyte( ifp );
709 k = getbyte( ifp );
710 l = ( (unsigned int) k << 8 ) + j;
711 Red = ( k & 0x7C ) >> 2;
712 Grn = ( ( k & 0x03 ) << 3 ) + ( ( j & 0xE0 ) >> 5 );
713 Blu = j & 0x1F;
714 Alpha = 0;
715 break;
716
717 case 32: /* 8 bits each of blue, green, red, and alpha */
718 case 24: /* 8 bits each of blue, green, and red. */
719 Blu = getbyte( ifp );
720 Grn = getbyte( ifp );
721 Red = getbyte( ifp );
722 if ( Size == 32 )
723 Alpha = getbyte( ifp );
724 else
725 Alpha = 0;
726 l = 0;
727 break;
728
729 default:
730 pm_error( "unknown pixel size (#2) - %d", Size );
731 }
732
733PixEncode:
734 if ( mapped ) {
735 *dest = ColorMap[l];
736 if (has_alpha()) {
737 *alpha_p = AlphaMap[l];
738 }
739 } else {
740 PPM_ASSIGN( *dest, Red, Grn, Blu );
741 if (has_alpha()) {
742 *alpha_p = Alpha;
743 }
744 }
745 }
746
747
748unsigned char PNMFileTypeTGA::Reader::
749getbyte( istream *ifp ) {
750 unsigned char c;
751
752 c = ifp->get();
753 if (ifp->fail() || ifp->eof())
754 pm_error( "EOF / read error" );
755
756 return c;
757 }
758
759void PNMFileTypeTGA::Writer::
760writetga( struct ImageHeader *tgaP, char *id )
761 {
762 unsigned char flags;
763
764 _file->put( tgaP->IDLength );
765 _file->put( tgaP->CoMapType );
766 _file->put( tgaP->ImgType );
767 _file->put( tgaP->Index_lo );
768 _file->put( tgaP->Index_hi );
769 _file->put( tgaP->Length_lo );
770 _file->put( tgaP->Length_hi );
771 _file->put( tgaP->CoSize );
772 _file->put( tgaP->X_org_lo );
773 _file->put( tgaP->X_org_hi );
774 _file->put( tgaP->Y_org_lo );
775 _file->put( tgaP->Y_org_hi );
776 _file->put( tgaP->Width_lo );
777 _file->put( tgaP->Width_hi );
778 _file->put( tgaP->Height_lo );
779 _file->put( tgaP->Height_hi );
780 _file->put( tgaP->PixelSize );
781 flags = ( tgaP->AttBits & 0xf ) | ( ( tgaP->Rsrvd & 0x1 ) << 4 ) |
782 ( ( tgaP->OrgBit & 0x1 ) << 5 ) | ( ( tgaP->OrgBit & 0x3 ) << 6 );
783 _file->put( flags );
784 if ( tgaP->IDLength )
785 _file->write( id, (int) tgaP->IDLength );
786 }
787
788void PNMFileTypeTGA::Writer::
789put_map_entry( pixel* valueP, int size, pixval maxval )
790 {
791 int j;
792 pixel p;
793
794 switch ( size )
795 {
796 case 8: /* Grey scale. */
797 put_mono( valueP, maxval );
798 break;
799
800 case 16: /* 5 bits each of red green and blue. */
801 case 15: /* Watch for byte order. */
802 PPM_DEPTH( p, *valueP, maxval, 31 );
803 j = (int) PPM_GETB( p ) | ( (int) PPM_GETG( p ) << 5 ) |
804 ( (int) PPM_GETR( p ) << 10 );
805 _file->put( j % 256 );
806 _file->put( j / 256 );
807 break;
808
809 case 32:
810 case 24: /* 8 bits each of blue green and red. */
811 put_rgb( valueP, maxval );
812 break;
813
814 default:
815 pm_error( "unknown colormap pixel size (#2) - %d", size );
816 }
817 }
818
819void PNMFileTypeTGA::Writer::
820compute_runlengths( int cols, pixel *pixelrow, int *runlength )
821 {
822 int col, start;
823
824 /* Initialize all run lengths to 0. (This is just an error check.) */
825 for ( col = 0; col < cols; ++col )
826 runlength[col] = 0;
827
828 /* Find runs of identical pixels. */
829 for ( col = 0; col < cols; )
830 {
831 start = col;
832 do {
833 ++col;
834 }
835 while ( col < cols &&
836 col - start < 128 &&
837 PPM_EQUAL( pixelrow[col], pixelrow[start] ) );
838 runlength[start] = col - start;
839 }
840
841 /* Now look for runs of length-1 runs, and turn them into negative runs. */
842 for ( col = 0; col < cols; )
843 {
844 if ( runlength[col] == 1 )
845 {
846 start = col;
847 while ( col < cols &&
848 col - start < 128 &&
849 runlength[col] == 1 )
850 {
851 runlength[col] = 0;
852 ++col;
853 }
854 runlength[start] = - ( col - start );
855 }
856 else
857 col += runlength[col];
858 }
859 }
860
861void PNMFileTypeTGA::Writer::
862put_pixel( pixel* pP, int imgtype, pixval maxval, colorhash_table cht )
863 {
864 switch ( imgtype )
865 {
866 case TGA_Mono:
867 case TGA_RLEMono:
868 put_mono( pP, maxval );
869 break;
870 case TGA_Map:
871 case TGA_RLEMap:
872 put_map( pP, cht );
873 break;
874 case TGA_RGB:
875 case TGA_RLERGB:
876 put_rgb( pP, maxval );
877 break;
878 default:
879 pm_error( "can't happen" );
880 }
881 }
882
883void PNMFileTypeTGA::Writer::
884put_mono( pixel* pP, pixval maxval )
885 {
886 pixel p;
887 PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
888 _file->put( PPM_GETB( p ) );
889 }
890
891void PNMFileTypeTGA::Writer::
892put_map( pixel *pP, colorhash_table cht )
893 {
894 _file->put( ppm_lookupcolor( cht, pP ) );
895 }
896
897void PNMFileTypeTGA::Writer::
898put_rgb( pixel* pP, pixval maxval ) {
899 pixel p;
900 PPM_DEPTH( p, *pP, maxval, (pixval) 255 );
901 _file->put( PPM_GETB( p ) );
902 if (is_grayscale()) {
903 _file->put( PPM_GETB( p ) );
904 _file->put( PPM_GETB( p ) );
905 } else {
906 _file->put( PPM_GETG( p ) );
907 _file->put( PPM_GETR( p ) );
908 }
909}
910
911#endif // HAVE_TGA
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
This is an abstract base class that defines the interface for reading image files of various types.
Definition: pnmReader.h:27
This is an abstract base class that defines the interface for writing image files of various types.
Definition: pnmWriter.h:27
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
char * pm_allocrow(int cols, int size)
Allocates a row of cols * size bytes.
void pm_freerow(char *itrow)
Frees the row previously allocated withm pm_allocrow().
void pm_error(const char *format,...)
Outputs the given printf-style message to the user and terminates messily.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.