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 
47 #include "config_pnmimagetypes.h"
48 
49 #include "pnmFileTypeRegistry.h"
50 #include "bamReader.h"
51 #include "pnmimage_base.h"
52 
53 #include <string.h>
54 
55 using std::istream;
56 using std::ostream;
57 using std::string;
58 
59 static const char * const extensions_tga[] = {
60  "tga"
61 };
62 static const int num_extensions_tga = sizeof(extensions_tga) / sizeof(const char *);
63 
64 TypeHandle PNMFileTypeTGA::_type_handle;
65 
66 
67 /* Header definition. */
68 struct 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 
86 typedef 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  */
110 PNMFileTypeTGA::
111 PNMFileTypeTGA() {
112 }
113 
114 /**
115  * Returns a few words describing the file type.
116  */
117 string PNMFileTypeTGA::
118 get_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  */
126 int PNMFileTypeTGA::
127 get_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  */
135 string PNMFileTypeTGA::
136 get_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  */
145 string PNMFileTypeTGA::
146 get_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  */
155 PNMReader *PNMFileTypeTGA::
156 make_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  */
166 PNMWriter *PNMFileTypeTGA::
167 make_writer(ostream *file, bool owns_file) {
168  init_pnm();
169  return new Writer(this, file, owns_file);
170 }
171 
172 
173 /**
174  *
175  */
176 PNMFileTypeTGA::Reader::
177 Reader(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  */
315 PNMFileTypeTGA::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  */
335 int PNMFileTypeTGA::Reader::
336 read_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  */
365 PNMFileTypeTGA::Writer::
366 Writer(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  */
378 PNMFileTypeTGA::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  */
409 int PNMFileTypeTGA::Writer::
410 write_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  */
559 void PNMFileTypeTGA::
560 register_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  */
573 TypedWritable *PNMFileTypeTGA::
574 make_PNMFileTypeTGA(const FactoryParams &params) {
575  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
576 }
577 
578 void PNMFileTypeTGA::Reader::
579 readtga( 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 
626 void PNMFileTypeTGA::Reader::
627 get_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 
669 void PNMFileTypeTGA::Reader::
670 get_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 
733 PixEncode:
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 
748 unsigned char PNMFileTypeTGA::Reader::
749 getbyte( 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 
759 void PNMFileTypeTGA::Writer::
760 writetga( 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 
788 void PNMFileTypeTGA::Writer::
789 put_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 
819 void PNMFileTypeTGA::Writer::
820 compute_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 
861 void PNMFileTypeTGA::Writer::
862 put_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 
883 void PNMFileTypeTGA::Writer::
884 put_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 
891 void PNMFileTypeTGA::Writer::
892 put_map( pixel *pP, colorhash_table cht )
893  {
894  _file->put( ppm_lookupcolor( cht, pP ) );
895  }
896 
897 void PNMFileTypeTGA::Writer::
898 put_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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:35
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:32
void pm_freerow(char *itrow)
Frees the row previously allocated withm pm_allocrow().
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
void pm_error(const char *format,...)
Outputs the given printf-style message to the user and terminates messily.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:36
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e....
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is an abstract base class that defines the interface for reading image files of various types.
Definition: pnmReader.h:27
char * pm_allocrow(int cols, int size)
Allocates a row of cols * size bytes.
This is an abstract base class that defines the interface for writing image files of various types.
Definition: pnmWriter.h:27
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:177
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81