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) {
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) {
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();