Panda3D
pnmFileTypePfm.cxx
1 // Filename: pnmFileTypePfm.cxx
2 // Created by: drose (04Apr98)
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 "pnmFileTypePfm.h"
16 #include "pfmFile.h"
17 #include "config_pnmimage.h"
18 
19 #include "pnmFileTypeRegistry.h"
20 #include "bamReader.h"
21 
22 TypeHandle PNMFileTypePfm::_type_handle;
23 
24 ////////////////////////////////////////////////////////////////////
25 // Function: PNMFileTypePfm::Constructor
26 // Access: Public
27 // Description:
28 ////////////////////////////////////////////////////////////////////
29 PNMFileTypePfm::
30 PNMFileTypePfm() {
31 }
32 
33 ////////////////////////////////////////////////////////////////////
34 // Function: PNMFileTypePfm::get_name
35 // Access: Public, Virtual
36 // Description: Returns a few words describing the file type.
37 ////////////////////////////////////////////////////////////////////
38 string PNMFileTypePfm::
39 get_name() const {
40  return "Portable Float Map";
41 }
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: PNMFileTypePfm::get_num_extensions
45 // Access: Public, Virtual
46 // Description: Returns the number of different possible filename
47 // extensions associated with this particular file type.
48 ////////////////////////////////////////////////////////////////////
51  return 1;
52 }
53 
54 ////////////////////////////////////////////////////////////////////
55 // Function: PNMFileTypePfm::get_extension
56 // Access: Public, Virtual
57 // Description: Returns the nth possible filename extension
58 // associated with this particular file type, without a
59 // leading dot.
60 ////////////////////////////////////////////////////////////////////
61 string PNMFileTypePfm::
62 get_extension(int n) const {
63  return "pfm";
64 }
65 
66 ////////////////////////////////////////////////////////////////////
67 // Function: PNMFileTypePfm::get_suggested_extension
68 // Access: Public, Virtual
69 // Description: Returns a suitable filename extension (without a
70 // leading dot) to suggest for files of this type, or
71 // empty string if no suggestions are available.
72 ////////////////////////////////////////////////////////////////////
73 string PNMFileTypePfm::
75  return "pfm";
76 }
77 
78 ////////////////////////////////////////////////////////////////////
79 // Function: PNMFileTypePfm::has_magic_number
80 // Access: Public, Virtual
81 // Description: Returns true if this particular file type uses a
82 // magic number to identify it, false otherwise.
83 ////////////////////////////////////////////////////////////////////
86  return true;
87 }
88 
89 ////////////////////////////////////////////////////////////////////
90 // Function: PNMFileTypePfm::matches_magic_number
91 // Access: Public, Virtual
92 // Description: Returns true if the indicated "magic number" byte
93 // stream (the initial few bytes read from the file)
94 // matches this particular file type, false otherwise.
95 ////////////////////////////////////////////////////////////////////
97 matches_magic_number(const string &magic_number) const {
98  return (magic_number.size() >= 2) &&
99  (magic_number.substr(0, 2) == "PF" ||
100  magic_number.substr(0, 2) == "Pf" ||
101  magic_number.substr(0, 2) == "pf");
102 }
103 
104 ////////////////////////////////////////////////////////////////////
105 // Function: PNMFileTypePfm::make_reader
106 // Access: Public, Virtual
107 // Description: Allocates and returns a new PNMReader suitable for
108 // reading from this file type, if possible. If reading
109 // from this file type is not supported, returns NULL.
110 ////////////////////////////////////////////////////////////////////
112 make_reader(istream *file, bool owns_file, const string &magic_number) {
113  return new Reader(this, file, owns_file, magic_number);
114 }
115 
116 ////////////////////////////////////////////////////////////////////
117 // Function: PNMFileTypePfm::make_writer
118 // Access: Public, Virtual
119 // Description: Allocates and returns a new PNMWriter suitable for
120 // reading from this file type, if possible. If writing
121 // files of this type is not supported, returns NULL.
122 ////////////////////////////////////////////////////////////////////
124 make_writer(ostream *file, bool owns_file) {
125  return new Writer(this, file, owns_file);
126 }
127 
128 
129 ////////////////////////////////////////////////////////////////////
130 // Function: PNMFileTypePfm::Reader::Constructor
131 // Access: Public
132 // Description:
133 ////////////////////////////////////////////////////////////////////
134 PNMFileTypePfm::Reader::
135 Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
136  PNMReader(type, file, owns_file)
137 {
138  read_magic_number(_file, magic_number, 2);
139 
140  if (magic_number == "pf") {
141  // In this case, we're probably reading a special-extension
142  // 4-channel pfm file, and we need a four-byte magic number to
143  // confirm this and fully identify the file format.
144  read_magic_number(_file, magic_number, 4);
145  }
146 
147  if (magic_number == "PF") {
148  _num_channels = 3;
149 
150  } else if (magic_number == "Pf") {
151  _num_channels = 1;
152 
153  } else if (magic_number == "pf2c") {
154  // Special DRZ extension.
155  _num_channels = 2;
156 
157  } else if (magic_number == "pf4c") {
158  // Special DRZ extension.
159  _num_channels = 4;
160 
161  } else {
162  pnmimage_cat.debug()
163  << "Not a PFM file\n";
164  _is_valid = false;
165  return;
166  }
167 
168  _maxval = PGM_MAXMAXVAL;
169 
170  (*_file) >> _x_size >> _y_size >> _scale;
171  if (!(*_file)) {
172  pnmimage_cat.debug()
173  << "Error parsing PFM header\n";
174  _is_valid = false;
175  return;
176  }
177 
178  // Skip the last newline/whitespace character before the raw data
179  // begins.
180  (*_file).get();
181 }
182 
183 ////////////////////////////////////////////////////////////////////
184 // Function: PNMFileTypePfm::Reader::is_floating_point
185 // Access: Public, Virtual
186 // Description: Returns true if this PNMFileType represents a
187 // floating-point image type, false if it is a normal,
188 // integer type. If this returns true, read_pfm() is
189 // implemented instead of read_data().
190 ////////////////////////////////////////////////////////////////////
193  return true;
194 }
195 
196 ////////////////////////////////////////////////////////////////////
197 // Function: PNMFileTypePfm::Reader::read_pfm
198 // Access: Public, Virtual
199 // Description: Reads floating-point data directly into the indicated
200 // PfmFile. Returns true on success, false on failure.
201 ////////////////////////////////////////////////////////////////////
204  if (!is_valid()) {
205  return false;
206  }
207 
208  bool little_endian = false;
209  if (_scale < 0) {
210  _scale = -_scale;
211  little_endian = true;
212  }
213  if (pfm_force_littleendian) {
214  little_endian = true;
215  }
216  if (pfm_reverse_dimensions) {
217  int t = _x_size;
218  _x_size = _y_size;
219  _y_size = t;
220  }
221 
222  pfm.clear(_x_size, _y_size, _num_channels);
223  pfm.set_scale(_scale);
224 
225  // So far, so good. Now read the data.
226  int size = _x_size * _y_size * _num_channels;
227 
228  pvector<PN_float32> table;
229  pfm.swap_table(table);
230 
231  (*_file).read((char *)&table[0], sizeof(PN_float32) * size);
232  if ((*_file).fail() && !(*_file).eof()) {
233  pfm.clear();
234  return false;
235  }
236 
237  // Now we may have to endian-reverse the data.
238 #ifdef WORDS_BIGENDIAN
239  bool endian_reversed = little_endian;
240 #else
241  bool endian_reversed = !little_endian;
242 #endif
243 
244  if (endian_reversed) {
245  for (int ti = 0; ti < size; ++ti) {
246  ReversedNumericData nd(&table[ti], sizeof(PN_float32));
247  nd.store_value(&table[ti], sizeof(PN_float32));
248  }
249  }
250 
251  pfm.swap_table(table);
252  return true;
253 }
254 
255 
256 ////////////////////////////////////////////////////////////////////
257 // Function: PNMFileTypePfm::Writer::Constructor
258 // Access: Public
259 // Description:
260 ////////////////////////////////////////////////////////////////////
261 PNMFileTypePfm::Writer::
262 Writer(PNMFileType *type, ostream *file, bool owns_file) :
263  PNMWriter(type, file, owns_file)
264 {
265 }
266 
267 ////////////////////////////////////////////////////////////////////
268 // Function: PNMFileTypePfm::Writer::supports_floating_point
269 // Access: Public, Virtual
270 // Description: Returns true if this PNMFileType can accept a
271 // floating-point image type, false if it can only
272 // accept a normal, integer type. If this returns true,
273 // write_pfm() is implemented.
274 ////////////////////////////////////////////////////////////////////
277  return true;
278 }
279 
280 ////////////////////////////////////////////////////////////////////
281 // Function: PNMFileTypePfm::Writer::supports_integer
282 // Access: Public, Virtual
283 // Description: Returns true if this PNMFileType can accept an
284 // integer image type, false if it can only
285 // accept a floating-point type. If this returns true,
286 // write_data() or write_row() is implemented.
287 ////////////////////////////////////////////////////////////////////
290  return false;
291 }
292 
293 ////////////////////////////////////////////////////////////////////
294 // Function: PNMFileTypePfm::Writer::write_pfm
295 // Access: Public, Virtual
296 // Description: Writes floating-point data from the indicated
297 // PfmFile. Returns true on success, false on failure.
298 ////////////////////////////////////////////////////////////////////
300 write_pfm(const PfmFile &pfm) {
301  nassertr(pfm.is_valid(), false);
302 
303  switch (pfm.get_num_channels()) {
304  case 1:
305  (*_file) << "Pf\n";
306  break;
307 
308  case 2:
309  (*_file) << "pf2c\n";
310  break;
311 
312  case 3:
313  (*_file) << "PF\n";
314  break;
315 
316  case 4:
317  (*_file) << "pf4c\n";
318  break;
319 
320  default:
321  nassertr(false, false);
322  }
323  (*_file) << pfm.get_x_size() << " " << pfm.get_y_size() << "\n";
324 
325  PN_float32 scale = cabs(pfm.get_scale());
326  if (scale == 0.0f) {
327  scale = 1.0f;
328  }
329 #ifndef WORDS_BIGENDIAN
330  // Little-endian computers must write a negative scale to indicate
331  // the little-endian nature of the output.
332  scale = -scale;
333 #endif
334  (*_file) << scale << "\n";
335 
336  int size = pfm.get_x_size() * pfm.get_y_size() * pfm.get_num_channels();
337  const pvector<PN_float32> &table = pfm.get_table();
338  (*_file).write((const char *)&table[0], sizeof(PN_float32) * size);
339 
340  if ((*_file).fail()) {
341  return false;
342  }
343  nassertr(sizeof(PN_float32) == 4, false);
344  return true;
345 }
346 
347 ////////////////////////////////////////////////////////////////////
348 // Function: PNMFileTypePfm::register_with_read_factory
349 // Access: Public, Static
350 // Description: Registers the current object as something that can be
351 // read from a Bam file.
352 ////////////////////////////////////////////////////////////////////
353 void PNMFileTypePfm::
356  register_factory(get_class_type(), make_PNMFileTypePfm);
357 }
358 
359 ////////////////////////////////////////////////////////////////////
360 // Function: PNMFileTypePfm::make_PNMFileTypePfm
361 // Access: Protected, Static
362 // Description: This method is called by the BamReader when an object
363 // of this type is encountered in a Bam file; it should
364 // allocate and return a new object with all the data
365 // read.
366 //
367 // In the case of the PNMFileType objects, since these
368 // objects are all shared, we just pull the object from
369 // the registry.
370 ////////////////////////////////////////////////////////////////////
371 TypedWritable *PNMFileTypePfm::
372 make_PNMFileTypePfm(const FactoryParams &params) {
373  return PNMFileTypeRegistry::get_global_ptr()->get_type_by_handle(get_class_type());
374 }
virtual string get_name() const
Returns a few words describing the file type.
virtual string get_extension(int n) const
Returns the nth possible filename extension associated with this particular file type, without a leading dot.
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
virtual PNMReader * make_reader(istream *file, bool owns_file=true, const string &magic_number=string())
Allocates and returns a new PNMReader suitable for reading from this file type, if possible...
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
int get_y_size() const
Returns the number of pixels in the Y direction.
int get_x_size() const
Returns the number of pixels in the X direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:39
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal...
void set_scale(PN_float32 scale)
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.I:44
virtual bool has_magic_number() const
Returns true if this particular file type uses a magic number to identify it, false otherwise...
virtual bool supports_floating_point()
Returns true if this PNMFileType can accept a floating-point image type, false if it can only accept ...
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component, or with a special extension, 2- or 4-component.
Definition: pfmFile.h:34
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
virtual bool supports_integer()
Returns true if this PNMFileType can accept an integer image type, false if it can only accept a floa...
virtual string get_suggested_extension() const
Returns a suitable filename extension (without a leading dot) to suggest for files of this type...
PN_float32 get_scale() const
The "scale" is reported in the pfm header and is probably meaningless.
Definition: pfmFile.I:33
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
NativeNumericData and ReversedNumericData work together to provide a sneaky interface for automatical...
virtual int get_num_extensions() const
Returns the number of different possible filename extensions associated with this particular file typ...
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
int get_num_channels() const
Returns the number of channels in the image.
virtual bool matches_magic_number(const string &magic_number) const
Returns true if the indicated "magic number" byte stream (the initial few bytes read from the file) m...
static void register_with_read_factory()
Registers the current object as something that can be read from a Bam file.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
void store_value(void *dest, size_t length) const
Copies the data, with byte reversal if appropriate, into the indicated numeric variable, whose address and sizeof are given.
virtual PNMWriter * make_writer(ostream *file, bool owns_file=true)
Allocates and returns a new PNMWriter suitable for reading from this file type, if possible...
void clear()
Eliminates all data in the file.
Definition: pfmFile.cxx:81