auto-scale textures at load time, without loading full-res and then downrezzing
This commit is contained in:
parent
c7a09a3926
commit
161e2cd5b3
|
|
@ -1979,6 +1979,7 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
|||
x_size = 1;
|
||||
y_size = 1;
|
||||
}
|
||||
|
||||
image = PNMImage(x_size, y_size, image.get_num_channels(),
|
||||
image.get_maxval(), image.get_type());
|
||||
image.fill(0.2, 0.3, 1.0);
|
||||
|
|
@ -1987,6 +1988,19 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
|||
}
|
||||
|
||||
} else {
|
||||
if (!image.read_header(fullpath, NULL, false)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read: " << fullpath << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (z == 0 && n == 0) {
|
||||
consider_rescale(image, fullpath.get_basename());
|
||||
} else {
|
||||
image.set_read_size(get_expected_mipmap_x_size(n),
|
||||
get_expected_mipmap_y_size(n));
|
||||
}
|
||||
|
||||
if (!image.read(fullpath, NULL, false)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read: " << fullpath << endl;
|
||||
|
|
@ -2021,6 +2035,22 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
|||
}
|
||||
|
||||
} else {
|
||||
if (!alpha_image.read_header(alpha_fullpath, NULL, true)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (image.get_x_size() != alpha_image.get_x_size() ||
|
||||
image.get_y_size() != alpha_image.get_y_size()) {
|
||||
gobj_cat.info()
|
||||
<< "Implicitly rescaling " << alpha_fullpath.get_basename()
|
||||
<< " from " << alpha_image.get_x_size() << " by "
|
||||
<< alpha_image.get_y_size() << " to " << image.get_x_size()
|
||||
<< " by " << image.get_y_size() << "\n";
|
||||
alpha_image.set_read_size(image.get_x_size(), image.get_y_size());
|
||||
}
|
||||
|
||||
if (!alpha_image.read(alpha_fullpath, NULL, true)) {
|
||||
gobj_cat.error()
|
||||
<< "Texture::read() - couldn't read (alpha): " << alpha_fullpath << endl;
|
||||
|
|
@ -2045,13 +2075,12 @@ do_read_one(const Filename &fullpath, const Filename &alpha_fullpath,
|
|||
|
||||
set_fullpath(fullpath);
|
||||
set_alpha_fullpath(alpha_fullpath);
|
||||
|
||||
consider_rescale(image, fullpath.get_basename());
|
||||
}
|
||||
|
||||
if (!alpha_fullpath.empty()) {
|
||||
// The grayscale (alpha channel) image must be the same size as the
|
||||
// main image.
|
||||
// The grayscale (alpha channel) image must be the same size as
|
||||
// the main image. This should really have been already
|
||||
// guaranteed by the above.
|
||||
if (image.get_x_size() != alpha_image.get_x_size() ||
|
||||
image.get_y_size() != alpha_image.get_y_size()) {
|
||||
gobj_cat.info()
|
||||
|
|
@ -2818,8 +2847,13 @@ clear_prepared(PreparedGraphicsObjects *prepared_objects) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Texture::consider_rescale
|
||||
// Access: Private
|
||||
// Description: Scales the PNMImage according to the whims of the
|
||||
// Config.prc file.
|
||||
// Description: Asks the PNMImage to change its scale when it reads
|
||||
// the image, according to the whims of the Config.prc
|
||||
// file.
|
||||
//
|
||||
// This method should be called after
|
||||
// pnmimage.read_header() has been called, but before
|
||||
// pnmimage.read().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Texture::
|
||||
consider_rescale(PNMImage &pnmimage, const string &name) {
|
||||
|
|
@ -2877,14 +2911,11 @@ consider_rescale(PNMImage &pnmimage, const string &name) {
|
|||
if (pnmimage.get_x_size() != new_x_size ||
|
||||
pnmimage.get_y_size() != new_y_size) {
|
||||
gobj_cat.info()
|
||||
<< "Automatically rescaling " << name << " from "
|
||||
<< "Implicitly rescaling " << name << " from "
|
||||
<< pnmimage.get_x_size() << " by " << pnmimage.get_y_size() << " to "
|
||||
<< new_x_size << " by " << new_y_size << "\n";
|
||||
|
||||
PNMImage scaled(new_x_size, new_y_size, pnmimage.get_num_channels(),
|
||||
pnmimage.get_maxval(), pnmimage.get_type());
|
||||
scaled.quick_filter_from(pnmimage);
|
||||
pnmimage = scaled;
|
||||
pnmimage.set_read_size(new_x_size, new_y_size);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,8 @@ INLINE PNMImage::
|
|||
PNMImage() {
|
||||
_array = NULL;
|
||||
_alpha = NULL;
|
||||
|
||||
clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -155,6 +157,39 @@ alpha_fill(double alpha) {
|
|||
alpha_fill_val((xelval)(alpha * get_maxval()));
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImage::set_read_size
|
||||
// Access: Published
|
||||
// Description: Specifies the size to we'd like to scale the image
|
||||
// upon reading it. This will affect the next call to
|
||||
// read(). This is usually used to reduce the image
|
||||
// size, e.g. for a thumbnail.
|
||||
//
|
||||
// If the file type reader supports it (e.g. JPEG), then
|
||||
// this will scale the image during the read operation,
|
||||
// consequently reducing memory and CPU utilization. If
|
||||
// the file type reader does not support it, this will
|
||||
// load the image normally, and them perform a linear
|
||||
// scale after it has been loaded.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PNMImage::
|
||||
set_read_size(int x_size, int y_size) {
|
||||
_read_x_size = x_size;
|
||||
_read_y_size = y_size;
|
||||
_has_read_size = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImage::clear_read_size
|
||||
// Access: Published
|
||||
// Description: Undoes the effect of a previous call to
|
||||
// set_read_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void PNMImage::
|
||||
clear_read_size() {
|
||||
_has_read_size = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMImage::is_valid
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ PNMImage::
|
|||
PNMImage(const Filename &filename, PNMFileType *type) {
|
||||
_array = NULL;
|
||||
_alpha = NULL;
|
||||
_has_read_size = false;
|
||||
|
||||
bool result = read(filename, type);
|
||||
if (!result) {
|
||||
|
|
@ -61,6 +62,7 @@ clear() {
|
|||
_maxval = 255;
|
||||
_comment.clear();
|
||||
_type = (PNMFileType *)NULL;
|
||||
_has_read_size = false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -81,6 +83,7 @@ clear(int x_size, int y_size, int num_channels,
|
|||
_maxval = maxval;
|
||||
_comment.clear();
|
||||
_type = type;
|
||||
_has_read_size = false;
|
||||
|
||||
if (has_alpha()) {
|
||||
allocate_alpha();
|
||||
|
|
@ -220,13 +223,12 @@ remix_channels(const LMatrix4f &conv) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMImage::
|
||||
read(const Filename &filename, PNMFileType *type, bool report_unknown_type) {
|
||||
clear();
|
||||
|
||||
PNMReader *reader = PNMImageHeader::make_reader(filename, type,
|
||||
report_unknown_type);
|
||||
PNMReader *reader = make_reader(filename, type, report_unknown_type);
|
||||
if (reader == (PNMReader *)NULL) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
return read(reader);
|
||||
}
|
||||
|
||||
|
|
@ -247,11 +249,10 @@ read(const Filename &filename, PNMFileType *type, bool report_unknown_type) {
|
|||
bool PNMImage::
|
||||
read(istream &data, const string &filename, PNMFileType *type,
|
||||
bool report_unknown_type) {
|
||||
clear();
|
||||
|
||||
PNMReader *reader = PNMImageHeader::make_reader
|
||||
(&data, false, filename, string(), type, report_unknown_type);
|
||||
if (reader == (PNMReader *)NULL) {
|
||||
clear();
|
||||
return false;
|
||||
}
|
||||
return read(reader);
|
||||
|
|
@ -272,6 +273,10 @@ read(istream &data, const string &filename, PNMFileType *type,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMImage::
|
||||
read(PNMReader *reader) {
|
||||
bool has_read_size = _has_read_size;
|
||||
int read_x_size = _read_x_size;
|
||||
int read_y_size = _read_y_size;
|
||||
|
||||
clear();
|
||||
|
||||
if (reader == NULL) {
|
||||
|
|
@ -283,6 +288,11 @@ read(PNMReader *reader) {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (has_read_size) {
|
||||
reader->set_read_size(read_x_size, read_y_size);
|
||||
}
|
||||
reader->prepare_read();
|
||||
|
||||
copy_header_from(*reader);
|
||||
|
||||
// We reassign y_size after reading because we might have read a
|
||||
|
|
@ -293,10 +303,20 @@ read(PNMReader *reader) {
|
|||
if (_y_size == 0) {
|
||||
clear();
|
||||
return false;
|
||||
} else {
|
||||
setup_rc();
|
||||
return true;
|
||||
}
|
||||
|
||||
setup_rc();
|
||||
|
||||
if (has_read_size && (_x_size != read_x_size || _y_size != read_y_size)) {
|
||||
// The Reader didn't comply with our size request. Do the sizing
|
||||
// explicitly, then.
|
||||
PNMImage new_image(read_x_size, read_y_size, get_num_channels(),
|
||||
get_maxval(), get_type());
|
||||
new_image.quick_filter_from(*this);
|
||||
take_from(new_image);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ PUBLISHED:
|
|||
INLINE void alpha_fill(double alpha = 0.0);
|
||||
void alpha_fill_val(xelval alpha = 0);
|
||||
|
||||
INLINE void set_read_size(int x_size, int y_size);
|
||||
INLINE void clear_read_size();
|
||||
|
||||
bool read(const Filename &filename, PNMFileType *type = NULL,
|
||||
bool report_unknown_type = true);
|
||||
bool read(istream &data, const string &filename = string(),
|
||||
|
|
@ -239,6 +242,9 @@ private:
|
|||
xel *_array;
|
||||
xelval *_alpha;
|
||||
double _default_rc, _default_gc, _default_bc;
|
||||
|
||||
int _read_x_size, _read_y_size;
|
||||
bool _has_read_size;
|
||||
};
|
||||
|
||||
#include "pnmImage.I"
|
||||
|
|
|
|||
|
|
@ -35,8 +35,9 @@
|
|||
// false.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMImageHeader::
|
||||
read_header(const Filename &filename, PNMFileType *type) {
|
||||
PNMReader *reader = make_reader(filename, type);
|
||||
read_header(const Filename &filename, PNMFileType *type,
|
||||
bool report_unknown_type) {
|
||||
PNMReader *reader = make_reader(filename, type, report_unknown_type);
|
||||
if (reader != (PNMReader *)NULL) {
|
||||
(*this) = (*reader);
|
||||
delete reader;
|
||||
|
|
|
|||
|
|
@ -82,7 +82,8 @@ PUBLISHED:
|
|||
INLINE PNMFileType *get_type() const;
|
||||
INLINE void set_type(PNMFileType *type);
|
||||
|
||||
bool read_header(const Filename &filename, PNMFileType *type = NULL);
|
||||
bool read_header(const Filename &filename, PNMFileType *type = NULL,
|
||||
bool report_unknown_type = true);
|
||||
|
||||
PNMReader *make_reader(const Filename &filename,
|
||||
PNMFileType *type = NULL,
|
||||
|
|
|
|||
|
|
@ -26,10 +26,28 @@ PNMReader(PNMFileType *type, istream *file, bool owns_file) :
|
|||
_type(type),
|
||||
_owns_file(owns_file),
|
||||
_file(file),
|
||||
_is_valid(true)
|
||||
_is_valid(true),
|
||||
_has_read_size(false)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMReader::set_read_size
|
||||
// Access: Public
|
||||
// Description: Instructs the reader to attempt to scale the image to
|
||||
// the indicated size while reading it. The reader may
|
||||
// or may not follow this suggestion, or may follow it
|
||||
// only partially (e.g. by reading a file which is
|
||||
// slightly reduced in size, but not the precise size
|
||||
// requested).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMReader::
|
||||
set_read_size(int x_size, int y_size) {
|
||||
_read_x_size = x_size;
|
||||
_read_y_size = y_size;
|
||||
_has_read_size = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMReader::get_type
|
||||
// Access: Public
|
||||
|
|
|
|||
|
|
@ -39,6 +39,40 @@ PNMReader::
|
|||
_file = (istream *)NULL;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMReader::prepare_read
|
||||
// Access: Public, Virtual
|
||||
// Description: This method will be called before read_data() or
|
||||
// read_row() is called. It instructs the reader to
|
||||
// initialize its data structures as necessary to
|
||||
// actually perform the read operation.
|
||||
//
|
||||
// After this call, _x_size and _y_size should reflect
|
||||
// the actual size that will be filled by read_data()
|
||||
// (as possibly modified by set_read_size()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMReader::
|
||||
prepare_read() {
|
||||
if (!_is_valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
_x_shift = 0;
|
||||
_y_shift = 0;
|
||||
_orig_x_size = _x_size;
|
||||
_orig_y_size = _y_size;
|
||||
|
||||
if (supports_read_row()) {
|
||||
// Maybe we can quick-filter each row down as we go.
|
||||
if (_has_read_size) {
|
||||
_x_shift = get_reduction_shift(_x_size, _read_x_size);
|
||||
_x_size = _x_size / (1 << _x_shift);
|
||||
_y_shift = get_reduction_shift(_y_size, _read_y_size);
|
||||
_y_size = _y_size / (1 << _y_shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMReader::read_data
|
||||
// Access: Public, Virtual
|
||||
|
|
@ -58,12 +92,102 @@ read_data(xel *array, xelval *alpha) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int y;
|
||||
for (y = 0; y < _y_size; y++) {
|
||||
if (!read_row(array + y * _x_size, alpha + y * _x_size)) {
|
||||
return y;
|
||||
if (_x_shift == 0 && _y_shift == 0) {
|
||||
// Read with no reduction.
|
||||
int y;
|
||||
for (y = 0; y < _y_size; ++y) {
|
||||
if (!read_row(array + y * _x_size, alpha + y * _x_size, _x_size, _y_size)) {
|
||||
return y;
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
int x_reduction = (1 << _x_shift);
|
||||
int y_reduction = (1 << _y_shift);
|
||||
|
||||
int shift = _x_shift + _y_shift;
|
||||
|
||||
// We need a temporary buffer, at least one row wide, with
|
||||
// full-width integers, for accumulating pixel data.
|
||||
int *accum_row_array = (int *)alloca(_orig_x_size * sizeof(int) * 3);
|
||||
int *accum_row_alpha = (int *)alloca(_orig_x_size * sizeof(int));
|
||||
|
||||
// Each time we read a row, we will actually read the full row
|
||||
// here, before we filter it down into the above.
|
||||
xel *orig_row_array = (xel *)alloca(_orig_x_size * sizeof(xel));
|
||||
xelval *orig_row_alpha = (xelval *)alloca(_orig_x_size * sizeof(xelval));
|
||||
|
||||
int y;
|
||||
for (y = 0; y < _y_size; ++y) {
|
||||
// Zero out the accumulation data, in preparation for
|
||||
// holding the results of the below.
|
||||
memset(accum_row_array, 0, _x_size * sizeof(int) * 3);
|
||||
if (has_alpha()) {
|
||||
memset(accum_row_alpha, 0, _x_size * sizeof(int));
|
||||
}
|
||||
|
||||
for (int yi = 0; yi < y_reduction; ++yi) {
|
||||
// OK, read a row. This reads the original, full-size row.
|
||||
if (!read_row(orig_row_array, orig_row_alpha, _orig_x_size, _orig_y_size)) {
|
||||
return y;
|
||||
}
|
||||
|
||||
// Boil that row down to its proper, reduced size, and
|
||||
// accumulate it into the target row.
|
||||
xel *p = orig_row_array;
|
||||
int *q = accum_row_array;
|
||||
int *qstop = q + _x_size * 3;
|
||||
while (q < qstop) {
|
||||
for (int xi = 0; xi < x_reduction; ++xi) {
|
||||
q[0] += (*p).r;
|
||||
q[1] += (*p).g;
|
||||
q[2] += (*p).b;
|
||||
++p;
|
||||
}
|
||||
q += 3;
|
||||
}
|
||||
if (has_alpha()) {
|
||||
// Now do it again for the alpha channel.
|
||||
xelval *p = orig_row_alpha;
|
||||
int *q = accum_row_alpha;
|
||||
int *qstop = q + _x_size;
|
||||
while (q < qstop) {
|
||||
for (int xi = 0; xi < x_reduction; ++xi) {
|
||||
(*q) += (*p);
|
||||
++p;
|
||||
}
|
||||
++q;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// OK, now copy the accumulated pixel data into the final
|
||||
// result.
|
||||
xel *target_row_array = array + y * _x_size;
|
||||
xelval *target_row_alpha = alpha + y * _x_size;
|
||||
|
||||
int *p = accum_row_array;
|
||||
xel *q = target_row_array;
|
||||
xel *qstop = q + _x_size;
|
||||
while (q < qstop) {
|
||||
(*q).r = (*p++) >> shift;
|
||||
(*q).g = (*p++) >> shift;
|
||||
(*q).b = (*p++) >> shift;
|
||||
++q;
|
||||
}
|
||||
|
||||
if (has_alpha()) {
|
||||
int *p = accum_row_alpha;
|
||||
xelval *q = target_row_alpha;
|
||||
xelval *qstop = q + _x_size;
|
||||
while (q < qstop) {
|
||||
(*q) = (*p++) >> shift;
|
||||
++q;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return _y_size;
|
||||
}
|
||||
|
|
@ -91,9 +215,17 @@ supports_read_row() const {
|
|||
// one horizontal row at a time, beginning from the top.
|
||||
// Returns true if the row is successfully read, false
|
||||
// if there is an error or end of file.
|
||||
//
|
||||
// The x_size and y_size parameters are the value of
|
||||
// _x_size and _y_size as originally filled in by the
|
||||
// constructor; it is the actual number of pixels in the
|
||||
// image. (The _x_size and _y_size members may have
|
||||
// been automatically modified by the time this method
|
||||
// is called if we are scaling on load, so should not be
|
||||
// used.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMReader::
|
||||
read_row(xel *, xelval *) {
|
||||
read_row(xel *, xelval *, int, int) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -111,3 +243,38 @@ bool PNMReader::
|
|||
supports_stream_read() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMReader::get_reduction_shift
|
||||
// Access: Private
|
||||
// Description: Determines the reduction factor between the original
|
||||
// size and the requested size, returned as an exponent
|
||||
// of power of 2 (that is, a bit shift).
|
||||
//
|
||||
// Only power-of-two reductions are supported, since
|
||||
// those are common, easy, and fast. Other reductions
|
||||
// will be handled in the higher level code.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
int PNMReader::
|
||||
get_reduction_shift(int orig_size, int new_size) {
|
||||
if (new_size == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int reduction = max(orig_size / new_size, 1);
|
||||
|
||||
int shift = 0;
|
||||
|
||||
int r = 2;
|
||||
while (r <= reduction) {
|
||||
shift += 1;
|
||||
r <<= 1;
|
||||
}
|
||||
|
||||
if ((orig_size % r) != 0) {
|
||||
// If the reduction isn't even, never mind.
|
||||
shift = 0;
|
||||
}
|
||||
|
||||
return shift;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,22 +38,33 @@ protected:
|
|||
|
||||
public:
|
||||
virtual ~PNMReader();
|
||||
INLINE void set_read_size(int x_size, int y_size);
|
||||
|
||||
INLINE PNMFileType *get_type() const;
|
||||
|
||||
virtual void prepare_read();
|
||||
virtual int read_data(xel *array, xelval *alpha);
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
|
||||
virtual bool supports_stream_read() const;
|
||||
|
||||
INLINE bool is_valid() const;
|
||||
|
||||
private:
|
||||
int get_reduction_shift(int orig_size, int new_size);
|
||||
|
||||
protected:
|
||||
PNMFileType *_type;
|
||||
bool _owns_file;
|
||||
istream *_file;
|
||||
bool _is_valid;
|
||||
|
||||
int _read_x_size, _read_y_size;
|
||||
bool _has_read_size;
|
||||
|
||||
int _x_shift, _y_shift;
|
||||
int _orig_x_size, _orig_y_size;
|
||||
};
|
||||
|
||||
#include "pnmReader.I"
|
||||
|
|
|
|||
|
|
@ -90,18 +90,6 @@ ConfigVariableInt jpeg_quality
|
|||
"size)."));
|
||||
|
||||
|
||||
// These control the scaling that is automatically performed on a JPEG
|
||||
// file for decompression. You might specify to scale down by a
|
||||
// fraction, e.g. 1/8, by specifying jpeg_scale_num = 1 and
|
||||
// jpeg_scale_denom = 8. This will reduce decompression time
|
||||
// correspondingly. Attempting to use this to scale up, or to scale
|
||||
// by any fraction other than an even power of two, may not be
|
||||
// supported.
|
||||
ConfigVariableInt jpeg_scale_num
|
||||
("jpeg-scale-num", 1);
|
||||
ConfigVariableInt jpeg_scale_denom
|
||||
("jpeg-scale-denom", 1);
|
||||
|
||||
ConfigVariableInt bmp_bpp
|
||||
("bmp-bpp", 0,
|
||||
PRC_DESC("This controls how many bits per pixel are written out for BMP "
|
||||
|
|
|
|||
|
|
@ -52,8 +52,6 @@ extern ConfigVariableBool tga_colormap;
|
|||
extern ConfigVariableBool tga_grayscale;
|
||||
|
||||
extern ConfigVariableInt jpeg_quality;
|
||||
extern ConfigVariableInt jpeg_scale_num;
|
||||
extern ConfigVariableInt jpeg_scale_denom;
|
||||
|
||||
extern ConfigVariableInt bmp_bpp;
|
||||
|
||||
|
|
|
|||
|
|
@ -229,7 +229,7 @@ supports_read_row() const {
|
|||
// if there is an error or end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMFileTypeAlias::Reader::
|
||||
read_row(xel *row_data, xelval *) {
|
||||
read_row(xel *row_data, xelval *, int x_size, int) {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -239,9 +239,9 @@ read_row(xel *row_data, xelval *) {
|
|||
unsigned char red, grn, blu;
|
||||
|
||||
x = 0;
|
||||
while (x < _x_size) {
|
||||
while (x < x_size) {
|
||||
num = read_uchar_ALIAS(_file);
|
||||
if (num==0 || x+num > _x_size) {
|
||||
if (num==0 || x+num > x_size) {
|
||||
return false;
|
||||
}
|
||||
blu = read_uchar_ALIAS(_file);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public:
|
|||
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
|
||||
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
};
|
||||
|
||||
class Writer : public PNMWriter {
|
||||
|
|
|
|||
|
|
@ -254,10 +254,10 @@ supports_read_row() const {
|
|||
// if there is an error or end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMFileTypeIMG::Reader::
|
||||
read_row(xel *row_data, xelval *) {
|
||||
read_row(xel *row_data, xelval *, int x_size, int) {
|
||||
int x;
|
||||
xelval red, grn, blu;
|
||||
for (x = 0; x < _x_size; x++) {
|
||||
for (x = 0; x < x_size; x++) {
|
||||
red = read_uchar_IMG(_file);
|
||||
grn = read_uchar_IMG(_file);
|
||||
blu = read_uchar_IMG(_file);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public:
|
|||
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
|
||||
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
};
|
||||
|
||||
class Writer : public PNMWriter {
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ public:
|
|||
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
|
||||
~Reader();
|
||||
|
||||
virtual void prepare_read();
|
||||
virtual int read_data(xel *array, xelval *alpha);
|
||||
|
||||
private:
|
||||
|
|
|
|||
|
|
@ -295,9 +295,36 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
|||
* See libjpeg.doc for more info.
|
||||
*/
|
||||
|
||||
_num_channels = _cinfo.num_components;
|
||||
_x_size = (int)_cinfo.image_width;
|
||||
_y_size = (int)_cinfo.image_height;
|
||||
_maxval = MAXJSAMPLE;
|
||||
|
||||
/* Step 6: set parameters for decompression */
|
||||
_cinfo.scale_num = jpeg_scale_num;
|
||||
_cinfo.scale_denom = jpeg_scale_denom;
|
||||
_cinfo.scale_num = 1;
|
||||
_cinfo.scale_denom = 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PNMFileTypeJPG::Reader::prepare_read
|
||||
// Access: Public, Virtual
|
||||
// Description: This method will be called before read_data() or
|
||||
// read_row() is called. It instructs the reader to
|
||||
// initialize its data structures as necessary to
|
||||
// actually perform the read operation.
|
||||
//
|
||||
// After this call, _x_size and _y_size should reflect
|
||||
// the actual size that will be filled by read_data()
|
||||
// (as possibly modified by set_read_size()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void PNMFileTypeJPG::Reader::
|
||||
prepare_read() {
|
||||
if (_has_read_size && _read_x_size != 0 && _read_y_size != 0) {
|
||||
// Attempt to get the scale close to our target scale.
|
||||
int x_reduction = _cinfo.image_width / _read_x_size;
|
||||
int y_reduction = _cinfo.image_height / _read_y_size;
|
||||
_cinfo.scale_denom = max(min(x_reduction, y_reduction), 1);
|
||||
}
|
||||
|
||||
/* Step 7: Start decompressor */
|
||||
|
||||
|
|
@ -309,7 +336,6 @@ Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number) :
|
|||
_num_channels = _cinfo.output_components;
|
||||
_x_size = (int)_cinfo.output_width;
|
||||
_y_size = (int)_cinfo.output_height;
|
||||
_maxval = MAXJSAMPLE;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ public:
|
|||
virtual ~Reader();
|
||||
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
|
||||
typedef struct {
|
||||
long start; /* offset in file */
|
||||
|
|
|
|||
|
|
@ -182,33 +182,33 @@ supports_read_row() const {
|
|||
// if there is an error or end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMFileTypeSGI::Reader::
|
||||
read_row(xel *row_data, xelval *alpha_data) {
|
||||
read_row(xel *row_data, xelval *alpha_data, int x_size, int y_size) {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
nassertr(current_row >= 0, false);
|
||||
|
||||
ScanElem *red = (ScanElem *)alloca(_x_size * sizeof(ScanElem));
|
||||
ScanElem *grn = (ScanElem *)alloca(_x_size * sizeof(ScanElem));
|
||||
ScanElem *blu = (ScanElem *)alloca(_x_size * sizeof(ScanElem));
|
||||
ScanElem *alpha = (ScanElem *)alloca(_x_size * sizeof(ScanElem));
|
||||
ScanElem *red = (ScanElem *)alloca(x_size * sizeof(ScanElem));
|
||||
ScanElem *grn = (ScanElem *)alloca(x_size * sizeof(ScanElem));
|
||||
ScanElem *blu = (ScanElem *)alloca(x_size * sizeof(ScanElem));
|
||||
ScanElem *alpha = (ScanElem *)alloca(x_size * sizeof(ScanElem));
|
||||
|
||||
read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, red,
|
||||
read_channel(_file, x_size, y_size, _num_channels, bpc, table, red,
|
||||
table_start, 0, current_row);
|
||||
|
||||
if (!is_grayscale()) {
|
||||
read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, grn,
|
||||
read_channel(_file, x_size, y_size, _num_channels, bpc, table, grn,
|
||||
table_start, 1, current_row);
|
||||
read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, blu,
|
||||
read_channel(_file, x_size, y_size, _num_channels, bpc, table, blu,
|
||||
table_start, 2, current_row);
|
||||
}
|
||||
|
||||
if (has_alpha()) {
|
||||
read_channel(_file, _x_size, _y_size, _num_channels, bpc, table, alpha,
|
||||
read_channel(_file, x_size, y_size, _num_channels, bpc, table, alpha,
|
||||
table_start, _num_channels - 1, current_row);
|
||||
}
|
||||
|
||||
for (int x = 0; x < _x_size; x++) {
|
||||
for (int x = 0; x < x_size; x++) {
|
||||
if (is_grayscale()) {
|
||||
PPM_PUTB(row_data[x], (xelval)red[x]);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -454,31 +454,31 @@ supports_read_row() const {
|
|||
// if there is an error or end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMFileTypeSoftImage::Reader::
|
||||
read_row(xel *row_data, xelval *alpha_data) {
|
||||
read_row(xel *row_data, xelval *alpha_data, int x_size, int) {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
switch (soft_color) {
|
||||
case rgb:
|
||||
if (!read_scanline(row_data, alpha_data, _x_size, _file,
|
||||
if (!read_scanline(row_data, alpha_data, x_size, _file,
|
||||
read_rgb, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case rgba:
|
||||
if (!read_scanline(row_data, alpha_data, _x_size, _file,
|
||||
if (!read_scanline(row_data, alpha_data, x_size, _file,
|
||||
read_rgba, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case rgb_a:
|
||||
if (!read_scanline(row_data, alpha_data, _x_size, _file,
|
||||
if (!read_scanline(row_data, alpha_data, x_size, _file,
|
||||
read_rgb, rgb_ctype)) {
|
||||
return false;
|
||||
}
|
||||
if (!read_scanline(row_data, alpha_data, _x_size, _file,
|
||||
if (!read_scanline(row_data, alpha_data, x_size, _file,
|
||||
read_alpha, alpha_ctype)) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public:
|
|||
Reader(PNMFileType *type, istream *file, bool owns_file, string magic_number);
|
||||
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
|
||||
private:
|
||||
enum { unknown, rgb, rgba, rgb_a } soft_color;
|
||||
|
|
|
|||
|
|
@ -592,7 +592,7 @@ supports_read_row() const {
|
|||
// if there is an error or end of file.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool PNMFileTypeTIFF::Reader::
|
||||
read_row(xel *row_data, xelval *alpha_data) {
|
||||
read_row(xel *row_data, xelval *alpha_data, int x_size, int) {
|
||||
if (!is_valid()) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -639,7 +639,7 @@ read_row(xel *row_data, xelval *alpha_data) {
|
|||
|
||||
switch ( photomet ) {
|
||||
case PHOTOMETRIC_MINISBLACK:
|
||||
for ( col = 0; col < _x_size; ++col )
|
||||
for ( col = 0; col < x_size; ++col )
|
||||
{
|
||||
sample = (this->*next_sample)(buf_ptr, bits_left);
|
||||
gray = sample;
|
||||
|
|
@ -661,7 +661,7 @@ read_row(xel *row_data, xelval *alpha_data) {
|
|||
break;
|
||||
|
||||
case PHOTOMETRIC_MINISWHITE:
|
||||
for ( col = 0; col < _x_size; ++col )
|
||||
for ( col = 0; col < x_size; ++col )
|
||||
{
|
||||
sample = (this->*next_sample)(buf_ptr, bits_left);
|
||||
gray = _maxval - sample;
|
||||
|
|
@ -685,7 +685,7 @@ read_row(xel *row_data, xelval *alpha_data) {
|
|||
break;
|
||||
|
||||
case PHOTOMETRIC_PALETTE:
|
||||
for ( col = 0; col < _x_size; ++col )
|
||||
for ( col = 0; col < x_size; ++col )
|
||||
{
|
||||
sample = (this->*next_sample)(buf_ptr, bits_left);
|
||||
row_data[col] = colormap[sample];
|
||||
|
|
@ -712,7 +712,7 @@ read_row(xel *row_data, xelval *alpha_data) {
|
|||
break;
|
||||
|
||||
case PHOTOMETRIC_RGB:
|
||||
for ( col = 0; col < _x_size; ++col ) {
|
||||
for ( col = 0; col < x_size; ++col ) {
|
||||
sample = (this->*next_sample)(buf_ptr, bits_left);
|
||||
r = sample;
|
||||
sample = (this->*next_sample)(buf_ptr, bits_left);
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ public:
|
|||
virtual ~Reader();
|
||||
|
||||
virtual bool supports_read_row() const;
|
||||
virtual bool read_row(xel *array, xelval *alpha);
|
||||
virtual bool read_row(xel *array, xelval *alpha, int x_size, int y_size);
|
||||
|
||||
private:
|
||||
xelval next_sample_lt_8(unsigned char *&buf_ptr, int &bits_left) const;
|
||||
|
|
|
|||
Loading…
Reference in New Issue