Panda3D
 All Classes Functions Variables Enumerations
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 }
PNMFileType * get_type_by_handle(TypeHandle handle) const
Returns the PNMFileType instance stored in the registry for the given TypeHandle, e...
PN_float32 get_scale() const
The &quot;scale&quot; is reported in the pfm header and is probably meaningless.
Definition: pfmFile.I:33
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...
int get_num_channels() const
Returns the number of channels in the image.
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_x_size() const
Returns the number of pixels in the X direction.
int get_y_size() const
Returns the number of pixels in the Y direction.
static PNMFileTypeRegistry * get_global_ptr()
Returns a pointer to the global PNMFileTypeRegistry object.
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.
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 swap_table(vector_float &table)
This is a very low-level function that completely exchanges the PfmFile&#39;s internal table of floating-...
Definition: pfmFile.I:619
void set_scale(PN_float32 scale)
The &quot;scale&quot; is reported in the pfm header and is probably meaningless.
Definition: pfmFile.I:44
virtual string get_suggested_extension() const
Returns a suitable filename extension (without a leading dot) to suggest for files of this type...
virtual bool supports_floating_point()
Returns true if this PNMFileType can accept a floating-point image type, false if it can only accept ...
virtual int get_num_extensions() const
Returns the number of different possible filename extensions associated with this particular file typ...
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.
virtual bool matches_magic_number(const string &magic_number) const
Returns true if the indicated &quot;magic number&quot; byte stream (the initial few bytes read from the file) m...
An instance of this class is passed to the Factory when requesting it to do its business and construc...
Definition: factoryParams.h:40
virtual bool supports_integer()
Returns true if this PNMFileType can accept an integer image type, false if it can only accept a floa...
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 string get_name() const
Returns a few words describing the file type.
static WritableFactory * get_factory()
Returns the global WritableFactory for generating TypedWritable objects.
Definition: bamReader.I:213
virtual bool has_magic_number() const
Returns true if this particular file type uses a magic number to identify it, false otherwise...
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
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
virtual string get_extension(int n) const
Returns the nth possible filename extension associated with this particular file type, without a leading dot.