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