36 (
"geomipterrain-incorrect-normals",
false,
37 PRC_DESC(
"If true, uses the incorrect normal vector calculation that "
38 "was used in Panda3D versions 1.9.0 and earlier. If false, "
39 "uses the correct calculation. For backward compatibility, "
40 "the default value is true in 1.9 releases, and false in "
41 "Panda3D 1.10.0 and above."));
52 generate_block(
unsigned short mx,
54 unsigned short level) {
56 nassertr(mx < (_xsize - 1) / _block_size,
nullptr);
57 nassertr(my < (_ysize - 1) / _block_size,
nullptr);
59 unsigned short center = _block_size / 2;
60 unsigned int vcounter = 0;
65 array->add_column(InternalName::get_color(), 4,
66 Geom::NT_stdfloat, Geom::C_color);
68 array->add_column(InternalName::get_vertex(), 3,
69 Geom::NT_stdfloat, Geom::C_point);
70 array->add_column(InternalName::get_texcoord(), 2,
71 Geom::NT_stdfloat, Geom::C_texcoord);
72 array->add_column(InternalName::get_normal(), 3,
73 Geom::NT_stdfloat, Geom::C_normal);
76 format->add_array(array);
80 GeomVertexFormat::register_format(format), Geom::UH_stream);
81 vdata->unclean_set_num_rows((_block_size + 1) * (_block_size + 1));
98 level = min(max(_min_level, level), _max_level);
99 unsigned short reallevel = level;
100 level = int(pow(2.0,
int(level)));
103 unsigned short lnlevel = get_neighbor_level(mx, my, -1, 0);
104 unsigned short rnlevel = get_neighbor_level(mx, my, 1, 0);
105 unsigned short bnlevel = get_neighbor_level(mx, my, 0, -1);
106 unsigned short tnlevel = get_neighbor_level(mx, my, 0, 1);
107 bool ljunction = (lnlevel != reallevel);
108 bool rjunction = (rnlevel != reallevel);
109 bool bjunction = (bnlevel != reallevel);
110 bool tjunction = (tnlevel != reallevel);
117 unsigned short lowblocksize = _block_size / level + 1;
119 PN_stdfloat cmap_xratio = _color_map.
get_x_size() / (PN_stdfloat)_xsize;
120 PN_stdfloat cmap_yratio = _color_map.
get_y_size() / (PN_stdfloat)_ysize;
122 PN_stdfloat tc_xscale = 1.0f / PN_stdfloat(_xsize - 1);
123 PN_stdfloat tc_yscale = 1.0f / PN_stdfloat(_ysize - 1);
125 for (
int x = 0; x <= _block_size; x++) {
126 for (
int y = 0; y <= _block_size; y++) {
127 if ((x % level) == 0 && (y % level) == 0) {
128 if (_has_color_map) {
130 int((mx * _block_size + x) * cmap_xratio),
131 int((my * _block_size + y) * cmap_yratio));
134 vwriter.
set_data3(x - 0.5 * _block_size, y - 0.5 * _block_size, get_pixel_value(mx, my, x, y));
135 twriter.
set_data2((mx * _block_size + x) * tc_xscale,
136 (my * _block_size + y) * tc_yscale);
139 if (x > 0 && y > 0) {
141 if (x == level && ljunction) {
142 if (y > level && y < _block_size) {
143 prim->add_vertex(min(max(sfav(y / level, lnlevel, reallevel), 0), lowblocksize - 1));
144 prim->add_vertex(vcounter - 1);
145 prim->add_vertex(vcounter);
146 prim->close_primitive();
148 if (f_part((y / level) / PN_stdfloat(pow(2.0,
int(lnlevel - reallevel)))) == 0.5) {
149 prim->add_vertex(min(max(sfav(y / level + 1, lnlevel, reallevel), 0), lowblocksize - 1));
150 prim->add_vertex(min(max(sfav(y / level - 1, lnlevel, reallevel), 0), lowblocksize - 1));
151 prim->add_vertex(vcounter);
152 prim->close_primitive();
155 (!(bjunction && y == level && x > level && x < _block_size) &&
156 !(rjunction && x == _block_size) &&
157 !(tjunction && y == _block_size && x > level && x < _block_size))) {
158 if ((x <= center && y <= center) || (x > center && y > center)) {
160 prim->add_vertex(vcounter - lowblocksize - 1);
161 prim->add_vertex(vcounter - 1);
162 prim->add_vertex(vcounter);
164 prim->add_vertex(vcounter);
165 prim->add_vertex(vcounter - lowblocksize);
166 prim->add_vertex(vcounter - lowblocksize - 1);
170 prim->add_vertex(vcounter);
171 prim->add_vertex(vcounter - lowblocksize);
172 prim->add_vertex(vcounter - 1);
174 prim->add_vertex(vcounter - 1);
175 prim->add_vertex(vcounter - lowblocksize);
176 prim->add_vertex(vcounter - lowblocksize - 1);
179 prim->close_primitive();
182 if (x == _block_size - level && rjunction) {
183 if (y > level && y < _block_size) {
184 prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level, rnlevel, reallevel), 0), lowblocksize - 1));
185 prim->add_vertex(vcounter);
186 prim->add_vertex(vcounter - 1);
187 prim->close_primitive();
189 if (f_part((y / level) / PN_stdfloat(pow(2.0,
int(rnlevel - reallevel)))) == 0.5) {
190 prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level - 1, rnlevel, reallevel), 0), lowblocksize - 1));
191 prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level + 1, rnlevel, reallevel), 0), lowblocksize - 1));
192 prim->add_vertex(vcounter);
193 prim->close_primitive();
197 if (y == level && bjunction) {
198 if (x > level && x < _block_size) {
199 prim->add_vertex(vcounter);
200 prim->add_vertex(vcounter - lowblocksize);
201 prim->add_vertex(min(max(sfav(x / level, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
202 prim->close_primitive();
204 if (f_part((x / level) / PN_stdfloat(pow(2.0,
int(bnlevel - reallevel)))) == 0.5) {
205 prim->add_vertex(min(max(sfav(x / level - 1, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
206 prim->add_vertex(min(max(sfav(x / level + 1, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
207 prim->add_vertex(vcounter);
208 prim->close_primitive();
211 (!(ljunction && x == level && y > level && y < _block_size) &&
212 !(tjunction && y == _block_size) &&
213 !(rjunction && x == _block_size && y > level && y < _block_size))) {
214 if ((x <= center && y <= center) || (x > center && y > center)) {
216 prim->add_vertex(vcounter);
217 prim->add_vertex(vcounter - lowblocksize);
218 prim->add_vertex(vcounter - lowblocksize - 1);
220 prim->add_vertex(vcounter - lowblocksize - 1);
221 prim->add_vertex(vcounter - 1);
222 prim->add_vertex(vcounter);
226 prim->add_vertex(vcounter);
227 prim->add_vertex(vcounter - lowblocksize);
228 prim->add_vertex(vcounter - 1);
230 prim->add_vertex(vcounter - 1);
231 prim->add_vertex(vcounter - lowblocksize);
232 prim->add_vertex(vcounter - lowblocksize - 1);
235 prim->close_primitive();
238 if (y == _block_size - level && tjunction) {
239 if (x > level && x < _block_size) {
240 prim->add_vertex(min(max(sfav(x / level, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
241 prim->add_vertex(vcounter - lowblocksize);
242 prim->add_vertex(vcounter);
243 prim->close_primitive();
245 if (f_part((x / level) / PN_stdfloat(pow(2.0,
int(tnlevel - reallevel)))) == 0.5) {
246 prim->add_vertex(min(max(sfav(x / level + 1, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
247 prim->add_vertex(min(max(sfav(x / level - 1, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
248 prim->add_vertex(vcounter);
249 prim->close_primitive();
259 geom->add_primitive(prim);
260 geom->set_bounds_type(BoundingVolume::BT_box);
262 std::ostringstream sname;
263 sname <<
"gmm" << mx <<
"x" << my;
265 node->add_geom(geom);
266 node->set_bounds_type(BoundingVolume::BT_box);
267 _old_levels.at(mx).at(my) = reallevel;
283 y = (_ysize - 1) - y;
284 if (x < 0.0) x = 0.0;
285 if (y < 0.0) y = 0.0;
286 unsigned int xlo = (
unsigned int) x;
287 unsigned int ylo = (
unsigned int) y;
288 if (xlo > _xsize - 2)
290 if (ylo > _ysize - 2)
292 unsigned int xhi = xlo + 1;
293 unsigned int yhi = ylo + 1;
294 double xoffs = x - xlo;
295 double yoffs = y - ylo;
296 double grayxlyl = get_pixel_value(xlo, ylo);
297 double grayxhyl = get_pixel_value(xhi, ylo);
298 double grayxlyh = get_pixel_value(xlo, yhi);
299 double grayxhyh = get_pixel_value(xhi, yhi);
300 double lerpyl = grayxhyl * xoffs + grayxlyl * (1.0 - xoffs);
301 double lerpyh = grayxhyh * xoffs + grayxlyh * (1.0 - xoffs);
302 return lerpyh * yoffs + lerpyl * (1.0 - yoffs);
324 if (px >=
int(_xsize)) px--;
325 if (py >=
int(_ysize)) py--;
326 double drx = get_pixel_value(nx, y) - get_pixel_value(px, y);
327 double dry = get_pixel_value(x, py) - get_pixel_value(x, ny);
328 LVector3 normal(drx * 0.5, dry * 0.5, 1);
331 if (geomipterrain_incorrect_normals) {
332 normal[0] = -normal[0];
351 for (
unsigned int x = 0; x < _xsize; ++x) {
352 for (
unsigned int y = 0; y < _ysize; ++y) {
354 normal.set(normal.get_x() / _root.get_sx(),
355 normal.get_y() / _root.get_sy(),
356 normal.get_z() / _root.get_sz());
358 result.
set_xel(x, y, normal.angle_deg(LVector3::up()) / 90.0);
372 _color_map =
PNMImage(_xsize, _ysize);
376 for (
unsigned int x = 0; x < _xsize; ++x) {
377 for (
unsigned int y = 0; y < _ysize; ++y) {
378 _color_map.
set_xel(x, _ysize - y - 1, get_pixel_value(x, y));
386 for (
unsigned int x = 0; x < _xsize; ++x) {
387 for (
unsigned int y = 0; y < _ysize; ++y) {
388 _color_map.
set_xel(x, y, (get_pixel_value(x, _ysize - y - 1) - _color_map.
get_gray(x, y)) * contrast + brightness);
392 _has_color_map =
true;
402 if (_xsize < 3 || _ysize < 3) {
403 grutil_cat.error() <<
"No valid heightfield image has been set!\n";
410 _old_levels.resize(
int((_xsize - 1) / _block_size));
411 _root_flattened =
false;
412 for (
unsigned int mx = 0; mx < (_xsize - 1) / _block_size; mx++) {
413 _old_levels[mx].resize(
int((_ysize - 1) / _block_size));
415 for (
unsigned int my = 0; my < (_ysize - 1) / _block_size; my++) {
419 tvector.push_back(_root.
attach_new_node(generate_block(mx, my, _levels[mx][my])));
421 tvector[my].set_pos((mx + 0.5) * _block_size, (my + 0.5) * _block_size, 0);
423 _blocks.push_back(tvector);
440 if (_xsize < 3 || _ysize < 3) {
441 grutil_cat.error() <<
"No valid heightfield image has been set!\n";
447 }
else if (!_bruteforce) {
449 if (root_flattened()) {
451 unsigned int xsize = _blocks.size();
452 for (
unsigned int tx = 0; tx < xsize; tx++) {
453 unsigned int ysize = _blocks[tx].size();
454 for (
unsigned int ty = 0;ty < ysize; ty++) {
455 _blocks[tx][ty].reparent_to(_root);
458 _root_flattened =
false;
460 bool returnVal =
false;
461 for (
unsigned int mx = 0; mx < (_xsize - 1) / _block_size; mx++) {
462 for (
unsigned int my = 0; my < (_ysize - 1) / _block_size; my++) {
463 bool isUpd (update_block(mx, my));
464 if (isUpd && mx > 0 && _old_levels[mx - 1][my] == _levels[mx - 1][my]) {
465 if (update_block(mx - 1, my, -1,
true)) {
469 if (isUpd && mx < (_ysize - 1)/_block_size - 1
470 && _old_levels[mx + 1][my] == _levels[mx + 1][my]) {
471 if (update_block(mx + 1, my, -1,
true)) {
475 if (isUpd && my > 0 && _old_levels[mx][my - 1] == _levels[mx][my - 1]) {
476 if (update_block(mx, my - 1, -1,
true)) {
480 if (isUpd && my < (_ysize - 1)/_block_size - 1
481 && _old_levels[mx][my + 1] == _levels[mx][my + 1]) {
482 if (update_block(mx, my + 1, -1,
true)) {
505 if (_root_flattened) {
515 unsigned int xsize = _blocks.size();
516 for (
unsigned int tx = 0; tx < xsize; tx++) {
517 unsigned int ysize = _blocks[tx].size();
518 for (
unsigned int ty = 0;ty < ysize; ty++) {
519 if (_blocks[tx][ty].get_node(1) != _root.
node()) {
520 grutil_cat.error() <<
"GeoMipTerrain: root node unexpectedly mangled!\n";
527 grutil_cat.error() <<
"GeoMipTerrain: root node unexpectedly mangled: " << total <<
" vs " << (_root.
node()->
get_num_children()) <<
"\n";
540 if (_auto_flatten == AFM_off) {
549 np.node()->copy_children(_root.
node());
552 switch(_auto_flatten) {
558 _root_flattened =
true;
567 nassertv(_xsize >= 3 && _ysize >= 3);
569 for (
unsigned int mx = 0; mx < (_xsize - 1) / _block_size; mx++) {
571 for (
unsigned int my = 0; my < (_ysize - 1) / _block_size; my++) {
573 tvector.push_back(0);
575 tvector.push_back(min(
short(max(_min_level, lod_decide(mx, my))),
579 _levels.push_back(tvector);
596 update_block(
unsigned short mx,
unsigned short my,
597 signed short level,
bool forced) {
598 nassertr_always(!_is_dirty,
false);
599 nassertr_always(mx < (_xsize - 1) / _block_size,
false);
600 nassertr_always(my < (_ysize - 1) / _block_size,
false);
602 level = _levels[mx][my];
604 level = min(max(_min_level, (
unsigned short) level), _max_level);
605 if (forced || _old_levels[mx][my] != level) {
607 generate_block(mx, my, level)->replace_node(_blocks[mx][my].node());
626 if (!is_power_of_two(imgheader.
get_x_size() - 1) ||
627 !is_power_of_two(imgheader.
get_y_size() - 1)) {
629 unsigned int reqx, reqy;
630 reqx = max(3, (
int) pow(2.0, ceil(log((
double) max(2, imgheader.
get_x_size() - 1)) / log(2.0))) + 1);
631 reqy = max(3, (
int) pow(2.0, ceil(log((
double) max(2, imgheader.
get_y_size() - 1)) / log(2.0))) + 1);
634 if (reqx != (
unsigned int)imgheader.
get_x_size() ||
635 reqy != (
unsigned int)imgheader.
get_y_size()) {
637 <<
"Rescaling heightfield image " << filename
639 <<
" to " << reqx <<
"x" << reqy <<
" pixels.\n";
647 <<
"Heightfield image is specified to have sRGB color space!\n"
648 "Panda applies gamma correction, which will probably cause "
649 "it to produce incorrect results.\n";
653 if (!_heightfield.
read(filename, ftype)) {
655 grutil_cat.error() <<
"Failed to read heightfield image " << filename <<
"!\n";
664 grutil_cat.error() <<
"Failed to load heightfield image " << filename <<
"!\n";
672 unsigned short GeoMipTerrain::
673 get_neighbor_level(
unsigned short mx,
unsigned short my,
short dmx,
short dmy) {
676 if ((
int)mx + (
int)dmx < 0 || (
int)mx + (
int)dmx >= ((
int)_xsize - 1) / (
int)_block_size ||
677 (
int)my + (
int)dmy < 0 || (
int)my + (
int)dmy >= ((
int)_ysize - 1) / (
int)_block_size) {
678 return (_stitching) ? _max_level : min(max(_min_level, _levels[mx][my]), _max_level);
682 return min(max(_min_level, _levels[mx][my]), _max_level);
686 if (_levels[mx + dmx][my + dmy] > _levels[mx][my]) {
687 return min(max(_min_level, _levels[mx + dmx][my + dmy]), _max_level);
689 return min(max(_min_level, _levels[mx][my]), _max_level);