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, 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: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, or with a special extension, 2- or 4-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.