Panda3D
Loading...
Searching...
No Matches
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 */
21PNMReader::
22~PNMReader() {
23 if (_owns_file) {
24 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
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 */
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 */
80read_pfm(PfmFile &pfm) {
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 */
94read_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 */
207supports_read_row() const {
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 */
224read_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 */
235supports_stream_read() const {
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 */
246int PNMReader::
247get_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}
bool has_alpha() const
Returns true if the image includes an alpha channel, false otherwise.
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...
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 is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
Definition pnmReader.cxx:71
virtual void prepare_read()
This method will be called before read_data() or read_row() is called.
Definition pnmReader.cxx:44
virtual bool supports_stream_read() const
Returns true if this particular PNMReader can read from a general stream (including pipes,...
virtual bool supports_read_row() const
Returns true if this particular PNMReader is capable of returning the data one row at a time,...
bool is_valid() const
Returns true if the PNMReader can be used to read data, false if something is wrong.
Definition pnmReader.I:53
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
Definition pnmReader.cxx:80
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
Definition pfmFile.h:31
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
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
STL class.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.