Panda3D
 All Classes Functions Variables Enumerations
pnmReader.cxx
1 // Filename: pnmReader.cxx
2 // Created by: drose (14Jun00)
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 "pnmReader.h"
16 #include "virtualFileSystem.h"
17 #include "thread.h"
18 
19 ////////////////////////////////////////////////////////////////////
20 // Function: PNMReader::Destructor
21 // Access: Public, Virtual
22 // Description:
23 ////////////////////////////////////////////////////////////////////
24 PNMReader::
25 ~PNMReader() {
26  if (_owns_file) {
28 
29  // We're assuming here that the file was opened via VFS. That
30  // may not necessarily be the case, but we don't make that
31  // distinction. However, at the moment at least, that
32  // distinction doesn't matter, since vfs->close_read_file()
33  // just deletes the file pointer anyway.
34  vfs->close_read_file(_file);
35  }
36  _file = (istream *)NULL;
37 }
38 
39 ////////////////////////////////////////////////////////////////////
40 // Function: PNMReader::prepare_read
41 // Access: Public, Virtual
42 // Description: This method will be called before read_data() or
43 // read_row() is called. It instructs the reader to
44 // initialize its data structures as necessary to
45 // actually perform the read operation.
46 //
47 // After this call, _x_size and _y_size should reflect
48 // the actual size that will be filled by read_data()
49 // (as possibly modified by set_read_size()).
50 ////////////////////////////////////////////////////////////////////
51 void PNMReader::
53  if (!_is_valid) {
54  return;
55  }
56 
57  _x_shift = 0;
58  _y_shift = 0;
59  _orig_x_size = _x_size;
60  _orig_y_size = _y_size;
61 
62  if (supports_read_row()) {
63  // Maybe we can quick-filter each row down as we go.
64  if (_has_read_size) {
65  _x_shift = get_reduction_shift(_x_size, _read_x_size);
66  _x_size = _x_size / (1 << _x_shift);
67  _y_shift = get_reduction_shift(_y_size, _read_y_size);
68  _y_size = _y_size / (1 << _y_shift);
69  }
70  }
71 }
72 
73 ////////////////////////////////////////////////////////////////////
74 // Function: PNMReader::is_floating_point
75 // Access: Public, Virtual
76 // Description: Returns true if this PNMFileType represents a
77 // floating-point image type, false if it is a normal,
78 // integer type. If this returns true, read_pfm() is
79 // implemented instead of read_data().
80 ////////////////////////////////////////////////////////////////////
81 bool PNMReader::
83  return false;
84 }
85 
86 ////////////////////////////////////////////////////////////////////
87 // Function: PNMReader::read_pfm
88 // Access: Public, Virtual
89 // Description: Reads floating-point data directly into the indicated
90 // PfmFile. Returns true on success, false on failure.
91 ////////////////////////////////////////////////////////////////////
92 bool PNMReader::
94  return false;
95 }
96 
97 ////////////////////////////////////////////////////////////////////
98 // Function: PNMReader::read_data
99 // Access: Public, Virtual
100 // Description: Reads in an entire image all at once, storing it in
101 // the pre-allocated _x_size * _y_size array and alpha
102 // pointers. (If the image type has no alpha channel,
103 // alpha is ignored.) Returns the number of rows
104 // correctly read.
105 //
106 // Derived classes need not override this if they
107 // instead provide supports_read_row() and read_row(),
108 // below.
109 ////////////////////////////////////////////////////////////////////
110 int PNMReader::
111 read_data(xel *array, xelval *alpha) {
112  if (!is_valid()) {
113  return 0;
114  }
115 
116  if (_x_shift == 0 && _y_shift == 0) {
117  // Read with no reduction.
118  int y;
119  for (y = 0; y < _y_size; ++y) {
120  if (!read_row(array + y * _x_size, alpha + y * _x_size, _x_size, _y_size)) {
122  return y;
123  }
124  }
125 
126  } else {
127  int x_reduction = (1 << _x_shift);
128  int y_reduction = (1 << _y_shift);
129 
130  int shift = _x_shift + _y_shift;
131 
132  // We need a temporary buffer, at least one row wide, with
133  // full-width integers, for accumulating pixel data.
134  int *accum_row_array = (int *)alloca(_orig_x_size * sizeof(int) * 3);
135  int *accum_row_alpha = (int *)alloca(_orig_x_size * sizeof(int));
136 
137  // Each time we read a row, we will actually read the full row
138  // here, before we filter it down into the above.
139  xel *orig_row_array = (xel *)alloca(_orig_x_size * sizeof(xel));
140  xelval *orig_row_alpha = (xelval *)alloca(_orig_x_size * sizeof(xelval));
141 
142  int y;
143  for (y = 0; y < _y_size; ++y) {
144  // Zero out the accumulation data, in preparation for
145  // holding the results of the below.
146  memset(accum_row_array, 0, _x_size * sizeof(int) * 3);
147  if (has_alpha()) {
148  memset(accum_row_alpha, 0, _x_size * sizeof(int));
149  }
150 
151  for (int yi = 0; yi < y_reduction; ++yi) {
152  // OK, read a row. This reads the original, full-size row.
153  if (!read_row(orig_row_array, orig_row_alpha, _orig_x_size, _orig_y_size)) {
155  return y;
156  }
157 
158  // Boil that row down to its proper, reduced size, and
159  // accumulate it into the target row.
160  xel *p = orig_row_array;
161  int *q = accum_row_array;
162  int *qstop = q + _x_size * 3;
163  while (q < qstop) {
164  for (int xi = 0; xi < x_reduction; ++xi) {
165  q[0] += (*p).r;
166  q[1] += (*p).g;
167  q[2] += (*p).b;
168  ++p;
169  }
170  q += 3;
171  }
172  if (has_alpha()) {
173  // Now do it again for the alpha channel.
174  xelval *p = orig_row_alpha;
175  int *q = accum_row_alpha;
176  int *qstop = q + _x_size;
177  while (q < qstop) {
178  for (int xi = 0; xi < x_reduction; ++xi) {
179  (*q) += (*p);
180  ++p;
181  }
182  ++q;
183  }
184  }
185  }
186 
187  // OK, now copy the accumulated pixel data into the final
188  // result.
189  xel *target_row_array = array + y * _x_size;
190  xelval *target_row_alpha = alpha + y * _x_size;
191 
192  int *p = accum_row_array;
193  xel *q = target_row_array;
194  xel *qstop = q + _x_size;
195  while (q < qstop) {
196  (*q).r = (*p++) >> shift;
197  (*q).g = (*p++) >> shift;
198  (*q).b = (*p++) >> shift;
199  ++q;
200  }
201 
202  if (has_alpha()) {
203  int *p = accum_row_alpha;
204  xelval *q = target_row_alpha;
205  xelval *qstop = q + _x_size;
206  while (q < qstop) {
207  (*q) = (*p++) >> shift;
208  ++q;
209  }
210  }
211  }
212  }
213 
214 
215  return _y_size;
216 }
217 
218 
219 ////////////////////////////////////////////////////////////////////
220 // Function: PNMReader::supports_read_row
221 // Access: Public, Virtual
222 // Description: Returns true if this particular PNMReader is capable
223 // of returning the data one row at a time, via repeated
224 // calls to read_row(). Returns false if the only way
225 // to read from this file is all at once, via
226 // read_data().
227 ////////////////////////////////////////////////////////////////////
228 bool PNMReader::
230  return false;
231 }
232 
233 ////////////////////////////////////////////////////////////////////
234 // Function: PNMReader::read_row
235 // Access: Public, Virtual
236 // Description: If supports_read_row(), above, returns true, this
237 // function may be called repeatedly to read the image,
238 // one horizontal row at a time, beginning from the top.
239 // Returns true if the row is successfully read, false
240 // if there is an error or end of file.
241 //
242 // The x_size and y_size parameters are the value of
243 // _x_size and _y_size as originally filled in by the
244 // constructor; it is the actual number of pixels in the
245 // image. (The _x_size and _y_size members may have
246 // been automatically modified by the time this method
247 // is called if we are scaling on load, so should not be
248 // used.)
249 ////////////////////////////////////////////////////////////////////
250 bool PNMReader::
251 read_row(xel *, xelval *, int, int) {
252  return false;
253 }
254 
255 
256 ////////////////////////////////////////////////////////////////////
257 // Function: PNMReader::supports_stream_read
258 // Access: Public, Virtual
259 // Description: Returns true if this particular PNMReader can read
260 // from a general stream (including pipes, etc.), or
261 // false if the reader must occasionally fseek() on its
262 // input stream, and thus only disk streams are
263 // supported.
264 ////////////////////////////////////////////////////////////////////
265 bool PNMReader::
267  return false;
268 }
269 
270 ////////////////////////////////////////////////////////////////////
271 // Function: PNMReader::get_reduction_shift
272 // Access: Private
273 // Description: Determines the reduction factor between the original
274 // size and the requested size, returned as an exponent
275 // of power of 2 (that is, a bit shift).
276 //
277 // Only power-of-two reductions are supported, since
278 // those are common, easy, and fast. Other reductions
279 // will be handled in the higher level code.
280 ////////////////////////////////////////////////////////////////////
281 int PNMReader::
282 get_reduction_shift(int orig_size, int new_size) {
283  if (new_size == 0) {
284  return 0;
285  }
286 
287  int reduction = max(orig_size / new_size, 1);
288 
289  int shift = 0;
290 
291  int r = 2;
292  while (r <= reduction) {
293  shift += 1;
294  r <<= 1;
295  }
296 
297  if ((orig_size % r) != 0) {
298  // If the reduction isn't even, never mind.
299  shift = 0;
300  }
301 
302  return shift;
303 }
virtual int read_data(xel *array, xelval *alpha)
Reads in an entire image all at once, storing it in the pre-allocated _x_size * _y_size array and alp...
Definition: pnmReader.cxx:111
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS&#39;s file system.
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal...
Definition: pnmReader.cxx:82
static void consider_yield()
Possibly suspends the current thread for the rest of the current epoch, if it has run for enough this...
Definition: thread.I:263
static void close_read_file(istream *stream)
Closes a file opened by a previous call to open_read_file().
virtual bool supports_stream_read() const
Returns true if this particular PNMReader can read from a general stream (including pipes...
Definition: pnmReader.cxx:266
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
Definition: pnmReader.cxx:93
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
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
bool is_valid() const
Returns true if the PNMReader can be used to read data, false if something is wrong.
Definition: pnmReader.I:65
bool has_alpha() const
Returns true if the image includes an alpha channel, false otherwise.
virtual void prepare_read()
This method will be called before read_data() or read_row() is called.
Definition: pnmReader.cxx:52
virtual bool supports_read_row() const
Returns true if this particular PNMReader is capable of returning the data one row at a time...
Definition: pnmReader.cxx:229
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size)
If supports_read_row(), above, returns true, this function may be called repeatedly to read the image...
Definition: pnmReader.cxx:251