more pfm fixes

This commit is contained in:
David Rose 2012-07-24 20:50:36 +00:00
parent 7fd2a81412
commit d459a084b4
3 changed files with 352 additions and 27 deletions

View File

@ -20,7 +20,7 @@
////////////////////////////////////////////////////////////////////
INLINE bool PfmFile::
is_valid() const {
return _num_channels != 0 && (_x_size * _y_size * _num_channels == (int)_table.size());
return _num_channels != 0 && (_x_size * _y_size * _num_channels <= (int)_table.size());
}
////////////////////////////////////////////////////////////////////
@ -82,6 +82,33 @@ has_point(int x, int y) const {
return _has_point(this, x, y);
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_point1
// Access: Published
// Description: Returns the 1-component point value at the indicated
// point.
////////////////////////////////////////////////////////////////////
INLINE PN_float32 PfmFile::
get_point1(int x, int y) const {
nassertr(x >= 0 && x < _x_size, 0.0);
nassertr(y >= 0 && y < _y_size, 0.0);
return _table[(y * _x_size + x) * _num_channels];
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::set_point1
// Access: Published
// Description: Replaces the 1-component point value at the indicated
// point.
////////////////////////////////////////////////////////////////////
INLINE void PfmFile::
set_point1(int x, int y, PN_float32 point) {
nassertv(!cnan(point));
nassertv(x >= 0 && x < _x_size);
nassertv(y >= 0 && y < _y_size);
_table[(y * _x_size + x) * _num_channels] = point;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::get_point
// Access: Published

View File

@ -117,7 +117,12 @@ clear(int x_size, int y_size, int num_channels) {
_table.clear();
int size = _x_size * _y_size * _num_channels;
_table.insert(_table.end(), size, (PN_float32)0.0);
// We allocate a little bit bigger to allow safe overflow: you can
// call get_point3() or get_point4() on the last point of a 1- or
// 3-channel image.
_table.insert(_table.end(), size + 4, (PN_float32)0.0);
clear_no_data_value();
}
@ -243,7 +248,11 @@ read(istream &in, const Filename &fullpath, const string &magic_number) {
// So far, so good. Now read the data.
int size = _x_size * _y_size * _num_channels;
_table.insert(_table.end(), size, (PN_float32)0.0);
// We allocate a little bit bigger to allow safe overflow: you can
// call get_point3() or get_point4() on the last point of a 1- or
// 3-channel image.
_table.insert(_table.end(), size + 4, (PN_float32)0.0);
in.read((char *)&_table[0], sizeof(PN_float32) * size);
if (in.fail() && !in.eof()) {
@ -784,27 +793,89 @@ resize(int new_x_size, int new_y_size) {
y_scale = (PN_float32)(_y_size - 1) / (PN_float32)(new_y_size - 1);
}
from_y0 = 0.0;
for (int to_y = 0; to_y < new_y_size; ++to_y) {
from_y1 = (to_y + 0.5) * y_scale;
from_y1 = min(from_y1, (PN_float32) _y_size);
from_x0 = 0.0;
for (int to_x = 0; to_x < new_x_size; ++to_x) {
from_x1 = (to_x + 0.5) * x_scale;
from_x1 = min(from_x1, (PN_float32) _x_size);
// Now the box from (from_x0, from_y0) - (from_x1, from_y1)
// but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
LPoint4f result;
box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
for (int ci = 0; ci < _num_channels; ++ci) {
new_data.push_back(result[ci]);
switch (_num_channels) {
case 1:
{
from_y0 = 0.0;
for (int to_y = 0; to_y < new_y_size; ++to_y) {
from_y1 = (to_y + 0.5) * y_scale;
from_y1 = min(from_y1, (PN_float32) _y_size);
from_x0 = 0.0;
for (int to_x = 0; to_x < new_x_size; ++to_x) {
from_x1 = (to_x + 0.5) * x_scale;
from_x1 = min(from_x1, (PN_float32) _x_size);
// Now the box from (from_x0, from_y0) - (from_x1, from_y1)
// but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
PN_float32 result;
box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
new_data.push_back(result);
from_x0 = from_x1;
}
from_y0 = from_y1;
}
from_x0 = from_x1;
}
from_y0 = from_y1;
break;
case 3:
{
from_y0 = 0.0;
for (int to_y = 0; to_y < new_y_size; ++to_y) {
from_y1 = (to_y + 0.5) * y_scale;
from_y1 = min(from_y1, (PN_float32) _y_size);
from_x0 = 0.0;
for (int to_x = 0; to_x < new_x_size; ++to_x) {
from_x1 = (to_x + 0.5) * x_scale;
from_x1 = min(from_x1, (PN_float32) _x_size);
// Now the box from (from_x0, from_y0) - (from_x1, from_y1)
// but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
LPoint3f result;
box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
new_data.push_back(result[0]);
new_data.push_back(result[1]);
new_data.push_back(result[2]);
from_x0 = from_x1;
}
from_y0 = from_y1;
}
}
break;
case 4:
{
from_y0 = 0.0;
for (int to_y = 0; to_y < new_y_size; ++to_y) {
from_y1 = (to_y + 0.5) * y_scale;
from_y1 = min(from_y1, (PN_float32) _y_size);
from_x0 = 0.0;
for (int to_x = 0; to_x < new_x_size; ++to_x) {
from_x1 = (to_x + 0.5) * x_scale;
from_x1 = min(from_x1, (PN_float32) _x_size);
// Now the box from (from_x0, from_y0) - (from_x1, from_y1)
// but not including (from_x1, from_y1) maps to the pixel (to_x, to_y).
LPoint4f result;
box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
new_data.push_back(result[0]);
new_data.push_back(result[1]);
new_data.push_back(result[2]);
new_data.push_back(result[3]);
from_x0 = from_x1;
}
from_y0 = from_y1;
}
}
break;
default:
nassertv(false);
}
nassertv(new_data.size() == new_x_size * new_y_size * _num_channels);
@ -832,7 +903,10 @@ reverse_rows() {
_table.begin() + start, _table.begin() + start + row_size);
}
nassertv(reversed.size() == _table.size());
nassertv(reversed.size() <= _table.size());
// Also add in the extra buffer at the end.
reversed.insert(reversed.end(), _table.size() - reversed.size(), (PN_float32)0.0);
_table.swap(reversed);
}
@ -987,7 +1061,11 @@ apply_crop(int x_begin, int x_end, int y_begin, int y_end) {
int new_y_size = y_end - y_begin;
Table new_table;
int new_size = new_x_size * new_y_size * _num_channels;
new_table.insert(new_table.end(), new_size, (PN_float32)0.0);
// We allocate a little bit bigger to allow safe overflow: you can
// call get_point3() or get_point4() on the last point of a 1- or
// 3-channel image.
new_table.insert(new_table.end(), new_size + 4, (PN_float32)0.0);
for (int yi = 0; yi < new_y_size; ++yi) {
memcpy(&new_table[(yi * new_x_size) * _num_channels],
@ -1184,9 +1262,31 @@ compute_sample_point(LPoint3f &result,
y *= _y_size;
PN_float32 xr = sample_radius * _x_size;
PN_float32 yr = sample_radius * _y_size;
LPoint4f result4;
box_filter_region(result4, x - xr, y - yr, x + xr, y + yr);
result.set(result4[0], result4[1], result4[2]);
switch (_num_channels) {
case 1:
{
PN_float32 result1;
box_filter_region(result1, x - xr, y - yr, x + xr, y + yr);
result.set(result1, 0.0, 0.0);
}
break;
case 3:
box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
break;
case 4:
{
LPoint4f result4;
box_filter_region(result4, x - xr, y - yr, x + xr, y + yr);
result.set(result4[0], result4[1], result4[2]);
}
break;
default:
nassertv(false);
}
}
@ -1525,6 +1625,96 @@ make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_region
// Access: Private
// Description: Averages all the points in the rectangle from x0
// .. y0 to x1 .. y1 into result. The region may be
// defined by floating-point boundaries; the result will
// be weighted by the degree of coverage of each
// included point.
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_region(PN_float32 &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const {
result = 0.0;
PN_float32 coverage = 0.0;
if (x1 < x0 || y1 < y0) {
return;
}
nassertv(y0 >= 0.0 && y1 >= 0.0);
int y = (int)y0;
// Get the first (partial) row
box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
int y_last = (int)y1;
if (y < y_last) {
y++;
while (y < y_last) {
// Get each consecutive (complete) row
box_filter_line(result, coverage, x0, y, x1, 1.0);
y++;
}
// Get the final (partial) row
PN_float32 y_contrib = y1 - (PN_float32)y_last;
if (y_contrib > 0.0001) {
box_filter_line(result, coverage, x0, y, x1, y_contrib);
}
}
if (coverage != 0.0) {
result /= coverage;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_region
// Access: Private
// Description: Averages all the points in the rectangle from x0
// .. y0 to x1 .. y1 into result. The region may be
// defined by floating-point boundaries; the result will
// be weighted by the degree of coverage of each
// included point.
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_region(LPoint3f &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const {
result = LPoint3f::zero();
PN_float32 coverage = 0.0;
if (x1 < x0 || y1 < y0) {
return;
}
nassertv(y0 >= 0.0 && y1 >= 0.0);
int y = (int)y0;
// Get the first (partial) row
box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
int y_last = (int)y1;
if (y < y_last) {
y++;
while (y < y_last) {
// Get each consecutive (complete) row
box_filter_line(result, coverage, x0, y, x1, 1.0);
y++;
}
// Get the final (partial) row
PN_float32 y_contrib = y1 - (PN_float32)y_last;
if (y_contrib > 0.0001) {
box_filter_line(result, coverage, x0, y, x1, y_contrib);
}
}
if (coverage != 0.0) {
result /= coverage;
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_region
// Access: Private
@ -1570,6 +1760,64 @@ box_filter_region(LPoint4f &result,
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_line
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_line(PN_float32 &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const {
int x = (int)x0;
// Get the first (partial) xel
box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
int x_last = (int)x1;
if (x < x_last) {
x++;
while (x < x_last) {
// Get each consecutive (complete) xel
box_filter_point(result, coverage, x, y, 1.0, y_contrib);
x++;
}
// Get the final (partial) xel
PN_float32 x_contrib = x1 - (PN_float32)x_last;
if (x_contrib > 0.0001) {
box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_line
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_line(LPoint3f &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const {
int x = (int)x0;
// Get the first (partial) xel
box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
int x_last = (int)x1;
if (x < x_last) {
x++;
while (x < x_last) {
// Get each consecutive (complete) xel
box_filter_point(result, coverage, x, y, 1.0, y_contrib);
x++;
}
// Get the final (partial) xel
PN_float32 x_contrib = x1 - (PN_float32)x_last;
if (x_contrib > 0.0001) {
box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_line
// Access: Private
@ -1599,6 +1847,42 @@ box_filter_line(LPoint4f &result, PN_float32 &coverage,
}
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_point
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_point(PN_float32 &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const {
if (!has_point(x, y)) {
return;
}
PN_float32 point = get_point1(x, y);
PN_float32 contrib = x_contrib * y_contrib;
result += point * contrib;
coverage += contrib;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_point
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
void PfmFile::
box_filter_point(LPoint3f &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const {
if (!has_point(x, y)) {
return;
}
const LPoint3f &point = get_point(x, y);
PN_float32 contrib = x_contrib * y_contrib;
result += point * contrib;
coverage += contrib;
}
////////////////////////////////////////////////////////////////////
// Function: PfmFile::box_filter_point
// Access: Private

View File

@ -57,6 +57,8 @@ PUBLISHED:
INLINE int get_num_channels() const;
INLINE bool has_point(int x, int y) const;
INLINE PN_float32 get_point1(int x, int y) const;
INLINE void set_point1(int x, int y, PN_float32 point);
INLINE const LPoint3f &get_point(int x, int y) const;
INLINE void set_point(int x, int y, const LVecBase3f &point);
INLINE void set_point(int x, int y, const LVecBase3d &point);
@ -117,10 +119,22 @@ PUBLISHED:
private:
void make_vis_mesh_geom(GeomNode *gnode, bool inverted) const;
void box_filter_region(PN_float32 &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_region(LPoint3f &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_region(LPoint4f &result,
PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1) const;
void box_filter_line(PN_float32 &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
void box_filter_line(LPoint3f &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
void box_filter_line(LPoint4f &result, PN_float32 &coverage,
PN_float32 x0, int y, PN_float32 x1, PN_float32 y_contrib) const;
void box_filter_point(PN_float32 &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
void box_filter_point(LPoint3f &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;
void box_filter_point(LPoint4f &result, PN_float32 &coverage,
int x, int y, PN_float32 x_contrib, PN_float32 y_contrib) const;