Panda3D
 All Classes Functions Variables Enumerations
pnmFileTypeSoftImage.cxx
1 // Filename: pnmFileTypeSoftImage.cxx
2 // Created by: drose (17Jun00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "pnmFileTypeSoftImage.h"
16 
17 #ifdef HAVE_SOFTIMAGE_PIC
18 
19 #include "config_pnmimagetypes.h"
20 
21 #include "pnmFileTypeRegistry.h"
22 #include "bamReader.h"
23 
24 static const float imageVersionNumber = 3.0;
25 static const int imageCommentLength = 80;
26 static const char imageComment[imageCommentLength+1] =
27  "Written by pnmimage.";
28 
29 // Values to indicate compressed/uncompressed types
30 #define UNCOMPRESSED 0x00
31 #define MIXED_RUN_LENGTH 0x02
32 
33 // Bits to indicate channel type
34 #define RGB_CHANNEL 0xe0
35 #define ALPHA_CHANNEL 0x10
36 
37 // SoftImage magic number: high word, low word
38 #define SOFTIMAGE_MAGIC1 0x5380
39 #define SOFTIMAGE_MAGIC2 0xf634
40 
41 static const char * const extensions_softimage[] = {
42  "pic", "soft"
43 };
44 static const int num_extensions_softimage = sizeof(extensions_softimage) / sizeof(const char *);
45 
46 TypeHandle PNMFileTypeSoftImage::_type_handle;
47 
48 inline float
49 read_float(istream *file) {
50  long l;
51 
52  if (pm_readbiglong(file, &l)==0) {
53  return *(float *)&l;
54  } else {
55  return 0.0;
56  }
57 }
58 
59 inline unsigned short
60 read_ushort_SI(istream *file) {
61  unsigned short x;
62  return pm_readbigshort(file, (short *)&x)==0 ? x : 0;
63 }
64 
65 inline unsigned char
66 read_uchar_SI(istream *file) {
67  int x;
68  x = file->get();
69  return (x!=EOF) ? (unsigned char)x : 0;
70 }
71 
72 inline void
73 write_ushort_SI(ostream *file, unsigned short x) {
74  pm_writebigshort(file, (short)x);
75 }
76 
77 inline void
78 write_uchar_SI(ostream *file, unsigned char x) {
79  file->put(x);
80 }
81 
82 inline void
83 write_float(ostream *file, float x) {
84  pm_writebiglong(file, *(long *)&x);
85 }
86 
87 static int
88 read_channel_pkt(istream *file,
89  int &chained, int &size, int &type, int &channel) {
90  chained = read_uchar_SI(file);
91  size = read_uchar_SI(file);
92  type = read_uchar_SI(file);
93  channel = read_uchar_SI(file);
94 
95  if (file->eof() || file->fail()) {
96  return false;
97  }
98 
99  if (size!=8) {
100  pnmimage_soft_cat.error()
101  << "Don't know how to interpret " << size << " bits per pixel!\n";
102  return false;
103  }
104 
105  return true;
106 }
107 
108 static void
109 read_rgb(xel *row_data, xelval *, istream *file, int x, int repeat) {
110  xelval red, grn, blu;
111  red = read_uchar_SI(file);
112  grn = read_uchar_SI(file);
113  blu = read_uchar_SI(file);
114 
115  while (repeat>0) {
116  PPM_ASSIGN(row_data[x], red, grn, blu);
117  x++;
118  repeat--;
119  }
120 }
121 
122 static void
123 read_alpha(xel *, xelval *alpha_data, istream *file, int x, int repeat) {
124  xelval alpha = read_uchar_SI(file);
125 
126  while (repeat>0) {
127  alpha_data[x] = alpha;
128  x++;
129  repeat--;
130  }
131 }
132 
133 static void
134 read_rgba(xel *row_data, xelval *alpha_data, istream *file, int x, int repeat) {
135  xelval red, grn, blu, alpha;
136  red = read_uchar_SI(file);
137  grn = read_uchar_SI(file);
138  blu = read_uchar_SI(file);
139  alpha = read_uchar_SI(file);
140 
141  while (repeat>0) {
142  PPM_ASSIGN(row_data[x], red, grn, blu);
143  alpha_data[x] = alpha;
144  x++;
145  repeat--;
146  }
147 }
148 
149 
150 static int
151 read_scanline(xel *row_data, xelval *alpha_data, int cols, istream *file,
152  void (*read_data)(xel *row_data, xelval *alpha_data, istream *file,
153  int x, int repeat),
154  int ctype) {
155  if (ctype==UNCOMPRESSED) {
156  for (int x = 0; x<cols; x++) {
157  read_data(row_data, alpha_data, file, x, 1);
158  }
159  return true;
160  } else {
161  int x;
162  int num;
163 
164  x = 0;
165  while (x < cols) {
166  num = read_uchar_SI(file);
167 
168  if (num<128) {
169  // Sequence of non-repeated values.
170  num++;
171  if (x+num > cols) {
172  return false;
173  }
174  while (num>0) {
175  read_data(row_data, alpha_data, file, x, 1);
176  if (file->eof() || file->fail()) {
177  return false;
178  }
179  x++;
180  num--;
181  }
182  } else {
183  // Sequence of repeated values.
184  if (num==128) {
185  num = read_ushort_SI(file);
186  } else {
187  num -= 127;
188  }
189  if (x+num > cols) {
190  return false;
191  }
192  read_data(row_data, alpha_data, file, x, num);
193  if (file->eof() || file->fail()) {
194  return false;
195  }
196  x += num;
197  }
198  }
199 
200  return (x==cols);
201  }
202 }
203 
204 ////////////////////////////////////////////////////////////////////
205 // Function: PNMFileTypeSoftImage::Constructor
206 // Access: Public
207 // Description:
208 ////////////////////////////////////////////////////////////////////
209 PNMFileTypeSoftImage::
210 PNMFileTypeSoftImage() {
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: PNMFileTypeSoftImage::get_name
215 // Access: Public, Virtual
216 // Description: Returns a few words describing the file type.
217 ////////////////////////////////////////////////////////////////////
218 string PNMFileTypeSoftImage::
219 get_name() const {
220  return "SoftImage";
221 }
222 
223 ////////////////////////////////////////////////////////////////////
224 // Function: PNMFileTypeSoftImage::get_num_extensions
225 // Access: Public, Virtual
226 // Description: Returns the number of different possible filename
227 // extensions_softimage associated with this particular file type.
228 ////////////////////////////////////////////////////////////////////
229 int PNMFileTypeSoftImage::
230 get_num_extensions() const {
231  return num_extensions_softimage;
232 }
233 
234 ////////////////////////////////////////////////////////////////////
235 // Function: PNMFileTypeSoftImage::get_extension
236 // Access: Public, Virtual
237 // Description: Returns the nth possible filename extension
238 // associated with this particular file type, without a
239 // leading dot.
240 ////////////////////////////////////////////////////////////////////
241 string PNMFileTypeSoftImage::
242 get_extension(int n) const {
243  nassertr(n >= 0 && n < num_extensions_softimage, string());
244  return extensions_softimage[n];
245 }
246 
247 ////////////////////////////////////////////////////////////////////
248 // Function: PNMFileTypeSoftImage::get_suggested_extension
249 // Access: Public, Virtual
250 // Description: Returns a suitable filename extension (without a
251 // leading dot) to suggest for files of this type, or
252 // empty string if no suggestions are available.
253 ////////////////////////////////////////////////////////////////////
254 string PNMFileTypeSoftImage::
255 get_suggested_extension() const {
256  return "pic";
257 }
258 
259 ////////////////////////////////////////////////////////////////////
260 // Function: PNMFileTypeSoftImage::has_magic_number
261 // Access: Public, Virtual
262 // Description: Returns true if this particular file type uses a
263 // magic number to identify it, false otherwise.
264 ////////////////////////////////////////////////////////////////////
265 bool PNMFileTypeSoftImage::
266 has_magic_number() const {
267  return true;
268 }
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: PNMFileTypeSoftImage::matches_magic_number
272 // Access: Public, Virtual
273 // Description: Returns true if the indicated "magic number" byte
274 // stream (the initial few bytes read from the file)
275 // matches this particular file type, false otherwise.
276 ////////////////////////////////////////////////////////////////////
277 bool PNMFileTypeSoftImage::
278 matches_magic_number(const string &magic_number) const {
279  nassertr(magic_number.size() >= 2, false);
280  int mn =
281  ((unsigned char)magic_number[0] << 8) |
282  ((unsigned char)magic_number[1]);
283  return (mn == SOFTIMAGE_MAGIC1);
284 }
285 
286 ////////////////////////////////////////////////////////////////////
287 // Function: PNMFileTypeSoftImage::make_reader
288 // Access: Public, Virtual
289 // Description: Allocates and returns a new PNMReader suitable for
290 // reading from this file type, if possible. If reading
291 // from this file type is not supported, returns NULL.
292 ////////////////////////////////////////////////////////////////////
293 PNMReader *PNMFileTypeSoftImage::
294 make_reader(istream *file, bool owns_file, const string &magic_number) {
295  init_pnm();
296  return new Reader(this, file, owns_file, magic_number);
297 }
298 
299 ////////////////////////////////////////////////////////////////////
300 // Function: PNMFileTypeSoftImage::make_writer
301 // Access: Public, Virtual
302 // Description: Allocates and returns a new PNMWriter suitable for
303 // reading from this file type, if possible. If writing
304 // files of this type is not supported, returns NULL.
305 ////////////////////////////////////////////////////////////////////
306 PNMWriter *PNMFileTypeSoftImage::
307 make_writer(ostream *file, bool owns_file) {
308  init_pnm();
309  return new Writer(this, file, owns_file);
310 }
311 
312 
313 ////////////////////////////////////////////////////////////////////
314 // Function: PNMFileTypeSoftImage::Reader::Constructor
315 // Access: Public
316 // Description:
317 ////////////////////////////////////////////////////////////////////
318 PNMFileTypeSoftImage::Reader::
319 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
320  PNMReader(type, file, owns_file)
321 {
322  if (!read_magic_number(_file, magic_number, 4)) {
323  // No magic number, no image.
324  if (pnmimage_soft_cat.is_debug()) {
325  pnmimage_soft_cat.debug()
326  << "SoftImage image file appears to be empty.\n";
327  }
328  _is_valid = false;
329  return;
330  }
331 
332  int magic1 =
333  ((unsigned char)magic_number[0] << 8) |
334  ((unsigned char)magic_number[1]);
335  int magic2 =
336  ((unsigned char)magic_number[2] << 8) |
337  ((unsigned char)magic_number[3]);
338 
339  if (magic1 != SOFTIMAGE_MAGIC1 || magic2 != SOFTIMAGE_MAGIC2) {
340  _is_valid = false;
341  return;
342  }
343 
344  // skip version number
345  read_float(_file);
346 
347  // Skip comment
348  _file->seekg(imageCommentLength, ios::cur);
349 
350  char pict_id[4];
351  _file->read(pict_id, 4);
352  if (_file->gcount() < 4) {
353  _is_valid = false;
354  return;
355  }
356 
357  if (memcmp(pict_id, "PICT", 4)!=0) {
358  _is_valid = false;
359  return;
360  }
361 
362  _x_size = read_ushort_SI(_file);
363  _y_size = read_ushort_SI(_file);
364 
365  /* float ratio = */ read_float(_file);
366  /* int fields = */ read_ushort_SI(_file);
367  read_ushort_SI(_file);
368 
369  int chained, size, channel;
370  if (!read_channel_pkt(_file, chained, size, rgb_ctype, channel)) {
371  _is_valid = false;
372  return;
373  }
374 
375  soft_color = unknown;
376 
377  if (channel == (RGB_CHANNEL | ALPHA_CHANNEL)) {
378  // Four components in the first part: RGBA.
379  soft_color = rgba;
380 
381  } else if (channel == RGB_CHANNEL) {
382  // Three components in the first part: RGB.
383  soft_color = rgb;
384 
385  if (chained) {
386  if (!read_channel_pkt(_file, chained, size, alpha_ctype, channel)) {
387  _is_valid = false;
388  return;
389  }
390 
391  if (channel == ALPHA_CHANNEL) {
392  // Alpha component in the second part: RGBA.
393  soft_color = rgb_a;
394  }
395  }
396  }
397 
398  switch (soft_color) {
399  case rgb:
400  _num_channels = 3;
401  break;
402 
403  case rgba:
404  case rgb_a:
405  _num_channels = 4;
406  break;
407 
408  default:
409  pnmimage_soft_cat.error()
410  << "Image is not RGB or RGBA!\n";
411  _is_valid = false;
412  return;
413  }
414 
415  if (chained) {
416  pnmimage_soft_cat.error()
417  << "Unexpected additional channels in image file.\n";
418  _is_valid = false;
419  return;
420  }
421 
422  _maxval = 255;
423 
424  if (pnmimage_soft_cat.is_debug()) {
425  pnmimage_soft_cat.debug()
426  << "Reading SoftImage " << *this << "\n";
427  }
428 }
429 
430 
431 ////////////////////////////////////////////////////////////////////
432 // Function: PNMFileTypeSoftImage::Reader::supports_read_row
433 // Access: Public, Virtual
434 // Description: Returns true if this particular PNMReader supports a
435 // streaming interface to reading the data: that is, it
436 // is capable of returning the data one row at a time,
437 // via repeated calls to read_row(). Returns false if
438 // the only way to read from this file is all at once,
439 // via read_data().
440 ////////////////////////////////////////////////////////////////////
441 bool PNMFileTypeSoftImage::Reader::
442 supports_read_row() const {
443  return true;
444 }
445 
446 ////////////////////////////////////////////////////////////////////
447 // Function: PNMFileTypeSoftImage::Reader::read_row
448 // Access: Public, Virtual
449 // Description: If supports_read_row(), above, returns true, this
450 // function may be called repeatedly to read the image,
451 // one horizontal row at a time, beginning from the top.
452 // Returns true if the row is successfully read, false
453 // if there is an error or end of file.
454 ////////////////////////////////////////////////////////////////////
455 bool PNMFileTypeSoftImage::Reader::
456 read_row(xel *row_data, xelval *alpha_data, int x_size, int) {
457  if (!is_valid()) {
458  return false;
459  }
460  switch (soft_color) {
461  case rgb:
462  if (!read_scanline(row_data, alpha_data, x_size, _file,
463  read_rgb, rgb_ctype)) {
464  return false;
465  }
466  break;
467 
468  case rgba:
469  if (!read_scanline(row_data, alpha_data, x_size, _file,
470  read_rgba, rgb_ctype)) {
471  return false;
472  }
473  break;
474 
475  case rgb_a:
476  if (!read_scanline(row_data, alpha_data, x_size, _file,
477  read_rgb, rgb_ctype)) {
478  return false;
479  }
480  if (!read_scanline(row_data, alpha_data, x_size, _file,
481  read_alpha, alpha_ctype)) {
482  return false;
483  }
484  break;
485 
486  default:
487  break;
488  }
489 
490  return true;
491 }
492 
493 
494 static void
495 write_channel_pkt(ostream *file,
496  int chained, int size, int type, int channel) {
497  write_uchar_SI(file, chained);
498  write_uchar_SI(file, size);
499  write_uchar_SI(file, type);
500  write_uchar_SI(file, channel);
501 }
502 
503 static void
504 write_rgb(xel *row_data, xelval *, ostream *file, int x) {
505  write_uchar_SI(file, PPM_GETR(row_data[x]));
506  write_uchar_SI(file, PPM_GETG(row_data[x]));
507  write_uchar_SI(file, PPM_GETB(row_data[x]));
508 }
509 
510 static int
511 compare_rgb(xel *row_data, xelval *, int x1, int x2) {
512  return PPM_EQUAL(row_data[x1], row_data[x2]);
513 }
514 
515 static void
516 write_gray(xel *row_data, xelval *, ostream *file, int x) {
517  write_uchar_SI(file, PPM_GETB(row_data[x]));
518  write_uchar_SI(file, PPM_GETB(row_data[x]));
519  write_uchar_SI(file, PPM_GETB(row_data[x]));
520 }
521 
522 static int
523 compare_gray(xel *row_data, xelval *, int x1, int x2) {
524  return (PPM_GETB(row_data[x1])==PPM_GETB(row_data[x2]));
525 }
526 
527 static void
528 write_alpha(xel *, xelval *alpha_data, ostream *file, int x) {
529  write_uchar_SI(file, alpha_data[x]);
530 }
531 
532 static int
533 compare_alpha(xel *, xelval *alpha_data, int x1, int x2) {
534  return (alpha_data[x1]==alpha_data[x2]);
535 }
536 
537 static void
538 write_diff(xel *row_data, xelval *alpha_data, ostream *file,
539  void (*write_data)(xel *row_data, xelval *alpha_data, ostream *file,
540  int x),
541  int tox, int length) {
542  if (length>0) {
543  nassertv(length<=128);
544 
545  write_uchar_SI(file, length-1);
546  while (length>0) {
547  length--;
548  write_data(row_data, alpha_data, file, tox-length);
549  }
550  }
551 }
552 
553 static void
554 write_same(xel *row_data, xelval *alpha_data, ostream *file,
555  void (*write_data)(xel *row_data, xelval *alpha_data, ostream *file,
556  int x),
557  int tox, int length) {
558  if (length==1) {
559  write_diff(row_data, alpha_data, file, write_data, tox, length);
560 
561  } else if (length>0) {
562  if (length<128) {
563  write_uchar_SI(file, length+127);
564  } else {
565  write_uchar_SI(file, 128);
566  write_ushort_SI(file, length);
567  }
568  write_data(row_data, alpha_data, file, tox);
569  }
570 }
571 
572 
573 static void
574 write_scanline(xel *row_data, xelval *alpha_data, int cols, ostream *file,
575  int (*compare_data)(xel *row_data, xelval *alpha_data,
576  int x1, int x2),
577  void (*write_data)(xel *row_data, xelval *alpha_data,
578  ostream *file, int x)) {
579  int run_length = 0;
580 
581  int x = 0;
582  int same = true;
583 
584  // Go through each value in the scanline, from beginning to end, looking
585  // for runs of identical values.
586  while (x < cols) {
587 
588  if (same) {
589 
590  // We have been scanning past a run of identical values. In this case,
591  // the run is the sequence of values from x-run_length to x-1.
592 
593  if (!compare_data(row_data, alpha_data, x, x-run_length)) {
594  // Oops, the end of a run.
595 
596  if (run_length <= 1) {
597  // If run_length is only 1, no big deal--this is actually the
598  // beginning of a different-valued run.
599 
600  same = false;
601 
602  } else {
603  // Write out the old run and begin a new one. We'll be optimistic
604  // and hope the new run will also represent a sequence of identical
605  // values (until we find otherwise).
606 
607  write_same(row_data, alpha_data, file, write_data, x-1, run_length);
608  same = true;
609  run_length = 0;
610  }
611  }
612 
613  } else { // !same
614 
615  // We have been scanning past a run of different values. In this case,
616  // the run is the sequence of values from x-run_length to x-1.
617 
618  if (run_length>128) {
619  // We can't have different runs of more than 128 characters. Close
620  // off the old run.
621 
622  int excess = run_length - 128;
623  write_diff(row_data, alpha_data, file, write_data, x-excess-1, 128);
624  run_length = excess;
625 
626  } else if (run_length > 2 &&
627  compare_data(row_data, alpha_data, x, x-1) &&
628  compare_data(row_data, alpha_data, x, x-2)) {
629 
630  // If the last three values have been the same, then it's time to
631  // begin a new run of similar values. Close off the old run.
632 
633  write_diff(row_data, alpha_data, file, write_data, x-3, run_length-2);
634  same = true;
635  run_length = 2;
636  }
637  }
638 
639  x++;
640  run_length++;
641  }
642 
643  // We made it all the way to the end. Flush out the last run.
644 
645  if (run_length>0) {
646  if (same) {
647  write_same(row_data, alpha_data, file, write_data, cols-1, run_length);
648  } else {
649 
650  // Mighty unlikely, but we might have just run over the
651  // 128-pixel limit.
652  if (run_length>128) {
653  int excess = run_length - 128;
654  write_diff(row_data, alpha_data, file, write_data, cols-excess-1, 128);
655  run_length = excess;
656  }
657 
658  write_diff(row_data, alpha_data, file, write_data, cols-1, run_length);
659  }
660  }
661 }
662 
663 ////////////////////////////////////////////////////////////////////
664 // Function: PNMFileTypeSoftImage::Writer::Constructor
665 // Access: Public
666 // Description:
667 ////////////////////////////////////////////////////////////////////
668 PNMFileTypeSoftImage::Writer::
669 Writer(PNMFileType *type, ostream *file, bool owns_file) :
670  PNMWriter(type, file, owns_file)
671 {
672 }
673 
674 ////////////////////////////////////////////////////////////////////
675 // Function: PNMFileTypeSoftImage::Writer::supports_write_row
676 // Access: Public, Virtual
677 // Description: Returns true if this particular PNMWriter supports a
678 // streaming interface to writing the data: that is, it
679 // is capable of writing the image one row at a time,
680 // via repeated calls to write_row(). Returns false if
681 // the only way to write from this file is all at once,
682 // via write_data().
683 ////////////////////////////////////////////////////////////////////
684 bool PNMFileTypeSoftImage::Writer::
685 supports_write_row() const {
686  return true;
687 }
688 
689 ////////////////////////////////////////////////////////////////////
690 // Function: PNMFileTypeSoftImage::Writer::write_header
691 // Access: Public, Virtual
692 // Description: If supports_write_row(), above, returns true, this
693 // function may be called to write out the image header
694 // in preparation to writing out the image data one row
695 // at a time. Returns true if the header is
696 // successfully written, false if there is an error.
697 //
698 // It is the user's responsibility to fill in the header
699 // data via calls to set_x_size(), set_num_channels(),
700 // etc., or copy_header_from(), before calling
701 // write_header().
702 ////////////////////////////////////////////////////////////////////
703 bool PNMFileTypeSoftImage::Writer::
704 write_header() {
705  write_ushort_SI(_file, SOFTIMAGE_MAGIC1);
706  write_ushort_SI(_file, SOFTIMAGE_MAGIC2);
707  write_float(_file, imageVersionNumber);
708 
709  _file->write(imageComment, imageCommentLength);
710  _file->write("PICT", 4);
711 
712  write_ushort_SI(_file, _x_size);
713  write_ushort_SI(_file, _y_size);
714 
715  write_float(_file, 1.0); // pixel aspect ratio; we don't know.
716  write_ushort_SI(_file, 3); // fields value; we don't really know either.
717  write_ushort_SI(_file, 0); // padding
718 
719  // There doesn't seem to be a variation on SoftImage image formats for
720  // grayscale images. We'll write out grayscale as a 3-channel image.
721 
722  if (has_alpha()) {
723  write_channel_pkt(_file, 1, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
724  write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, ALPHA_CHANNEL);
725  } else {
726  write_channel_pkt(_file, 0, 8, MIXED_RUN_LENGTH, RGB_CHANNEL);
727  }
728 
729  return true;
730 }
731 
732 ////////////////////////////////////////////////////////////////////
733 // Function: PNMFileTypeSoftImage::Writer::write_row
734 // Access: Public, Virtual
735 // Description: If supports_write_row(), above, returns true, this
736 // function may be called repeatedly to write the image,
737 // one horizontal row at a time, beginning from the top.
738 // Returns true if the row is successfully written,
739 // false if there is an error.
740 //
741 // You must first call write_header() before writing the
742 // individual rows. It is also important to delete the
743 // PNMWriter class after successfully writing the last
744 // row. Failing to do this may result in some data not
745 // getting flushed!
746 ////////////////////////////////////////////////////////////////////
747 bool PNMFileTypeSoftImage::Writer::
748 write_row(xel *row_data, xelval *alpha_data) {
749  if (is_grayscale()) {
750  write_scanline(row_data, alpha_data, _x_size, _file, compare_gray, write_gray);
751 
752  } else {
753  write_scanline(row_data, alpha_data, _x_size, _file, compare_rgb, write_rgb);
754  }
755 
756  if (has_alpha()) {
757  write_scanline(row_data, alpha_data, _x_size, _file, compare_alpha, write_alpha);
758  }
759 
760  return !_file->fail();
761 }
762 
763 
764 
765 ////////////////////////////////////////////////////////////////////
766 // Function: PNMFileTypeSoftImage::register_with_read_factory
767 // Access: Public, Static
768 // Description: Registers the current object as something that can be
769 // read from a Bam file.
770 ////////////////////////////////////////////////////////////////////
771 void PNMFileTypeSoftImage::
772 register_with_read_factory() {
774  register_factory(get_class_type(), make_PNMFileTypeSoftImage);
775 }
776 
777 ////////////////////////////////////////////////////////////////////
778 // Function: PNMFileTypeSoftImage::make_PNMFileTypeSoftImage
779 // Access: Protected, Static
780 // Description: This method is called by the BamReader when an object
781 // of this type is encountered in a Bam file; it should
782 // allocate and return a new object with all the data
783 // read.
784 //
785 // In the case of the PNMFileType objects, since these
786 // objects are all shared, we just pull the object from
787 // the registry.
788 ////////////////////////////////////////////////////////////////////
789 TypedWritable *PNMFileTypeSoftImage::
790 make_PNMFileTypeSoftImage(const FactoryParams &params) {
791  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
792 }
793 
794 #endif // HAVE_SOFTIMAGE_PIC
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
Base class for objects that can be written to and read from Bam files.
Definition: typedWritable.h:37
This is the base class of a family of classes that represent particular image file types that PNMImag...
Definition: pnmFileType.h:35
static bool read_magic_number(istream *file, string &magic_number, int num_bytes)
Ensures that the first n bytes of the file are read into magic_number.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
This is an abstract base class that defines the interface for reading image files of various types...
Definition: pnmReader.h:31
This is an abstract base class that defines the interface for writing image files of various types...
Definition: pnmWriter.h:31
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85