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) {
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
A hierarchy of directories and files that appears to be one continuous file system,...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.