00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "config_grutil.h"
00016 #include "pfmFile.h"
00017 #include "virtualFileSystem.h"
00018 #include "pandaFileStream.h"
00019 #include "littleEndian.h"
00020 #include "bigEndian.h"
00021 #include "cmath.h"
00022 #include "geomNode.h"
00023 #include "geom.h"
00024 #include "geomVertexData.h"
00025 #include "geomVertexFormat.h"
00026 #include "geomPoints.h"
00027 #include "geomTriangles.h"
00028 #include "geomVertexWriter.h"
00029 #include "lens.h"
00030 #include "look_at.h"
00031
00032
00033
00034
00035
00036
00037 PfmFile::
00038 PfmFile() {
00039 _zero_special = false;
00040 _vis_inverse = false;
00041 _vis_2d = false;
00042 clear();
00043 }
00044
00045
00046
00047
00048
00049
00050 PfmFile::
00051 PfmFile(const PfmFile ©) :
00052 _table(copy._table),
00053 _x_size(copy._x_size),
00054 _y_size(copy._y_size),
00055 _scale(copy._scale),
00056 _num_channels(copy._num_channels),
00057 _zero_special(copy._zero_special),
00058 _vis_inverse(copy._vis_inverse),
00059 _vis_2d(copy._vis_2d)
00060 {
00061 }
00062
00063
00064
00065
00066
00067
00068 void PfmFile::
00069 operator = (const PfmFile ©) {
00070 _table = copy._table;
00071 _x_size = copy._x_size;
00072 _y_size = copy._y_size;
00073 _scale = copy._scale;
00074 _num_channels = copy._num_channels;
00075 _zero_special = copy._zero_special;
00076 _vis_inverse = copy._vis_inverse;
00077 _vis_2d = copy._vis_2d;
00078 }
00079
00080
00081
00082
00083
00084
00085 void PfmFile::
00086 clear() {
00087 _x_size = 0;
00088 _y_size = 0;
00089 _scale = 1.0;
00090 _num_channels = 3;
00091 _table.clear();
00092 }
00093
00094
00095
00096
00097
00098
00099 void PfmFile::
00100 clear(int x_size, int y_size, int num_channels) {
00101 nassertv(num_channels == 1 || num_channels == 3);
00102 nassertv(x_size >= 0 && y_size >= 0);
00103 _x_size = x_size;
00104 _y_size = y_size;
00105 _scale = 1.0;
00106 _num_channels = _num_channels;
00107
00108 _table.clear();
00109 int size = _x_size * _y_size;
00110 _table.insert(_table.end(), size, LPoint3::zero());
00111 }
00112
00113
00114
00115
00116
00117
00118
00119 bool PfmFile::
00120 read(const Filename &fullpath) {
00121 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00122
00123 Filename filename = Filename::binary_filename(fullpath);
00124 PT(VirtualFile) file = vfs->get_file(filename);
00125 if (file == (VirtualFile *)NULL) {
00126
00127 grutil_cat.error()
00128 << "Could not find " << fullpath << "\n";
00129 return false;
00130 }
00131
00132 if (grutil_cat.is_debug()) {
00133 grutil_cat.debug()
00134 << "Reading PFM file " << filename << "\n";
00135 }
00136
00137 istream *in = file->open_read_file(true);
00138 bool success = read(*in);
00139 vfs->close_read_file(in);
00140
00141 return success;
00142 }
00143
00144
00145
00146
00147
00148
00149
00150 bool PfmFile::
00151 read(istream &in) {
00152 clear();
00153
00154 string identifier;
00155 in >> identifier;
00156
00157 if (identifier == "PF") {
00158 _num_channels = 3;
00159 } else if (identifier == "Pf") {
00160 _num_channels = 1;
00161 } else {
00162 grutil_cat.error()
00163 << "Not a pfm file.\n";
00164 return false;
00165 }
00166
00167 int width, height;
00168 PN_stdfloat scale;
00169 in >> width >> height >> scale;
00170 if (!in) {
00171 grutil_cat.error()
00172 << "Error parsing pfm header.\n";
00173 return false;
00174 }
00175
00176
00177
00178 in.get();
00179
00180 bool little_endian = false;
00181 if (scale < 0) {
00182 scale = -scale;
00183 little_endian = true;
00184 }
00185 if (pfm_force_littleendian) {
00186 little_endian = true;
00187 }
00188 if (pfm_reverse_dimensions) {
00189 int t = width;
00190 width = height;
00191 height = t;
00192 }
00193
00194 _x_size = width;
00195 _y_size = height;
00196 _scale = scale;
00197
00198
00199 int size = _x_size * _y_size;
00200 _table.reserve(size);
00201
00202 if (little_endian) {
00203 for (int i = 0; i < size; ++i) {
00204 LPoint3 point = LPoint3::zero();
00205 for (int ci = 0; ci < _num_channels; ++ci) {
00206 PN_float32 data;
00207 in.read((char *)&data, sizeof(data));
00208 LittleEndian value(&data, sizeof(data));
00209 PN_float32 result;
00210 value.store_value(&result, sizeof(result));
00211 if (!cnan(result)) {
00212 point[ci] = result;
00213 }
00214 }
00215 _table.push_back(point);
00216 }
00217 } else {
00218 for (int i = 0; i < size; ++i) {
00219 LPoint3 point = LPoint3::zero();
00220 for (int ci = 0; ci < _num_channels; ++ci) {
00221 PN_float32 data;
00222 in.read((char *)&data, sizeof(data));
00223 BigEndian value(&data, sizeof(data));
00224 PN_float32 result;
00225 value.store_value(&result, sizeof(result));
00226 if (!cnan(result)) {
00227 point[ci] = result;
00228 }
00229 }
00230 _table.push_back(point);
00231 }
00232 }
00233
00234 if (in.fail() && !in.eof()) {
00235 return false;
00236 }
00237
00238 nassertr(sizeof(PN_float32) == 4, false);
00239 return true;
00240 }
00241
00242
00243
00244
00245
00246
00247
00248 bool PfmFile::
00249 write(const Filename &fullpath) {
00250 Filename filename = Filename::binary_filename(fullpath);
00251 pofstream out;
00252 if (!filename.open_write(out)) {
00253 grutil_cat.error()
00254 << "Unable to open " << filename << "\n";
00255 return false;
00256 }
00257
00258 if (grutil_cat.is_debug()) {
00259 grutil_cat.debug()
00260 << "Writing PFM file " << filename << "\n";
00261 }
00262
00263 return write(out);
00264 }
00265
00266
00267
00268
00269
00270
00271
00272 bool PfmFile::
00273 write(ostream &out) {
00274 nassertr(is_valid(), false);
00275
00276 if (_num_channels == 1) {
00277 out << "Pf\n";
00278 } else {
00279 out << "PF\n";
00280 }
00281 out << _x_size << " " << _y_size << "\n";
00282
00283 PN_stdfloat scale = cabs(_scale);
00284 if (scale == 0.0f) {
00285 scale = 1.0f;
00286 }
00287 #ifndef WORDS_BIGENDIAN
00288
00289
00290 scale = -scale;
00291 #endif
00292 out << scale << "\n";
00293
00294 int size = _x_size * _y_size;
00295 for (int i = 0; i < size; ++i) {
00296 const LPoint3 &point = _table[i];
00297 for (int ci = 0; ci < _num_channels; ++ci) {
00298 PN_float32 data = point[ci];
00299 out.write((const char *)&data, sizeof(data));
00300 }
00301 }
00302
00303 if (out.fail()) {
00304 return false;
00305 }
00306 nassertr(sizeof(PN_float32) == 4, false);
00307 return true;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 bool PfmFile::
00321 calc_average_point(LPoint3 &result, PN_stdfloat x, PN_stdfloat y, PN_stdfloat radius) const {
00322 result = LPoint3::zero();
00323
00324 int min_x = int(ceil(x - radius));
00325 int min_y = int(ceil(y - radius));
00326 int max_x = int(floor(x + radius));
00327 int max_y = int(floor(y + radius));
00328
00329
00330
00331
00332
00333 int x_size = max_x - min_x + 1;
00334 int y_size = max_y - min_y + 1;
00335 int size = x_size * y_size;
00336 if (size == 0) {
00337 return false;
00338 }
00339
00340 pvector<MiniGridCell> mini_grid;
00341 mini_grid.insert(mini_grid.end(), size, MiniGridCell());
00342
00343
00344
00345 min_x = max(min_x, 0);
00346 min_y = max(min_y, 0);
00347 max_x = min(max_x, _x_size - 1);
00348 max_y = min(max_y, _y_size - 1);
00349
00350 bool got_any = false;
00351 int xi, yi;
00352 for (yi = min_y; yi <= max_y; ++yi) {
00353 for (xi = min_x; xi <= max_x; ++xi) {
00354 const LPoint3 &p = _table[yi * _x_size + xi];
00355 if (_zero_special && p == LPoint3::zero()) {
00356 continue;
00357 }
00358
00359 int gi = (yi - min_y) * y_size + (xi - min_x);
00360 nassertr(gi >= 0 && gi < size, false);
00361 mini_grid[gi]._ti = yi * _x_size + xi;
00362 mini_grid[gi]._dist = 0;
00363 got_any = true;
00364 }
00365 }
00366
00367 if (!got_any) {
00368 return false;
00369 }
00370
00371
00372 for (yi = 0; yi < y_size; ++yi) {
00373 for (xi = 0; xi < x_size; ++xi) {
00374 int gi = yi * x_size + xi;
00375 if (mini_grid[gi]._dist == 0) {
00376 int ti = mini_grid[gi]._ti;
00377 fill_mini_grid(&mini_grid[0], x_size, y_size, xi + 1, yi, 1, ti);
00378 fill_mini_grid(&mini_grid[0], x_size, y_size, xi - 1, yi, 1, ti);
00379 fill_mini_grid(&mini_grid[0], x_size, y_size, xi, yi + 1, 1, ti);
00380 fill_mini_grid(&mini_grid[0], x_size, y_size, xi, yi - 1, 1, ti);
00381 }
00382 }
00383 }
00384
00385
00386
00387 for (int gi = 0; gi < size; ++gi) {
00388 int ti = mini_grid[gi]._ti;
00389 nassertr(ti >= 0 && ti < (int)_table.size(), false);
00390 result += _table[ti];
00391 }
00392
00393 result /= PN_stdfloat(size);
00394 return true;
00395 }
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406 bool PfmFile::
00407 calc_min_max(LVecBase3 &min_depth, LVecBase3 &max_depth) const {
00408 bool any_points = false;
00409
00410 min_depth = LVecBase3::zero();
00411 max_depth = LVecBase3::zero();
00412
00413 Table::const_iterator ti;
00414 for (ti = _table.begin(); ti != _table.end(); ++ti) {
00415 const LPoint3 &p = (*ti);
00416 if (_zero_special && p == LPoint3::zero()) {
00417 continue;
00418 }
00419
00420 if (!any_points) {
00421 min_depth = p;
00422 max_depth = p;
00423 any_points = true;
00424 } else {
00425 min_depth[0] = min(min_depth[0], p[0]);
00426 min_depth[1] = min(min_depth[1], p[1]);
00427 min_depth[2] = min(min_depth[2], p[2]);
00428 max_depth[0] = max(max_depth[0], p[0]);
00429 max_depth[1] = max(max_depth[1], p[1]);
00430 max_depth[2] = max(max_depth[2], p[2]);
00431 }
00432 }
00433
00434 return any_points;
00435 }
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 void PfmFile::
00446 resize(int new_x_size, int new_y_size) {
00447 if (_x_size == 0 || _y_size == 0 || new_x_size == 0 || new_y_size == 0) {
00448 clear(new_x_size, new_y_size, _num_channels);
00449 return;
00450 }
00451
00452 if (new_x_size == _x_size && new_y_size == _y_size) {
00453 return;
00454 }
00455
00456 Table new_data;
00457 new_data.reserve(new_x_size * new_y_size);
00458
00459 PN_stdfloat from_x0, from_x1, from_y0, from_y1;
00460
00461 PN_stdfloat x_scale = 1.0;
00462 PN_stdfloat y_scale = 1.0;
00463
00464 if (new_x_size > 1) {
00465 x_scale = (PN_stdfloat)(_x_size - 1) / (PN_stdfloat)(new_x_size - 1);
00466 }
00467 if (new_y_size > 1) {
00468 y_scale = (PN_stdfloat)(_y_size - 1) / (PN_stdfloat)(new_y_size - 1);
00469 }
00470
00471 from_y0 = 0.0;
00472 for (int to_y = 0; to_y < new_y_size; ++to_y) {
00473 from_y1 = (to_y + 0.5) * y_scale;
00474 from_y1 = min(from_y1, (PN_stdfloat) _y_size);
00475
00476 from_x0 = 0.0;
00477 for (int to_x = 0; to_x < new_x_size; ++to_x) {
00478 from_x1 = (to_x + 0.5) * x_scale;
00479 from_x1 = min(from_x1, (PN_stdfloat) _x_size);
00480
00481
00482
00483 LPoint3 result;
00484 box_filter_region(result, from_x0, from_y0, from_x1, from_y1);
00485 new_data.push_back(result);
00486
00487 from_x0 = from_x1;
00488 }
00489 from_y0 = from_y1;
00490 }
00491
00492 _table.swap(new_data);
00493 _x_size = new_x_size;
00494 _y_size = new_y_size;
00495 }
00496
00497
00498
00499
00500
00501
00502 void PfmFile::
00503 reverse_rows() {
00504 nassertv(is_valid());
00505
00506 Table reversed;
00507 reversed.reserve(_table.size());
00508 for (int yi = 0; yi < _y_size; ++yi) {
00509 int source_yi = _y_size - 1 - yi;
00510 int start = source_yi * _x_size;
00511 reversed.insert(reversed.end(),
00512 _table.begin() + start, _table.begin() + start + _x_size);
00513 }
00514
00515 nassertv(reversed.size() == _table.size());
00516 _table.swap(reversed);
00517 }
00518
00519
00520
00521
00522
00523
00524
00525 void PfmFile::
00526 xform(const LMatrix4 &transform) {
00527 nassertv(is_valid());
00528
00529 Table::iterator ti;
00530 for (ti = _table.begin(); ti != _table.end(); ++ti) {
00531 if (_zero_special && (*ti) == LPoint3::zero()) {
00532 continue;
00533 }
00534
00535 (*ti) = (*ti) * transform;
00536 }
00537 }
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550 void PfmFile::
00551 project(const Lens *lens) {
00552 nassertv(is_valid());
00553
00554 static LMatrix4 to_uv(0.5, 0.0, 0.0, 0.0,
00555 0.0, 0.5, 0.0, 0.0,
00556 0.0, 0.0, 1.0, 0.0,
00557 0.5, 0.5, 0.0, 1.0);
00558
00559 Table::iterator ti;
00560 for (ti = _table.begin(); ti != _table.end(); ++ti) {
00561 if (_zero_special && (*ti) == LPoint3::zero()) {
00562 continue;
00563 }
00564
00565 LPoint3 &p = (*ti);
00566 LPoint3 film;
00567 lens->project(p, film);
00568 p = to_uv.xform_point(film);
00569 }
00570 }
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580 void PfmFile::
00581 merge(const PfmFile &other) {
00582 nassertv(is_valid() && other.is_valid());
00583 nassertv(other._x_size == _x_size && other._y_size == _y_size);
00584
00585 if (!_zero_special) {
00586
00587 return;
00588 }
00589
00590 for (size_t i = 0; i < _table.size(); ++i) {
00591 if (_table[i] == LPoint3::zero()) {
00592 _table[i] = other._table[i];
00593 }
00594 }
00595 }
00596
00597
00598
00599
00600
00601
00602
00603 PT(BoundingHexahedron) PfmFile::
00604 compute_planar_bounds(PN_stdfloat point_dist, PN_stdfloat sample_radius) const {
00605 return compute_planar_bounds(LPoint2(0.5, 0.5), point_dist, sample_radius, false);
00606 }
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628 PT(BoundingHexahedron) PfmFile::
00629 compute_planar_bounds(const LPoint2 ¢er, PN_stdfloat point_dist, PN_stdfloat sample_radius, bool points_only) const {
00630 LPoint3 p0, p1, p2, p3;
00631 compute_sample_point(p0, center[0] + point_dist, center[1] - point_dist, sample_radius);
00632 compute_sample_point(p1, center[0] + point_dist, center[1] + point_dist, sample_radius);
00633 compute_sample_point(p2, center[0] - point_dist, center[1] + point_dist, sample_radius);
00634 compute_sample_point(p3, center[0] - point_dist, center[1] - point_dist, sample_radius);
00635
00636 LPoint3 normal;
00637
00638 normal[0] = p0[1] * p1[2] - p0[2] * p1[1];
00639 normal[1] = p0[2] * p1[0] - p0[0] * p1[2];
00640 normal[2] = p0[0] * p1[1] - p0[1] * p1[0];
00641
00642 normal[0] += p1[1] * p2[2] - p1[2] * p2[1];
00643 normal[1] += p1[2] * p2[0] - p1[0] * p2[2];
00644 normal[2] += p1[0] * p2[1] - p1[1] * p2[0];
00645
00646 normal[0] += p2[1] * p3[2] - p2[2] * p3[1];
00647 normal[1] += p2[2] * p3[0] - p2[0] * p3[2];
00648 normal[2] += p2[0] * p3[1] - p2[1] * p3[0];
00649
00650 normal[0] += p3[1] * p0[2] - p3[2] * p0[1];
00651 normal[1] += p3[2] * p0[0] - p3[0] * p0[2];
00652 normal[2] += p3[0] * p0[1] - p3[1] * p0[0];
00653
00654 normal.normalize();
00655
00656 LVector3 up = (p1 - p0) + (p2 - p3);
00657 LPoint3 pcenter = ((p0 + p1 + p2 + p3) * 0.25);
00658
00659
00660
00661 LMatrix4 rotate;
00662 look_at(rotate, normal, up);
00663
00664 LMatrix4 rinv;
00665 rinv.invert_from(rotate);
00666
00667 LPoint3 trans = pcenter * rinv;
00668 rinv.set_row(3, -trans);
00669 rotate.invert_from(rinv);
00670
00671
00672 PN_stdfloat min_x, min_y, min_z, max_x, max_y, max_z;
00673 bool got_point = false;
00674 if (points_only) {
00675 LPoint3 points[4] = {
00676 p0 * rinv,
00677 p1 * rinv,
00678 p2 * rinv,
00679 p3 * rinv,
00680 };
00681 for (int i = 0; i < 4; ++i) {
00682 const LPoint3 &point = points[i];
00683 if (!got_point) {
00684 min_x = point[0];
00685 min_y = point[1];
00686 min_z = point[2];
00687 max_x = point[0];
00688 max_y = point[1];
00689 max_z = point[2];
00690 got_point = true;
00691 } else {
00692 min_x = min(min_x, point[0]);
00693 min_y = min(min_y, point[1]);
00694 min_z = min(min_z, point[2]);
00695 max_x = max(max_x, point[0]);
00696 max_y = max(max_y, point[1]);
00697 max_z = max(max_z, point[2]);
00698 }
00699 }
00700
00701 } else {
00702 Table::const_iterator ti;
00703 for (ti = _table.begin(); ti != _table.end(); ++ti) {
00704 if (_zero_special && (*ti) == LPoint3::zero()) {
00705 continue;
00706 }
00707 LPoint3 point = (*ti) * rinv;
00708 if (!got_point) {
00709 min_x = point[0];
00710 min_y = point[1];
00711 min_z = point[2];
00712 max_x = point[0];
00713 max_y = point[1];
00714 max_z = point[2];
00715 got_point = true;
00716 } else {
00717 min_x = min(min_x, point[0]);
00718 min_y = min(min_y, point[1]);
00719 min_z = min(min_z, point[2]);
00720 max_x = max(max_x, point[0]);
00721 max_y = max(max_y, point[1]);
00722 max_z = max(max_z, point[2]);
00723 }
00724 }
00725 }
00726
00727 PT(BoundingHexahedron) bounds;
00728
00729
00730
00731 CoordinateSystem cs = get_default_coordinate_system();
00732 switch (cs) {
00733 case CS_yup_right:
00734 bounds = new BoundingHexahedron
00735 (LPoint3(min_x, min_y, min_z), LPoint3(max_x, min_y, min_z),
00736 LPoint3(min_x, max_y, min_z), LPoint3(max_x, max_y, min_z),
00737 LPoint3(min_x, min_y, max_z), LPoint3(max_x, min_y, max_z),
00738 LPoint3(min_x, max_y, max_z), LPoint3(max_x, max_y, max_z));
00739 break;
00740
00741 case CS_zup_right:
00742 bounds = new BoundingHexahedron
00743 (LPoint3(min_x, min_y, min_z), LPoint3(max_x, min_y, min_z),
00744 LPoint3(min_x, min_y, max_z), LPoint3(max_x, min_y, max_z),
00745 LPoint3(min_x, max_y, min_z), LPoint3(max_x, max_y, min_z),
00746 LPoint3(min_x, max_y, max_z), LPoint3(max_x, max_y, max_z));
00747 break;
00748
00749 case CS_yup_left:
00750 bounds = new BoundingHexahedron
00751 (LPoint3(max_x, min_y, max_z), LPoint3(min_x, min_y, max_z),
00752 LPoint3(max_x, max_y, max_z), LPoint3(min_x, max_y, max_z),
00753 LPoint3(max_x, min_y, min_z), LPoint3(min_x, min_y, min_z),
00754 LPoint3(max_x, max_y, min_z), LPoint3(min_x, max_y, min_z));
00755 break;
00756
00757 case CS_zup_left:
00758 bounds = new BoundingHexahedron
00759 (LPoint3(max_x, max_y, min_z), LPoint3(min_x, max_y, min_z),
00760 LPoint3(max_x, max_y, max_z), LPoint3(min_x, max_y, max_z),
00761 LPoint3(max_x, min_y, min_z), LPoint3(min_x, min_y, min_z),
00762 LPoint3(max_x, min_y, max_z), LPoint3(min_x, min_y, max_z));
00763 break;
00764 }
00765
00766
00767
00768 bounds->xform(rotate);
00769
00770 return bounds;
00771 }
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783 void PfmFile::
00784 compute_sample_point(LPoint3 &result,
00785 PN_stdfloat x, PN_stdfloat y, PN_stdfloat sample_radius) const {
00786 x *= _x_size;
00787 y *= _y_size;
00788 PN_stdfloat xr = sample_radius * _x_size;
00789 PN_stdfloat yr = sample_radius * _y_size;
00790 box_filter_region(result, x - xr, y - yr, x + xr, y + yr);
00791 }
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802 NodePath PfmFile::
00803 generate_vis_points() const {
00804 nassertr(is_valid(), NodePath());
00805
00806 CPT(GeomVertexFormat) format;
00807 if (_vis_inverse) {
00808 if (_vis_2d) {
00809 format = GeomVertexFormat::get_v3t2();
00810 } else {
00811
00812
00813 GeomVertexArrayFormat *v3t3 = new GeomVertexArrayFormat
00814 (InternalName::get_vertex(), 3,
00815 Geom::NT_stdfloat, Geom::C_point,
00816 InternalName::get_texcoord(), 3,
00817 Geom::NT_stdfloat, Geom::C_texcoord);
00818 format = GeomVertexFormat::register_format(v3t3);
00819 }
00820 } else {
00821 format = GeomVertexFormat::get_v3t2();
00822 }
00823
00824 PT(GeomVertexData) vdata = new GeomVertexData
00825 ("points", format, Geom::UH_static);
00826 vdata->set_num_rows(_x_size * _y_size);
00827 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00828 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00829
00830 LPoint2 uv_scale(1.0, 1.0);
00831 if (_x_size > 1) {
00832 uv_scale[0] = 1.0f / PN_stdfloat(_x_size - 1);
00833 }
00834 if (_y_size > 1) {
00835 uv_scale[1] = 1.0f / PN_stdfloat(_y_size - 1);
00836 }
00837
00838 for (int yi = 0; yi < _y_size; ++yi) {
00839 for (int xi = 0; xi < _x_size; ++xi) {
00840 const LPoint3 &point = get_point(xi, yi);
00841 LPoint2 uv(PN_stdfloat(xi) * uv_scale[0],
00842 PN_stdfloat(yi) * uv_scale[1]);
00843 if (_vis_inverse) {
00844 vertex.add_data2(uv);
00845 texcoord.add_data3(point);
00846 } else if (_vis_2d) {
00847 vertex.add_data2(point[0], point[1]);
00848 texcoord.add_data2(uv);
00849 } else {
00850 vertex.add_data3(point);
00851 texcoord.add_data2(uv);
00852 }
00853 }
00854 }
00855
00856 PT(Geom) geom = new Geom(vdata);
00857 PT(GeomPoints) points = new GeomPoints(Geom::UH_static);
00858 points->add_next_vertices(_x_size * _y_size);
00859 geom->add_primitive(points);
00860
00861 PT(GeomNode) gnode = new GeomNode("");
00862 gnode->add_geom(geom);
00863 return NodePath(gnode);
00864 }
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874 NodePath PfmFile::
00875 generate_vis_mesh(MeshFace face) const {
00876 nassertr(is_valid(), NodePath());
00877 nassertr(face != 0, NodePath());
00878
00879 if (_x_size == 1 || _y_size == 1) {
00880
00881 return generate_vis_points();
00882 }
00883
00884 PT(GeomNode) gnode = new GeomNode("");
00885
00886 if (face & MF_front) {
00887 make_vis_mesh_geom(gnode, false);
00888 }
00889
00890 if (face & MF_back) {
00891 make_vis_mesh_geom(gnode, true);
00892 }
00893
00894 return NodePath(gnode);
00895 }
00896
00897
00898
00899
00900
00901
00902
00903 void PfmFile::
00904 make_vis_mesh_geom(GeomNode *gnode, bool inverted) const {
00905 int num_x_cells = 1;
00906 int num_y_cells = 1;
00907
00908 int x_size = _x_size;
00909 int y_size = _y_size;
00910
00911
00912 int num_vertices = x_size * y_size;
00913 if (num_vertices == 0) {
00914
00915 return;
00916 }
00917
00918 bool reverse_normals = inverted;
00919 bool reverse_faces = inverted;
00920 if (!is_right_handed(get_default_coordinate_system())) {
00921 reverse_faces = !reverse_faces;
00922 }
00923
00924
00925
00926
00927 int max_indices = (x_size - 1) * (y_size - 1) * 6;
00928
00929 while (num_vertices > pfm_vis_max_vertices || max_indices > pfm_vis_max_indices) {
00930
00931
00932 if (num_x_cells > num_y_cells) {
00933 ++num_y_cells;
00934 } else {
00935 ++num_x_cells;
00936 }
00937
00938 x_size = (_x_size + num_x_cells - 1) / num_x_cells + 1;
00939 y_size = (_y_size + num_y_cells - 1) / num_y_cells + 1;
00940
00941 num_vertices = x_size * y_size;
00942 max_indices = (x_size - 1) * (y_size - 1) * 6;
00943 }
00944
00945
00946 if (grutil_cat.is_debug()) {
00947 grutil_cat.debug()
00948 << "Generating mesh with " << num_x_cells << " x " << num_y_cells
00949 << " pieces.\n";
00950 }
00951
00952 PT(GeomVertexArrayFormat) array_format;
00953
00954 if (_vis_2d) {
00955
00956 array_format = new GeomVertexArrayFormat
00957 (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point,
00958 InternalName::get_texcoord(), 2, Geom::NT_stdfloat, Geom::C_texcoord);
00959
00960 } else {
00961 if (_vis_inverse) {
00962
00963
00964 array_format = new GeomVertexArrayFormat
00965 (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point,
00966 InternalName::get_texcoord(), 3, Geom::NT_stdfloat, Geom::C_texcoord);
00967 } else {
00968
00969
00970 array_format = new GeomVertexArrayFormat
00971 (InternalName::get_vertex(), 3, Geom::NT_stdfloat, Geom::C_point,
00972 InternalName::get_normal(), 3, Geom::NT_stdfloat, Geom::C_vector,
00973 InternalName::get_texcoord(), 2, Geom::NT_stdfloat, Geom::C_texcoord);
00974 }
00975 }
00976
00977 if (_flat_texcoord_name != (InternalName *)NULL) {
00978
00979 array_format->add_column(_flat_texcoord_name, 2,
00980 Geom::NT_stdfloat, Geom::C_texcoord);
00981 }
00982
00983 CPT(GeomVertexFormat) format = GeomVertexFormat::register_format(array_format);
00984
00985 for (int yci = 0; yci < num_y_cells; ++yci) {
00986 int y_begin = (yci * _y_size) / num_y_cells;
00987 int y_end = ((yci + 1) * _y_size) / num_y_cells;
00988
00989
00990
00991 y_end = min(y_end + 1, _y_size);
00992
00993 y_size = y_end - y_begin;
00994 if (y_size == 0) {
00995 continue;
00996 }
00997
00998 for (int xci = 0; xci < num_x_cells; ++xci) {
00999 int x_begin = (xci * _x_size) / num_x_cells;
01000 int x_end = ((xci + 1) * _x_size) / num_x_cells;
01001 x_end = min(x_end + 1, _x_size);
01002 x_size = x_end - x_begin;
01003 if (x_size == 0) {
01004 continue;
01005 }
01006
01007 num_vertices = x_size * y_size;
01008 max_indices = (x_size - 1) * (y_size - 1) * 6;
01009
01010 ostringstream mesh_name;
01011 mesh_name << "mesh_" << xci << "_" << yci;
01012 PT(GeomVertexData) vdata = new GeomVertexData
01013 (mesh_name.str(), format, Geom::UH_static);
01014
01015 vdata->set_num_rows(num_vertices);
01016 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
01017 GeomVertexWriter normal(vdata, InternalName::get_normal());
01018 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
01019 GeomVertexWriter texcoord2(vdata, _flat_texcoord_name);
01020
01021 for (int yi = y_begin; yi < y_end; ++yi) {
01022 for (int xi = x_begin; xi < x_end; ++xi) {
01023 const LPoint3 &point = get_point(xi, yi);
01024 LPoint2 uv(PN_stdfloat(xi) / PN_stdfloat(_x_size - 1),
01025 PN_stdfloat(yi) / PN_stdfloat(_y_size - 1));
01026
01027 if (_vis_inverse) {
01028 vertex.add_data2(uv);
01029 texcoord.add_data3(point);
01030 } else if (_vis_2d) {
01031 vertex.add_data2(point[0], point[1]);
01032 texcoord.add_data2(uv);
01033 } else {
01034 vertex.add_data3(point);
01035 texcoord.add_data2(uv);
01036
01037
01038 LPoint3 v[3];
01039 v[0] = get_point(xi, yi);
01040 if (xi + 1 < _x_size) {
01041 v[1] = get_point(xi + 1, yi);
01042 } else {
01043 v[1] = v[0];
01044 v[0] = get_point(xi - 1, yi);
01045 }
01046
01047 if (yi + 1 < _y_size) {
01048 v[2] = get_point(xi, yi + 1);
01049 } else {
01050 v[2] = v[0];
01051 v[0] = get_point(xi, yi - 1);
01052 }
01053
01054 LVector3 n = LVector3::zero();
01055 for (int i = 0; i < 3; ++i) {
01056 const LPoint3 &v0 = v[i];
01057 const LPoint3 &v1 = v[(i + 1) % 3];
01058 n[0] += v0[1] * v1[2] - v0[2] * v1[1];
01059 n[1] += v0[2] * v1[0] - v0[0] * v1[2];
01060 n[2] += v0[0] * v1[1] - v0[1] * v1[0];
01061 }
01062 n.normalize();
01063 nassertv(!n.is_nan());
01064 if (reverse_normals) {
01065 n = -n;
01066 }
01067 normal.add_data3(n);
01068 }
01069
01070 if (_flat_texcoord_name != (InternalName *)NULL) {
01071 texcoord2.add_data2(uv);
01072 }
01073 }
01074 }
01075
01076 PT(Geom) geom = new Geom(vdata);
01077 PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
01078
01079 tris->reserve_num_vertices(max_indices);
01080
01081 for (int yi = y_begin; yi < y_end - 1; ++yi) {
01082 for (int xi = x_begin; xi < x_end - 1; ++xi) {
01083
01084 if (_zero_special) {
01085 if (get_point(xi, yi) == LPoint3::zero() ||
01086 get_point(xi, yi + 1) == LPoint3::zero() ||
01087 get_point(xi + 1, yi + 1) == LPoint3::zero() ||
01088 get_point(xi + 1, yi) == LPoint3::zero()) {
01089 continue;
01090 }
01091 }
01092
01093 int xi0 = xi - x_begin;
01094 int yi0 = yi - y_begin;
01095
01096 int vi0 = ((xi0) + (yi0) * x_size);
01097 int vi1 = ((xi0) + (yi0 + 1) * x_size);
01098 int vi2 = ((xi0 + 1) + (yi0 + 1) * x_size);
01099 int vi3 = ((xi0 + 1) + (yi0) * x_size);
01100
01101 if (reverse_faces) {
01102 tris->add_vertices(vi2, vi0, vi1);
01103 tris->close_primitive();
01104
01105 tris->add_vertices(vi3, vi0, vi2);
01106 tris->close_primitive();
01107 } else {
01108 tris->add_vertices(vi2, vi1, vi0);
01109 tris->close_primitive();
01110
01111 tris->add_vertices(vi3, vi2, vi0);
01112 tris->close_primitive();
01113 }
01114 }
01115 }
01116 geom->add_primitive(tris);
01117 gnode->add_geom(geom);
01118 }
01119 }
01120 }
01121
01122
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132 void PfmFile::
01133 box_filter_region(LPoint3 &result,
01134 PN_stdfloat x0, PN_stdfloat y0, PN_stdfloat x1, PN_stdfloat y1) const {
01135 result = LPoint3::zero();
01136 PN_stdfloat coverage = 0.0;
01137
01138 if (x1 < x0 || y1 < y0) {
01139 return;
01140 }
01141 nassertv(y0 >= 0.0 && y1 >= 0.0);
01142
01143 int y = (int)y0;
01144
01145 box_filter_line(result, coverage, x0, y, x1, (PN_stdfloat)(y+1)-y0);
01146
01147 int y_last = (int)y1;
01148 if (y < y_last) {
01149 y++;
01150 while (y < y_last) {
01151
01152 box_filter_line(result, coverage, x0, y, x1, 1.0);
01153 y++;
01154 }
01155
01156
01157 PN_stdfloat y_contrib = y1 - (PN_stdfloat)y_last;
01158 if (y_contrib > 0.0001) {
01159 box_filter_line(result, coverage, x0, y, x1, y_contrib);
01160 }
01161 }
01162
01163 if (coverage != 0.0) {
01164 result /= coverage;
01165 }
01166 }
01167
01168
01169
01170
01171
01172
01173 void PfmFile::
01174 box_filter_line(LPoint3 &result, PN_stdfloat &coverage,
01175 PN_stdfloat x0, int y, PN_stdfloat x1, PN_stdfloat y_contrib) const {
01176 int x = (int)x0;
01177
01178 box_filter_point(result, coverage, x, y, (PN_stdfloat)(x+1)-x0, y_contrib);
01179
01180 int x_last = (int)x1;
01181 if (x < x_last) {
01182 x++;
01183 while (x < x_last) {
01184
01185 box_filter_point(result, coverage, x, y, 1.0, y_contrib);
01186 x++;
01187 }
01188
01189
01190 PN_stdfloat x_contrib = x1 - (PN_stdfloat)x_last;
01191 if (x_contrib > 0.0001) {
01192 box_filter_point(result, coverage, x, y, x_contrib, y_contrib);
01193 }
01194 }
01195 }
01196
01197
01198
01199
01200
01201
01202 void PfmFile::
01203 box_filter_point(LPoint3 &result, PN_stdfloat &coverage,
01204 int x, int y, PN_stdfloat x_contrib, PN_stdfloat y_contrib) const {
01205 const LPoint3 &point = get_point(x, y);
01206 if (_zero_special && point == LPoint3::zero()) {
01207 return;
01208 }
01209
01210 PN_stdfloat contrib = x_contrib * y_contrib;
01211 result += point * contrib;
01212 coverage += contrib;
01213 }
01214
01215
01216
01217
01218
01219
01220
01221
01222 void PfmFile::
01223 fill_mini_grid(MiniGridCell *mini_grid, int x_size, int y_size,
01224 int xi, int yi, int dist, int ti) const {
01225 if (xi < 0 || xi >= x_size || yi < 0 || yi >= y_size) {
01226
01227 return;
01228 }
01229
01230 int gi = yi * x_size + xi;
01231 if (mini_grid[gi]._dist == -1 || mini_grid[gi]._dist > dist) {
01232
01233 mini_grid[gi]._dist = dist;
01234 mini_grid[gi]._ti = ti;
01235 fill_mini_grid(mini_grid, x_size, y_size, xi + 1, yi, dist + 1, ti);
01236 fill_mini_grid(mini_grid, x_size, y_size, xi - 1, yi, dist + 1, ti);
01237 fill_mini_grid(mini_grid, x_size, y_size, xi, yi + 1, dist + 1, ti);
01238 fill_mini_grid(mini_grid, x_size, y_size, xi, yi - 1, dist + 1, ti);
01239 }
01240 }