Panda3D
Loading...
Searching...
No Matches
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...
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.
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.