37 _has_no_data_value =
false;
38 _has_no_data_threshold =
false;
39 _no_data_value = LPoint4f::zero();
40 _has_point = has_point_noop;
52 _has_no_data_value(copy._has_no_data_value),
53 _has_no_data_threshold(copy._has_no_data_threshold),
54 _no_data_value(copy._no_data_value),
55 _has_point(copy._has_point)
63 operator = (
const PfmFile ©) {
64 PNMImageHeader::operator = (copy);
67 _has_no_data_value = copy._has_no_data_value;
68 _has_no_data_threshold = copy._has_no_data_threshold;
69 _no_data_value = copy._no_data_value;
70 _has_point = copy._has_point;
92 clear(
int x_size,
int y_size,
int num_channels) {
93 nassertv(x_size >= 0 && y_size >= 0);
94 nassertv((num_channels > 0 && num_channels <= 4) ||
95 (x_size == 0 && y_size == 0 && num_channels == 0));
100 _num_channels = num_channels;
103 int size = _x_size * _y_size * _num_channels;
108 _table.insert(_table.end(), size + 4, (PN_float32)0.0);
124 Filename filename = Filename::binary_filename(fullpath);
126 if (file ==
nullptr) {
129 <<
"Could not find " << fullpath <<
"\n";
133 if (pnmimage_cat.is_debug()) {
135 <<
"Reading PFM file " << filename <<
"\n";
138 istream *in = file->open_read_file(
true);
139 bool success =
read(*in, fullpath);
155 if (reader ==
nullptr) {
171 if (reader ==
nullptr) {
183 if (!pnm.
read(reader)) {
190 bool success = reader->
read_pfm(*
this);
207 <<
"PFM file is invalid.\n";
211 Filename filename = Filename::binary_filename(fullpath);
215 <<
"Unable to open " << filename <<
"\n";
219 if (pnmimage_cat.is_debug()) {
221 <<
"Writing PFM file " << filename <<
"\n";
224 return write(out, fullpath);
238 if (writer ==
nullptr) {
242 return write(writer);
252 if (writer ==
nullptr) {
267 if (!
store(pnmimage)) {
296 switch (num_channels) {
299 for (
int yi = 0; yi < pnmimage.
get_y_size(); ++yi) {
300 for (
int xi = 0; xi < pnmimage.
get_x_size(); ++xi) {
301 _table[yi * _x_size + xi] = pnmimage.
get_gray(xi, yi);
309 for (
int yi = 0; yi < pnmimage.
get_y_size(); ++yi) {
310 for (
int xi = 0; xi < pnmimage.
get_x_size(); ++xi) {
311 PN_float32 *point = &_table[(yi * _x_size + xi) * _num_channels];
312 point[0] = pnmimage.
get_gray(xi, yi);
321 for (
int yi = 0; yi < pnmimage.
get_y_size(); ++yi) {
322 for (
int xi = 0; xi < pnmimage.
get_x_size(); ++xi) {
323 PN_float32 *point = &_table[(yi * _x_size + xi) * _num_channels];
335 for (
int yi = 0; yi < pnmimage.
get_y_size(); ++yi) {
336 for (
int xi = 0; xi < pnmimage.
get_x_size(); ++xi) {
337 PN_float32 *point = &_table[(yi * _x_size + xi) * _num_channels];
349 nassert_raise(
"unexpected channel count");
368 switch (num_channels) {
373 pnmimage.
set_gray(xi, yi, _table[yi * _x_size + xi]);
384 pnmimage.
set_gray(xi, yi, point[0]);
396 pnmimage.
set_xel(xi, yi, point[0], point[1], point[2]);
407 pnmimage.
set_xel_a(xi, yi, point[0], point[1], point[2], point[3]);
414 nassert_raise(
"unexpected channel count");
464 const float *value = &_table[(yi * _x_size + xi) * _num_channels];
465 bool in_range =
true;
466 for (
int ci = 0; ci < _num_channels; ++ci) {
467 if (value[ci] < min_point[ci] || value[ci] > max_point[ci]) {
472 pnmimage.
set_gray(xi, yi, (
float)in_range);
484 switch (_num_channels) {
487 for (
int yi = 0; yi < _y_size; ++yi) {
488 for (
int xi = 0; xi < _x_size; ++xi) {
489 _table[(yi * _x_size + xi)] = value[0];
497 for (
int yi = 0; yi < _y_size; ++yi) {
498 for (
int xi = 0; xi < _x_size; ++xi) {
499 (*(LPoint2f *)&_table[(yi * _x_size + xi) * _num_channels]).set(value[0], value[1]);
507 for (
int yi = 0; yi < _y_size; ++yi) {
508 for (
int xi = 0; xi < _x_size; ++xi) {
509 (*(LPoint3f *)&_table[(yi * _x_size + xi) * _num_channels]).set(value[0], value[1], value[2]);
517 for (
int yi = 0; yi < _y_size; ++yi) {
518 for (
int xi = 0; xi < _x_size; ++xi) {
519 *(LPoint4f *)&_table[(yi * _x_size + xi) * _num_channels] = value;
532 PN_float32 nan = make_nan((PN_float32)0.0);
533 LPoint4f nan4(nan, nan, nan, nan);
542 fill(_no_data_value);
551 nassertv(channel >= 0 && channel < _num_channels);
553 for (
int yi = 0; yi < _y_size; ++yi) {
554 for (
int xi = 0; xi < _x_size; ++xi) {
555 _table[(yi * _x_size + xi) * _num_channels + channel] = value;
565 PN_float32 nan = make_nan((PN_float32)0.0);
575 nassertv(channel >= 0 && channel < _num_channels);
577 if (!_has_no_data_value) {
580 for (
int yi = 0; yi < _y_size; ++yi) {
581 for (
int xi = 0; xi < _x_size; ++xi) {
583 _table[(yi * _x_size + xi) * _num_channels + channel] = value;
596 PN_float32 nan = make_nan((PN_float32)0.0);
608 result = LPoint3f::zero();
610 int min_x = int(ceil(x - radius));
611 int min_y = int(ceil(y - radius));
612 int max_x = int(floor(x + radius));
613 int max_y = int(floor(y + radius));
619 int x_size = max_x - min_x + 1;
620 int y_size = max_y - min_y + 1;
621 int size = x_size * y_size;
627 mini_grid.insert(mini_grid.end(), size, MiniGridCell());
630 min_x = max(min_x, 0);
631 min_y = max(min_y, 0);
632 max_x = min(max_x, _x_size - 1);
633 max_y = min(max_y, _y_size - 1);
635 bool got_any =
false;
637 for (yi = min_y; yi <= max_y; ++yi) {
638 for (xi = min_x; xi <= max_x; ++xi) {
643 int gi = (yi - min_y) * y_size + (xi - min_x);
644 nassertr(gi >= 0 && gi < size,
false);
645 mini_grid[gi]._sxi = xi;
646 mini_grid[gi]._syi = yi;
647 mini_grid[gi]._dist = 0;
657 for (yi = 0; yi < y_size; ++yi) {
658 for (xi = 0; xi < x_size; ++xi) {
659 int gi = yi * x_size + xi;
660 if (mini_grid[gi]._dist == 0) {
661 int sxi = mini_grid[gi]._sxi;
662 int syi = mini_grid[gi]._syi;
663 fill_mini_grid(&mini_grid[0], x_size, y_size, xi + 1, yi, 1, sxi, syi);
664 fill_mini_grid(&mini_grid[0], x_size, y_size, xi - 1, yi, 1, sxi, syi);
665 fill_mini_grid(&mini_grid[0], x_size, y_size, xi, yi + 1, 1, sxi, syi);
666 fill_mini_grid(&mini_grid[0], x_size, y_size, xi, yi - 1, 1, sxi, syi);
672 for (
int gi = 0; gi < size; ++gi) {
673 int sxi = mini_grid[gi]._sxi;
674 int syi = mini_grid[gi]._syi;
679 result /= PN_float32(size);
690 result = LPoint3f::zero();
692 x = (x * _x_size - 0.5);
693 y = (y * _y_size - 0.5);
695 int min_x = int(floor(x));
696 int min_y = int(floor(y));
698 PN_float32 frac_x = x - min_x;
699 PN_float32 frac_y = y - min_y;
701 LPoint3f p00(LPoint3f::zero()), p01(LPoint3f::zero()), p10(LPoint3f::zero()), p11(LPoint3f::zero());
702 PN_float32 w00 = 0.0, w01 = 0.0, w10 = 0.0, w11 = 0.0;
705 w00 = (1.0 - frac_y) * (1.0 - frac_x);
709 w10 = (1.0 - frac_y) * frac_x;
713 w01 = frac_y * (1.0 - frac_x);
717 w11 = frac_y * frac_x;
721 PN_float32 net_w = w00 + w01 + w10 + w11;
726 result = (p00 * w00 + p01 * w01 + p10 * w10 + p11 * w11) / net_w;
738 bool any_points =
false;
740 min_depth = LVecBase3f::zero();
741 max_depth = LVecBase3f::zero();
743 for (
int yi = 0; yi < _y_size; ++yi) {
744 for (
int xi = 0; xi < _x_size; ++xi) {
755 min_depth[0] = min(min_depth[0], p[0]);
756 min_depth[1] = min(min_depth[1], p[1]);
757 min_depth[2] = min(min_depth[2], p[2]);
758 max_depth[0] = max(max_depth[0], p[0]);
759 max_depth[1] = max(max_depth[1], p[1]);
760 max_depth[2] = max(max_depth[2], p[2]);
779 if (y_begin >= _y_size) {
781 x_begin = x_end = y_begin = y_end = 0;
789 nassertr(y_end > y_begin,
false);
796 nassertr(x_begin < _x_size,
false);
802 nassertr(x_end > x_begin,
false);
814 nassertr(y >= 0 && y < _y_size &&
815 x_begin >= 0 && x_begin <= x_end && x_end <= _x_size,
false);
817 if (!_has_no_data_value) {
820 for (
int x = x_begin; x < x_end; ++x) {
835 nassertr(x >= 0 && x < _x_size &&
836 y_begin >= 0 && y_begin <= y_end && y_end <= _y_size,
false);
838 if (!_has_no_data_value) {
841 for (
int y = y_begin; y < y_end; ++y) {
859 if (num_channels > 0) {
860 num_channels = min(num_channels, _num_channels);
861 _has_no_data_value =
true;
862 _has_no_data_threshold =
false;
863 _no_data_value = LPoint4f::zero();
864 PN_float32 nan = make_nan((PN_float32)0.0);
865 for (
int i = 0; i < num_channels; ++i) {
866 _no_data_value[i] = nan;
868 switch (num_channels) {
870 _has_point = has_point_nan_1;
873 _has_point = has_point_nan_2;
876 _has_point = has_point_nan_3;
879 _has_point = has_point_nan_4;
882 nassert_raise(
"unexpected channel count");
896 nassertv(is_valid());
898 _has_no_data_value =
true;
899 _has_no_data_threshold =
false;
900 _no_data_value = no_data_value;
901 switch (_num_channels) {
903 _has_point = has_point_1;
906 _has_point = has_point_2;
909 _has_point = has_point_3;
912 _has_point = has_point_4;
915 nassert_raise(
"unexpected channel count");
926 nassertv(is_valid());
928 _has_no_data_value =
true;
929 _has_no_data_threshold =
true;
930 _no_data_value = no_data_value;
931 switch (_num_channels) {
933 _has_point = has_point_threshold_1;
936 _has_point = has_point_threshold_2;
939 _has_point = has_point_threshold_3;
942 _has_point = has_point_threshold_4;
945 nassert_raise(
"unexpected channel count");
957 if (_x_size == 0 || _y_size == 0 || new_x_size == 0 || new_y_size == 0) {
958 clear(new_x_size, new_y_size, _num_channels);
962 if (new_x_size == _x_size && new_y_size == _y_size) {
967 result.
clear(new_x_size, new_y_size, _num_channels);
968 if (_has_no_data_value) {
969 result.
fill(_no_data_value);
972 if (pfm_resize_quick && new_x_size <= _x_size && new_y_size <= _y_size) {
979 if (pfm_resize_gaussian) {
986 _table.swap(result._table);
987 _x_size = new_x_size;
988 _y_size = new_y_size;
999 if (_x_size == 0 || _y_size == 0) {
1004 new_data.reserve(_table.size());
1006 PN_float32 from_x0, from_x1, from_y0, from_y1;
1011 PN_float32 x_scale = 1.0;
1012 PN_float32 y_scale = 1.0;
1015 x_scale = (PN_float32)orig_x_size / (PN_float32)_x_size;
1018 y_scale = (PN_float32)orig_y_size / (PN_float32)_y_size;
1021 switch (_num_channels) {
1025 for (
int to_y = 0; to_y < _y_size; ++to_y) {
1026 from_y1 = (to_y + 1.0) * y_scale;
1027 from_y1 = min(from_y1, (PN_float32)orig_y_size);
1030 for (
int to_x = 0; to_x < _x_size; ++to_x) {
1031 from_x1 = (to_x + 1.0) * x_scale;
1032 from_x1 = min(from_x1, (PN_float32)orig_x_size);
1037 from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
1038 new_data.push_back(result);
1050 for (
int to_y = 0; to_y < _y_size; ++to_y) {
1051 from_y1 = (to_y + 1.0) * y_scale;
1052 from_y1 = min(from_y1, (PN_float32)orig_y_size);
1055 for (
int to_x = 0; to_x < _x_size; ++to_x) {
1056 from_x1 = (to_x + 1.0) * x_scale;
1057 from_x1 = min(from_x1, (PN_float32)orig_x_size);
1062 from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
1063 new_data.push_back(result[0]);
1064 new_data.push_back(result[1]);
1076 for (
int to_y = 0; to_y < _y_size; ++to_y) {
1077 from_y1 = (to_y + 1.0) * y_scale;
1078 from_y1 = min(from_y1, (PN_float32)orig_y_size);
1081 for (
int to_x = 0; to_x < _x_size; ++to_x) {
1082 from_x1 = (to_x + 1.0) * x_scale;
1083 from_x1 = min(from_x1, (PN_float32)orig_x_size);
1088 from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
1089 new_data.push_back(result[0]);
1090 new_data.push_back(result[1]);
1091 new_data.push_back(result[2]);
1103 for (
int to_y = 0; to_y < _y_size; ++to_y) {
1104 from_y1 = (to_y + 1.0) * y_scale;
1105 from_y1 = min(from_y1, (PN_float32)orig_y_size);
1108 for (
int to_x = 0; to_x < _x_size; ++to_x) {
1109 from_x1 = (to_x + 1.0) * x_scale;
1110 from_x1 = min(from_x1, (PN_float32)orig_x_size);
1115 from.box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
1116 new_data.push_back(result[0]);
1117 new_data.push_back(result[1]);
1118 new_data.push_back(result[2]);
1119 new_data.push_back(result[3]);
1129 nassert_raise(
"unexpected channel count");
1133 new_data.push_back(0.0);
1134 new_data.push_back(0.0);
1135 new_data.push_back(0.0);
1136 new_data.push_back(0.0);
1138 nassertv(new_data.size() == _table.size());
1139 _table.swap(new_data);
1147 nassertv(is_valid());
1150 reversed.reserve(_table.size());
1151 int row_size = _x_size * _num_channels;
1152 for (
int yi = 0; yi < _y_size; ++yi) {
1153 int source_yi = _y_size - 1 - yi;
1154 int start = source_yi * row_size;
1155 reversed.insert(reversed.end(),
1156 _table.begin() + start, _table.begin() + start + row_size);
1159 nassertv(reversed.size() <= _table.size());
1161 reversed.insert(reversed.end(), _table.size() - reversed.size(), (PN_float32)0.0);
1163 _table.swap(reversed);
1174 flip(
bool flip_x,
bool flip_y,
bool transpose) {
1175 nassertv(is_valid());
1178 flipped.reserve(_table.size());
1182 for (
int xi = 0; xi < _x_size; ++xi) {
1183 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
1184 for (
int yi = 0; yi < _y_size; ++yi) {
1185 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
1186 const PN_float32 *p = &_table[(source_yi * _x_size + source_xi) * _num_channels];
1187 for (
int ci = 0; ci < _num_channels; ++ci) {
1188 flipped.push_back(p[ci]);
1199 for (
int yi = 0; yi < _y_size; ++yi) {
1200 int source_yi = !flip_y ? yi : _y_size - 1 - yi;
1201 for (
int xi = 0; xi < _x_size; ++xi) {
1202 int source_xi = !flip_x ? xi : _x_size - 1 - xi;
1203 const PN_float32 *p = &_table[(source_yi * _x_size + source_xi) * _num_channels];
1204 for (
int ci = 0; ci < _num_channels; ++ci) {
1205 flipped.push_back(p[ci]);
1211 nassertv(flipped.size() <= _table.size());
1213 flipped.insert(flipped.end(), _table.size() - flipped.size(), (PN_float32)0.0);
1215 _table.swap(flipped);
1223 nassertv(is_valid());
1226 switch (num_channels) {
1229 for (
int yi = 0; yi < _y_size; ++yi) {
1230 for (
int xi = 0; xi < _x_size; ++xi) {
1235 LPoint3f po = transform.xform_point(LPoint3f(pi, 0.0, 0.0));
1244 for (
int yi = 0; yi < _y_size; ++yi) {
1245 for (
int xi = 0; xi < _x_size; ++xi) {
1250 LPoint3f po = transform.xform_point(LPoint3f(pi[0], pi[1], 0.0));
1259 for (
int yi = 0; yi < _y_size; ++yi) {
1260 for (
int xi = 0; xi < _x_size; ++xi) {
1265 transform.xform_point_general_in_place(p);
1273 for (
int yi = 0; yi < _y_size; ++yi) {
1274 for (
int xi = 0; xi < _x_size; ++xi) {
1279 transform.xform_in_place(p);
1306 int working_x_size = (int)cceil(_x_size * scale_factor);
1307 int working_y_size = (int)cceil(_y_size * scale_factor);
1309 working_x_size = max(working_x_size, dist.
get_x_size());
1310 working_y_size = max(working_y_size, dist.
get_y_size());
1312 const PfmFile *source_p =
this;
1314 if ((*this).get_x_size() != working_x_size || (*this).get_y_size() != working_y_size) {
1316 scaled_source = (*this);
1317 scaled_source.
resize(working_x_size, working_y_size);
1318 source_p = &scaled_source;
1321 const PfmFile *dist_p = &dist;
1326 scaled_dist.
resize(working_x_size, working_y_size);
1327 dist_p = &scaled_dist;
1331 result.
clear(working_x_size, working_y_size, _num_channels);
1333 if (_has_no_data_value) {
1335 result.
fill(_no_data_value);
1338 for (
int yi = 0; yi < working_y_size; ++yi) {
1339 for (
int xi = 0; xi < working_x_size; ++xi) {
1345 if (!source_p->calc_bilinear_point(p, uv[0], 1.0 - uv[1])) {
1348 nassertv(!p.is_nan());
1349 result.
set_point(xi, working_y_size - 1 - yi, p);
1354 result.
resize(_x_size, _y_size);
1356 nassertv(result._table.size() == _table.size());
1357 _table.swap(result._table);
1379 int working_x_size = (int)cceil(_x_size * scale_factor);
1380 int working_y_size = (int)cceil(_y_size * scale_factor);
1382 working_x_size = max(working_x_size, dist.
get_x_size());
1383 working_y_size = max(working_y_size, dist.
get_y_size());
1385 const PfmFile *source_p =
this;
1387 if ((*this).get_x_size() != working_x_size || (*this).get_y_size() != working_y_size) {
1389 scaled_source = (*this);
1390 scaled_source.
resize(working_x_size, working_y_size);
1391 source_p = &scaled_source;
1394 const PfmFile *dist_p = &dist;
1399 scaled_dist.
resize(working_x_size, working_y_size);
1400 dist_p = &scaled_dist;
1404 result.
clear(working_x_size, working_y_size, _num_channels);
1406 if (_has_no_data_value) {
1408 result.
fill(_no_data_value);
1411 for (
int yi = 0; yi < working_y_size; ++yi) {
1412 for (
int xi = 0; xi < working_x_size; ++xi) {
1413 if (!source_p->has_point(xi, yi)) {
1416 LPoint2f uv = source_p->get_point2(xi, yi);
1421 result.
set_point(xi, yi, LPoint3f(p[0], 1.0 - p[1], p[2]));
1426 result.
resize(_x_size, _y_size);
1428 nassertv(result._table.size() == _table.size());
1429 _table.swap(result._table);
1439 for (
int yi = 0; yi < _y_size; ++yi) {
1440 for (
int xi = 0; xi < _x_size; ++xi) {
1462 nassertv(is_valid() && other.is_valid());
1463 nassertv(other._x_size == _x_size && other._y_size == _y_size && other._num_channels == _num_channels);
1465 if (!_has_no_data_value) {
1470 size_t point_size = _num_channels *
sizeof(PN_float32);
1471 for (
int y = 0; y < _y_size; ++y) {
1472 for (
int x = 0; x < _x_size; ++x) {
1474 memcpy(&_table[(y * _x_size + x) * _num_channels],
1475 &other._table[(y * _x_size + x) * _num_channels],
1491 nassertv(is_valid() && other.is_valid());
1492 nassertv(other._x_size == _x_size && other._y_size == _y_size);
1494 if (!other._has_no_data_value || !_has_no_data_value) {
1499 for (
int yi = 0; yi < _y_size; ++yi) {
1500 for (
int xi = 0; xi < _x_size; ++xi) {
1514 nassertv(is_valid() && other.is_valid());
1515 nassertv(other._x_size == _x_size && other._y_size == _y_size);
1519 for (
int yi = 0; yi < _y_size; ++yi) {
1520 for (
int xi = 0; xi < _x_size; ++xi) {
1532 nassertv(is_valid() && other.is_valid());
1533 nassertv(other._x_size == _x_size && other._y_size == _y_size);
1537 for (
int yi = 0; yi < _y_size; ++yi) {
1538 for (
int xi = 0; xi < _x_size; ++xi) {
1552 nassertv(x_begin >= 0 && x_begin <= x_end && x_end <= _x_size);
1553 nassertv(y_begin >= 0 && y_begin <= y_end && y_end <= _y_size);
1555 int new_x_size = x_end - x_begin;
1556 int new_y_size = y_end - y_begin;
1558 size_t new_size = (size_t)new_x_size * (
size_t)new_y_size * (size_t)_num_channels;
1563 new_table.insert(new_table.end(), new_size + 4, (PN_float32)0.0);
1565 for (
int yi = 0; yi < new_y_size; ++yi) {
1566 memcpy(&new_table[(yi * new_x_size) * _num_channels],
1567 &_table[((yi + y_begin) * _x_size + x_begin) * _num_channels],
1568 new_x_size *
sizeof(PN_float32) * _num_channels);
1571 nassertv(new_table.size() == new_size + 4);
1572 _table.swap(new_table);
1573 _x_size = new_x_size;
1574 _y_size = new_y_size;
1583 clear(x_size, y_size, 3);
1585 LPoint2f uv_scale(1.0, 1.0);
1587 uv_scale[0] = 1.0f / PN_float32(_x_size);
1590 uv_scale[1] = 1.0f / PN_float32(_y_size);
1593 for (
int yi = 0; yi < _y_size; ++yi) {
1594 for (
int xi = 0; xi < _x_size; ++xi) {
1595 LPoint3f uv((PN_float32(xi) + 0.5) * uv_scale[0],
1596 (PN_float32(yi) + 0.5) * uv_scale[1],
1611 float xr,
float yr,
float exponent) {
1612 int minx = max((
int)cceil(xc - xr), 0);
1613 int maxx = min((
int)cfloor(xc + xr), _x_size - 1);
1614 int miny = max((
int)cceil(yc - yr), 0);
1615 int maxy = min((
int)cfloor(yc + yr), _y_size - 1);
1618 for (
int yi = miny; yi <= maxy; ++yi) {
1619 for (
int xi = minx; xi <= maxx; ++xi) {
1620 float xd = ((float)xi - xc) / xr;
1621 float yd = ((float)yi - yc) / yr;
1622 float r2 = xd * xd + yd * yd;
1626 PN_float32 t = (PN_float32)cpow(1.0f - csqrt(r2), exponent);
1628 PN_float32 *f = &_table[(yi * _x_size + xi) * _num_channels];
1629 for (
int ci = 0; ci < _num_channels; ++ci) {
1630 f[ci] += delta[ci] * t;
1647 min_point.set(0.0f, 0.0f, 0.0f);
1648 max_point.set(0.0f, 0.0f, 0.0f);
1650 bool found_any =
false;
1651 for (
int yi = 0; yi < _y_size; ++yi) {
1652 for (
int xi = 0; xi < _x_size; ++xi) {
1657 const LPoint3f &point =
get_point(xi, yi);
1663 min_point.set(min(min_point[0], point[0]),
1664 min(min_point[1], point[1]),
1665 min(min_point[2], point[2]));
1666 max_point.set(max(max_point[0], point[0]),
1667 max(max_point[1], point[1]),
1668 max(max_point[2], point[2]));
1691 compute_planar_bounds(
const LPoint2f ¢er, PN_float32 point_dist, PN_float32 sample_radius,
bool points_only)
const {
1692 LPoint3f p0, p1, p2, p3;
1693 compute_sample_point(p0, center[0] + point_dist, center[1] - point_dist, sample_radius);
1694 compute_sample_point(p1, center[0] + point_dist, center[1] + point_dist, sample_radius);
1695 compute_sample_point(p2, center[0] - point_dist, center[1] + point_dist, sample_radius);
1696 compute_sample_point(p3, center[0] - point_dist, center[1] - point_dist, sample_radius);
1700 normal[0] = p0[1] * p1[2] - p0[2] * p1[1];
1701 normal[1] = p0[2] * p1[0] - p0[0] * p1[2];
1702 normal[2] = p0[0] * p1[1] - p0[1] * p1[0];
1704 normal[0] += p1[1] * p2[2] - p1[2] * p2[1];
1705 normal[1] += p1[2] * p2[0] - p1[0] * p2[2];
1706 normal[2] += p1[0] * p2[1] - p1[1] * p2[0];
1708 normal[0] += p2[1] * p3[2] - p2[2] * p3[1];
1709 normal[1] += p2[2] * p3[0] - p2[0] * p3[2];
1710 normal[2] += p2[0] * p3[1] - p2[1] * p3[0];
1712 normal[0] += p3[1] * p0[2] - p3[2] * p0[1];
1713 normal[1] += p3[2] * p0[0] - p3[0] * p0[2];
1714 normal[2] += p3[0] * p0[1] - p3[1] * p0[0];
1718 LVector3f up = (p1 - p0) + (p2 - p3);
1719 LPoint3f pcenter = ((p0 + p1 + p2 + p3) * 0.25);
1724 look_at(rotate, normal, up);
1727 rinv.invert_from(rotate);
1729 LPoint3f trans = pcenter * rinv;
1730 rinv.set_row(3, -trans);
1731 rotate.invert_from(rinv);
1734 PN_float32 min_x, min_y, min_z, max_x, max_y, max_z;
1736 const LPoint3f points[4] = {
1742 const LPoint3f &point = points[0];
1750 for (
int i = 1; i < 4; ++i) {
1751 const LPoint3f &point = points[i];
1752 min_x = min(min_x, point[0]);
1753 min_y = min(min_y, point[1]);
1754 min_z = min(min_z, point[2]);
1755 max_x = max(max_x, point[0]);
1756 max_y = max(max_y, point[1]);
1757 max_z = max(max_z, point[2]);
1760 bool got_point =
false;
1761 for (
int yi = 0; yi < _y_size; ++yi) {
1762 for (
int xi = 0; xi < _x_size; ++xi) {
1767 LPoint3f point =
get_point(xi, yi) * rinv;
1777 min_x = min(min_x, point[0]);
1778 min_y = min(min_y, point[1]);
1779 min_z = min(min_z, point[2]);
1780 max_x = max(max_x, point[0]);
1781 max_y = max(max_y, point[1]);
1782 max_z = max(max_z, point[2]);
1800 CoordinateSystem cs = get_default_coordinate_system();
1804 (LPoint3(min_x, min_y, min_z), LPoint3(max_x, min_y, min_z),
1805 LPoint3(min_x, max_y, min_z), LPoint3(max_x, max_y, min_z),
1806 LPoint3(min_x, min_y, max_z), LPoint3(max_x, min_y, max_z),
1807 LPoint3(min_x, max_y, max_z), LPoint3(max_x, max_y, max_z));
1812 (LPoint3(min_x, min_y, min_z), LPoint3(max_x, min_y, min_z),
1813 LPoint3(min_x, min_y, max_z), LPoint3(max_x, min_y, max_z),
1814 LPoint3(min_x, max_y, min_z), LPoint3(max_x, max_y, min_z),
1815 LPoint3(min_x, max_y, max_z), LPoint3(max_x, max_y, max_z));
1820 (LPoint3(max_x, min_y, max_z), LPoint3(min_x, min_y, max_z),
1821 LPoint3(max_x, max_y, max_z), LPoint3(min_x, max_y, max_z),
1822 LPoint3(max_x, min_y, min_z), LPoint3(min_x, min_y, min_z),
1823 LPoint3(max_x, max_y, min_z), LPoint3(min_x, max_y, min_z));
1828 (LPoint3(max_x, max_y, min_z), LPoint3(min_x, max_y, min_z),
1829 LPoint3(max_x, max_y, max_z), LPoint3(min_x, max_y, max_z),
1830 LPoint3(max_x, min_y, min_z), LPoint3(min_x, min_y, min_z),
1831 LPoint3(max_x, min_y, max_z), LPoint3(min_x, min_y, max_z));
1835 nassert_raise(
"invalid coordinate system");
1840 bounds->xform(LCAST(PN_stdfloat, rotate));
1852 compute_sample_point(LPoint3f &result,
1853 PN_float32 x, PN_float32 y, PN_float32 sample_radius)
const {
1856 PN_float32 xr = sample_radius * _x_size;
1857 PN_float32 yr = sample_radius * _y_size;
1859 switch (_num_channels) {
1863 box_filter_region(result1, x - xr, y - yr, x + xr, y + yr);
1864 result.set(result1, 0.0, 0.0);
1871 box_filter_region(result2, x - xr, y - yr, x + xr, y + yr);
1872 result.set(result2[0], result2[1], 0.0);
1877 box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
1883 box_filter_region(result4, x - xr, y - yr, x + xr, y + yr);
1884 result.set(result4[0], result4[1], result4[2]);
1889 nassert_raise(
"unexpected channel count");
1902 copy_sub_image(
const PfmFile ©,
int xto,
int yto,
1903 int xfrom,
int yfrom,
int x_size,
int y_size) {
1904 int xmin, ymin, xmax, ymax;
1905 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1906 xmin, ymin, xmax, ymax);
1909 switch (_num_channels) {
1912 for (y = ymin; y < ymax; y++) {
1913 for (x = xmin; x < xmax; x++) {
1914 if (copy.
has_point(x - xmin + xfrom, y - ymin + yfrom)) {
1924 for (y = ymin; y < ymax; y++) {
1925 for (x = xmin; x < xmax; x++) {
1926 if (copy.
has_point(x - xmin + xfrom, y - ymin + yfrom)) {
1936 for (y = ymin; y < ymax; y++) {
1937 for (x = xmin; x < xmax; x++) {
1938 if (copy.
has_point(x - xmin + xfrom, y - ymin + yfrom)) {
1948 for (y = ymin; y < ymax; y++) {
1949 for (x = xmin; x < xmax; x++) {
1950 if (copy.
has_point(x - xmin + xfrom, y - ymin + yfrom)) {
1966 int xfrom,
int yfrom,
int x_size,
int y_size,
1967 float pixel_scale) {
1968 int xmin, ymin, xmax, ymax;
1969 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
1970 xmin, ymin, xmax, ymax);
1973 switch (_num_channels) {
1976 for (y = ymin; y < ymax; y++) {
1977 for (x = xmin; x < xmax; x++) {
1988 for (y = ymin; y < ymax; y++) {
1989 for (x = xmin; x < xmax; x++) {
2000 for (y = ymin; y < ymax; y++) {
2001 for (x = xmin; x < xmax; x++) {
2012 for (y = ymin; y < ymax; y++) {
2013 for (x = xmin; x < xmax; x++) {
2030 int xfrom,
int yfrom,
int x_size,
int y_size,
2031 float pixel_scale) {
2032 int xmin, ymin, xmax, ymax;
2033 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
2034 xmin, ymin, xmax, ymax);
2037 switch (_num_channels) {
2040 for (y = ymin; y < ymax; y++) {
2041 for (x = xmin; x < xmax; x++) {
2052 for (y = ymin; y < ymax; y++) {
2053 for (x = xmin; x < xmax; x++) {
2064 for (y = ymin; y < ymax; y++) {
2065 for (x = xmin; x < xmax; x++) {
2076 for (y = ymin; y < ymax; y++) {
2077 for (x = xmin; x < xmax; x++) {
2095 int xfrom,
int yfrom,
int x_size,
int y_size,
2096 float pixel_scale) {
2097 int xmin, ymin, xmax, ymax;
2098 setup_sub_image(copy, xto, yto, xfrom, yfrom, x_size, y_size,
2099 xmin, ymin, xmax, ymax);
2102 switch (_num_channels) {
2105 for (y = ymin; y < ymax; y++) {
2106 for (x = xmin; x < xmax; x++) {
2108 float val =
get_point1(x, y) / copy.
get_point1(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
2121 for (y = ymin; y < ymax; y++) {
2122 for (x = xmin; x < xmax; x++) {
2124 LPoint2f p = copy.
get_point2(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
2136 for (y = ymin; y < ymax; y++) {
2137 for (x = xmin; x < xmax; x++) {
2139 LPoint3f p = copy.
get_point3(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
2152 for (y = ymin; y < ymax; y++) {
2153 for (x = xmin; x < xmax; x++) {
2155 LPoint4f p = copy.
get_point4(x - xmin + xfrom, y - ymin + yfrom) * pixel_scale;
2175 nassertv(is_valid());
2177 switch (_num_channels) {
2180 for (
int y = 0; y < _y_size; ++y) {
2181 for (
int x = 0; x < _x_size; ++x) {
2194 for (
int y = 0; y < _y_size; ++y) {
2195 for (
int x = 0; x < _x_size; ++x) {
2207 for (
int y = 0; y < _y_size; ++y) {
2208 for (
int x = 0; x < _x_size; ++x) {
2220 for (
int y = 0; y < _y_size; ++y) {
2221 for (
int x = 0; x < _x_size; ++x) {
2250 const PfmFile &pixel_values) {
2259 nassertv(v >= 0 && v < pixel_values.
get_x_size());
2267 nassertv(v >= 0 && v < pixel_values.
get_x_size());
2275 nassertv(v >= 0 && v < pixel_values.
get_x_size());
2283 nassertv(v >= 0 && v < pixel_values.
get_x_size());
2297 float c3_exponent) {
2298 switch (_num_channels) {
2301 for (
int yi = 0; yi < _y_size; ++yi) {
2302 for (
int xi = 0; xi < _x_size; ++xi) {
2303 float *val = &_table[(yi * _x_size + xi)];
2304 val[0] = cpow(val[0], c0_exponent);
2312 for (
int yi = 0; yi < _y_size; ++yi) {
2313 for (
int xi = 0; xi < _x_size; ++xi) {
2314 float *val = &_table[(yi * _x_size + xi) * _num_channels];
2315 val[0] = cpow(val[0], c0_exponent);
2316 val[1] = cpow(val[1], c1_exponent);
2324 for (
int yi = 0; yi < _y_size; ++yi) {
2325 for (
int xi = 0; xi < _x_size; ++xi) {
2326 float *val = &_table[(yi * _x_size + xi) * _num_channels];
2327 val[0] = cpow(val[0], c0_exponent);
2328 val[1] = cpow(val[1], c1_exponent);
2329 val[2] = cpow(val[2], c2_exponent);
2337 for (
int yi = 0; yi < _y_size; ++yi) {
2338 for (
int xi = 0; xi < _x_size; ++xi) {
2339 float *val = &_table[(yi * _x_size + xi) * _num_channels];
2340 val[0] = cpow(val[0], c0_exponent);
2341 val[1] = cpow(val[1], c1_exponent);
2342 val[2] = cpow(val[2], c2_exponent);
2343 val[3] = cpow(val[3], c3_exponent);
2355 output(ostream &out)
const {
2356 out <<
"floating-point image: " << _x_size <<
" by " << _y_size <<
" pixels, " 2357 << _num_channels <<
" channels.";
2366 box_filter_region(PN_float32 &result,
2367 PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1)
const {
2369 PN_float32 coverage = 0.0;
2371 if (x1 < x0 || y1 < y0) {
2374 nassertv(y0 >= 0.0 && y1 >= 0.0);
2378 box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
2380 int y_last = (int)y1;
2383 while (y < y_last) {
2385 box_filter_line(result, coverage, x0, y, x1, 1.0);
2390 PN_float32 y_contrib = y1 - (PN_float32)y_last;
2391 if (y_contrib > 0.0001) {
2392 box_filter_line(result, coverage, x0, y, x1, y_contrib);
2396 if (coverage != 0.0) {
2407 box_filter_region(LPoint2f &result,
2408 PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1)
const {
2409 result = LPoint2f::zero();
2410 PN_float32 coverage = 0.0;
2412 if (x1 < x0 || y1 < y0) {
2415 nassertv(y0 >= 0.0 && y1 >= 0.0);
2419 box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
2421 int y_last = (int)y1;
2424 while (y < y_last) {
2426 box_filter_line(result, coverage, x0, y, x1, 1.0);
2431 PN_float32 y_contrib = y1 - (PN_float32)y_last;
2432 if (y_contrib > 0.0001) {
2433 box_filter_line(result, coverage, x0, y, x1, y_contrib);
2437 if (coverage != 0.0) {
2448 box_filter_region(LPoint3f &result,
2449 PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1)
const {
2450 result = LPoint3f::zero();
2451 PN_float32 coverage = 0.0;
2453 if (x1 < x0 || y1 < y0) {
2456 nassertv(y0 >= 0.0 && y1 >= 0.0);
2460 box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
2462 int y_last = (int)y1;
2465 while (y < y_last) {
2467 box_filter_line(result, coverage, x0, y, x1, 1.0);
2472 PN_float32 y_contrib = y1 - (PN_float32)y_last;
2473 if (y_contrib > 0.0001) {
2474 box_filter_line(result, coverage, x0, y, x1, y_contrib);
2478 if (coverage != 0.0) {
2489 box_filter_region(LPoint4f &result,
2490 PN_float32 x0, PN_float32 y0, PN_float32 x1, PN_float32 y1)
const {
2491 result = LPoint4f::zero();
2492 PN_float32 coverage = 0.0;
2494 if (x1 < x0 || y1 < y0) {
2497 nassertv(y0 >= 0.0 && y1 >= 0.0);
2501 box_filter_line(result, coverage, x0, y, x1, (PN_float32)(y+1)-y0);
2503 int y_last = (int)y1;
2506 while (y < y_last) {
2508 box_filter_line(result, coverage, x0, y, x1, 1.0);
2513 PN_float32 y_contrib = y1 - (PN_float32)y_last;
2514 if (y_contrib > 0.0001) {
2515 box_filter_line(result, coverage, x0, y, x1, y_contrib);
2519 if (coverage != 0.0) {
2528 box_filter_line(PN_float32 &result, PN_float32 &coverage,
2529 PN_float32 x0,
int y, PN_float32 x1, PN_float32 y_contrib)
const {
2532 box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
2534 int x_last = (int)x1;
2537 while (x < x_last) {
2539 box_filter_point(result, coverage, x, y, 1.0, y_contrib);
2544 PN_float32 x_contrib = x1 - (PN_float32)x_last;
2545 if (x_contrib > 0.0001) {
2546 box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
2555 box_filter_line(LPoint2f &result, PN_float32 &coverage,
2556 PN_float32 x0,
int y, PN_float32 x1, PN_float32 y_contrib)
const {
2559 box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
2561 int x_last = (int)x1;
2564 while (x < x_last) {
2566 box_filter_point(result, coverage, x, y, 1.0, y_contrib);
2571 PN_float32 x_contrib = x1 - (PN_float32)x_last;
2572 if (x_contrib > 0.0001) {
2573 box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
2582 box_filter_line(LPoint3f &result, PN_float32 &coverage,
2583 PN_float32 x0,
int y, PN_float32 x1, PN_float32 y_contrib)
const {
2586 box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
2588 int x_last = (int)x1;
2591 while (x < x_last) {
2593 box_filter_point(result, coverage, x, y, 1.0, y_contrib);
2598 PN_float32 x_contrib = x1 - (PN_float32)x_last;
2599 if (x_contrib > 0.0001) {
2600 box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
2609 box_filter_line(LPoint4f &result, PN_float32 &coverage,
2610 PN_float32 x0,
int y, PN_float32 x1, PN_float32 y_contrib)
const {
2613 box_filter_point(result, coverage, x, y, (PN_float32)(x+1)-x0, y_contrib);
2615 int x_last = (int)x1;
2618 while (x < x_last) {
2620 box_filter_point(result, coverage, x, y, 1.0, y_contrib);
2625 PN_float32 x_contrib = x1 - (PN_float32)x_last;
2626 if (x_contrib > 0.0001) {
2627 box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
2636 box_filter_point(PN_float32 &result, PN_float32 &coverage,
2637 int x,
int y, PN_float32 x_contrib, PN_float32 y_contrib)
const {
2643 PN_float32 contrib = x_contrib * y_contrib;
2644 result += point * contrib;
2645 coverage += contrib;
2652 box_filter_point(LPoint2f &result, PN_float32 &coverage,
2653 int x,
int y, PN_float32 x_contrib, PN_float32 y_contrib)
const {
2659 PN_float32 contrib = x_contrib * y_contrib;
2660 result += point * contrib;
2661 coverage += contrib;
2668 box_filter_point(LPoint3f &result, PN_float32 &coverage,
2669 int x,
int y, PN_float32 x_contrib, PN_float32 y_contrib)
const {
2675 PN_float32 contrib = x_contrib * y_contrib;
2676 result += point * contrib;
2677 coverage += contrib;
2684 box_filter_point(LPoint4f &result, PN_float32 &coverage,
2685 int x,
int y, PN_float32 x_contrib, PN_float32 y_contrib)
const {
2691 PN_float32 contrib = x_contrib * y_contrib;
2692 result += point * contrib;
2693 coverage += contrib;
2701 fill_mini_grid(MiniGridCell *mini_grid,
int x_size,
int y_size,
2702 int xi,
int yi,
int dist,
int sxi,
int syi)
const {
2703 if (xi < 0 || xi >= x_size || yi < 0 || yi >= y_size) {
2708 int gi = yi * x_size + xi;
2709 if (mini_grid[gi]._dist == -1 || mini_grid[gi]._dist > dist) {
2711 mini_grid[gi]._dist = dist;
2712 mini_grid[gi]._sxi = sxi;
2713 mini_grid[gi]._syi = syi;
2714 fill_mini_grid(mini_grid, x_size, y_size, xi + 1, yi, dist + 1, sxi, syi);
2715 fill_mini_grid(mini_grid, x_size, y_size, xi - 1, yi, dist + 1, sxi, syi);
2716 fill_mini_grid(mini_grid, x_size, y_size, xi, yi + 1, dist + 1, sxi, syi);
2717 fill_mini_grid(mini_grid, x_size, y_size, xi, yi - 1, dist + 1, sxi, syi);
2725 has_point_noop(
const PfmFile *
self,
int x,
int y) {
2726 if ((x >= 0 && x < self->_x_size) &&
2727 (y >= 0 && y < self->_y_size)) {
2738 has_point_1(
const PfmFile *
self,
int x,
int y) {
2739 if ((x >= 0 && x < self->_x_size) &&
2740 (y >= 0 && y < self->_y_size)) {
2741 return self->_table[(y *
self->_x_size + x)] != self->_no_data_value[0];
2751 has_point_2(
const PfmFile *
self,
int x,
int y) {
2752 if ((x >= 0 && x < self->_x_size) &&
2753 (y >= 0 && y < self->_y_size)) {
2754 return *(LPoint2f *)&self->_table[(y * self->_x_size + x) * 2] != *(LPoint2f *)&self->_no_data_value;
2764 has_point_3(
const PfmFile *
self,
int x,
int y) {
2765 if ((x >= 0 && x < self->_x_size) &&
2766 (y >= 0 && y < self->_y_size)) {
2767 return *(LPoint3f *)&self->_table[(y * self->_x_size + x) * 3] != *(LPoint3f *)&self->_no_data_value;
2777 has_point_4(
const PfmFile *
self,
int x,
int y) {
2778 if ((x >= 0 && x < self->_x_size) &&
2779 (y >= 0 && y < self->_y_size)) {
2780 return *(LPoint4f *)&self->_table[(y * self->_x_size + x) * 4] != *(LPoint4f *)&self->_no_data_value;
2790 has_point_threshold_1(
const PfmFile *
self,
int x,
int y) {
2791 if ((x >= 0 && x < self->_x_size) &&
2792 (y >= 0 && y < self->_y_size)) {
2793 const float *table = &
self->_table[(y *
self->_x_size + x)];
2794 return table[0] >=
self->_no_data_value[0];
2804 has_point_threshold_2(
const PfmFile *
self,
int x,
int y) {
2805 if ((x >= 0 && x < self->_x_size) &&
2806 (y >= 0 && y < self->_y_size)) {
2807 const float *table = &
self->_table[(y *
self->_x_size + x) * 2];
2808 return (table[0] >= self->_no_data_value[0] ||
2809 table[1] >= self->_no_data_value[1]);
2819 has_point_threshold_3(
const PfmFile *
self,
int x,
int y) {
2820 if ((x >= 0 && x < self->_x_size) &&
2821 (y >= 0 && y < self->_y_size)) {
2822 const float *table = &
self->_table[(y *
self->_x_size + x) * 3];
2823 return (table[0] >= self->_no_data_value[0] ||
2824 table[1] >= self->_no_data_value[1] ||
2825 table[2] >= self->_no_data_value[2]);
2835 has_point_threshold_4(
const PfmFile *
self,
int x,
int y) {
2836 if ((x >= 0 && x < self->_x_size) &&
2837 (y >= 0 && y < self->_y_size)) {
2838 const float *table = &
self->_table[(y *
self->_x_size + x) * 4];
2839 return (table[0] >= self->_no_data_value[0] ||
2840 table[1] >= self->_no_data_value[1] ||
2841 table[2] >= self->_no_data_value[2] ||
2842 table[3] >= self->_no_data_value[3]);
2853 has_point_chan4(
const PfmFile *
self,
int x,
int y) {
2854 if ((x >= 0 && x < self->_x_size) &&
2855 (y >= 0 && y < self->_y_size)) {
2856 return self->_table[(y *
self->_x_size + x) * 4 + 3] >= 0.0;
2866 has_point_nan_1(
const PfmFile *
self,
int x,
int y) {
2867 if ((x >= 0 && x < self->_x_size) &&
2868 (y >= 0 && y < self->_y_size)) {
2869 return !cnan(self->_table[(y * self->_x_size + x) * self->_num_channels]);
2879 has_point_nan_2(
const PfmFile *
self,
int x,
int y) {
2880 if ((x >= 0 && x < self->_x_size) &&
2881 (y >= 0 && y < self->_y_size)) {
2882 return !((LVecBase2f *)&self->_table[(y * self->_x_size + x) *
self->_num_channels])->is_nan();
2892 has_point_nan_3(
const PfmFile *
self,
int x,
int y) {
2893 if ((x >= 0 && x < self->_x_size) &&
2894 (y >= 0 && y < self->_y_size)) {
2895 return !((LVecBase3f *)&self->_table[(y * self->_x_size + x) *
self->_num_channels])->is_nan();
2905 has_point_nan_4(
const PfmFile *
self,
int x,
int y) {
2906 if ((x >= 0 && x < self->_x_size) &&
2907 (y >= 0 && y < self->_y_size)) {
2908 return !((LVecBase4f *)&self->_table[(y * self->_x_size + x) *
self->_num_channels])->is_nan();
bool calc_average_point(LPoint3f &result, PN_float32 x, PN_float32 y, PN_float32 radius) const
Computes the unweighted average point of all points within the box centered at (x,...
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
void apply_exponent(float gray_exponent)
Adjusts each channel of the image by raising the corresponding component value to the indicated expon...
void forward_distort(const PfmFile &dist, PN_float32 scale_factor=1.0)
Applies the distortion indicated in the supplied dist map to the current map.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool has_point(int x, int y) const
Returns true if there is a valid point at x, y.
void copy_header_from(const PNMImageHeader &header)
Initializes all the data in the header (x_size, y_size, num_channels, etc.) to the same values indica...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_column_empty(int x, int y_begin, int y_end) const
Returns true if all of the points on column x, from [y_begin, y_end), are the no_data value,...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void fill_channel_masked(int channel, PN_float32 value)
Fills the indicated channel with all of the same value, but only where the table already has a data p...
void mult_sub_image(const PfmFile ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the copy pixels are multiplied to the pixels of the destination...
void fill_channel(int channel, PN_float32 value)
Fills the indicated channel with all of the same value, leaving the other channels unchanged.
void set_point4(int x, int y, const LVecBase4f &point)
Replaces the 4-component point value at the indicated point.
A hierarchy of directories and files that appears to be one continuous file system,...
bool calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point) const
Calculates the minimum and maximum vertices of all points within the table.
const LPoint3f & get_point(int x, int y) const
Returns the 3-component point value at the indicated point.
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
void apply_1d_lut(int channel, const PfmFile &lut, PN_float32 x_scale=1.0)
Assumes that lut is an X by 1, 1-component PfmFile whose X axis maps points to target points.
virtual bool write_pfm(const PfmFile &pfm)
Writes floating-point data from the indicated PfmFile.
virtual bool is_floating_point()
Returns true if this PNMFileType represents a floating-point image type, false if it is a normal,...
bool calc_bilinear_point(LPoint3f &result, PN_float32 x, PN_float32 y) const
Computes the weighted average of the four nearest points to the floating- point index (x,...
void apply_mask(const PfmFile &other)
Wherever there is missing data in the other PfmFile, set this the corresponding point in this PfmFile...
void fill_nan()
Fills the table with all NaN.
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void fill_channel_masked_nan(int channel)
Fills the indicated channel with NaN, but only where the table already has a data point.
void fill_channel_nan(int channel)
Fills the indicated channel with NaN, leaving the other channels unchanged.
xel * get_array()
Directly access the underlying PNMImage array.
void set_point2(int x, int y, const LVecBase2f &point)
Replaces the 2-component point value at the indicated point.
The abstract base class for a file or directory within the VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
const LPoint4f & get_point4(int x, int y) const
Returns the 4-component point value at the indicated point.
void set_point3(int x, int y, const LVecBase3f &point)
Replaces the 3-component point value at the indicated point.
virtual bool supports_floating_point()
Returns true if this PNMFileType can accept a floating-point image type, false if it can only accept ...
bool is_row_empty(int y, int x_begin, int x_end) const
Returns true if all of the points on row y, in the range [x_begin, x_end), are the no_data value,...
const LPoint3f & get_point3(int x, int y) const
Returns the 3-component point value at the indicated point.
virtual bool read_pfm(PfmFile &pfm)
Reads floating-point data directly into the indicated PfmFile.
void resize(int new_x_size, int new_y_size)
Applies a simple filter to resample the pfm file in-place to the indicated size.
bool is_valid() const
Returns true if the image has been read in or correctly initialized with a height and width.
This is our own Panda specialization on the default STL vector.
const LPoint2f & get_point2(int x, int y) const
Returns the 2-component point value at the indicated point.
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
LPoint4f & modify_point4(int x, int y)
Returns a modifiable 4-component point value at the indicated point.
PN_float32 get_point1(int x, int y) const
Returns the 1-component point value at the indicated point.
bool read(const Filename &fullpath)
Reads the PFM data from the indicated file, returning true on success, false on failure.
void set_point1(int x, int y, PN_float32 point)
Replaces the 1-component point value at the indicated point.
bool write(const Filename &fullpath)
Writes the PFM data to the indicated file, returning true on success, false on failure.
bool is_valid() const
Returns true if the PNMReader can be used to read data, false if something is wrong.
void gaussian_filter_from(float radius, const PfmFile ©)
Makes a resized copy of the indicated image into this one using the indicated filter.
void merge(const PfmFile &other)
Wherever there is missing data in this PfmFile (that is, wherever has_point() returns false),...
LRGBColorf get_xel(int x, int y) const
Returns the RGB color at the indicated pixel.
LColorf get_xel_a(int x, int y) const
Returns the RGBA color at the indicated pixel.
void copy_channel_masked(int to_channel, const PfmFile &other, int from_channel)
Copies just the specified channel values from the indicated PfmFile, but only where the other file ha...
void apply_crop(int x_begin, int x_end, int y_begin, int y_end)
Reduces the PFM file to the cells in the rectangle bounded by (x_begin, x_end, y_begin,...
LPoint3f & modify_point3(int x, int y)
Returns a modifiable 3-component point value at the indicated point.
The name of a file, such as a texture file or an Egg file.
Defines a pfm file, a 2-d table of floating-point numbers, either 3-component or 1-component,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void reverse_rows()
Performs an in-place reversal of the row (y) data.
void set_gray(int x, int y, float gray)
Sets the gray component color at the indicated pixel.
void box_filter_from(float radius, const PfmFile ©)
Makes a resized copy of the indicated image into this one using the indicated filter.
void clear_to_texcoords(int x_size, int y_size)
Replaces this PfmFile with a new PfmFile of size x_size x y_size x 3, containing the x y 0 values in ...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PN_float32 get_channel(int x, int y, int c) const
Returns the cth channel of the point value at the indicated point.
void set_xel_a(int x, int y, const LColorf &value)
Changes the RGBA color at the indicated pixel.
void reverse_distort(const PfmFile &dist, PN_float32 scale_factor=1.0)
Applies the distortion indicated in the supplied dist map to the current map.
void fill(PN_float32 value)
Fills the table with all of the same value.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
void set_point(int x, int y, const LVecBase3f &point)
Replaces the 3-component point value at the indicated point.
void flip(bool flip_x, bool flip_y, bool transpose)
Reverses, transposes, and/or rotates the table in-place according to the specified parameters.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xelval * get_alpha_array()
Directly access the underlying PNMImage array of alpha values.
void quick_filter_from(const PfmFile ©)
Resizes from the given image, with a fixed radius of 0.5.
This is an abstract base class that defines the interface for reading image files of various types.
This is an abstract base class that defines the interface for writing image files of various types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool store_mask(PNMImage &pnmimage) const
Stores 1 or 0 values into the indicated PNMImage, according to has_point() for each pixel.
void indirect_1d_lookup(const PfmFile &index_image, int channel, const PfmFile &pixel_values)
index_image is a WxH 1-channel image, while pixel_values is an Nx1 image with any number of channels.
void set_channel(int x, int y, int c, PN_float32 value)
Replaces the cth channel of the point value at the indicated point.
bool load(const PNMImage &pnmimage)
Fills the PfmFile with the data from the indicated PNMImage, converted to floating-point values.
int pull_spot(const LPoint4f &delta, float xc, float yc, float xr, float yr, float exponent)
Applies delta * t to the point values within radius (xr, yr) distance of (xc, yc).
virtual int write_data(xel *array, xelval *alpha)
Writes out an entire image all at once, including the header, based on the image data stored in the g...
void operator *=(float multiplier)
Multiplies every point value in the image by a constant floating-point multiplier value.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color,...
void set_alpha(int x, int y, float a)
Sets the alpha component color only at the indicated pixel.
void xform(const LMatrix4f &transform)
Applies the indicated transform matrix to all points in-place.
void divide_sub_image(const PfmFile ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the copy pixels are divided into the pixels of the destination,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void copy_channel(int to_channel, const PfmFile &other, int from_channel)
Copies just the specified channel values from the indicated PfmFile (which could be same as this PfmF...
void clear_no_data_value()
Removes the special value that means "no data" when it appears in the pfm file.
bool calc_min_max(LVecBase3f &min_points, LVecBase3f &max_points) const
Calculates the minimum and maximum x, y, and z depth component values, representing the bounding box ...
void set_no_data_threshold(const LPoint4f &no_data_value)
Sets the special threshold value.
void fill_no_data_value()
Fills the table with the current no_data value, so that the table is empty.
LPoint2f & modify_point2(int x, int y)
Returns a modifiable 2-component point value at the indicated point.
bool store(PNMImage &pnmimage) const
Copies the data to the indicated PNMImage, converting to RGB values.
void add_sub_image(const PfmFile ©, int xto, int yto, int xfrom=0, int yfrom=0, int x_size=-1, int y_size=-1, float pixel_scale=1.0)
Behaves like copy_sub_image(), except the copy pixels are added to the pixels of the destination,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool calc_autocrop(int &x_begin, int &x_end, int &y_begin, int &y_end) const
Computes the minimum range of x and y across the PFM file that include all points.
void set_xel(int x, int y, const LRGBColorf &value)
Changes the RGB color at the indicated pixel.
void set_no_data_nan(int num_channels)
Sets the no_data_nan flag.
void clear()
Eliminates all data in the file.
This defines a bounding convex hexahedron.
float get_alpha(int x, int y) const
Returns the alpha component color at the indicated pixel.
void set_no_data_value(const LPoint4f &no_data_value)
Sets the special value that means "no data" when it appears in the pfm file.
PT(BoundingHexahedron) PfmFile
Computes the minmax bounding volume of the points in 3-D space, assuming the points represent a mostl...