|
|
@@ -1,6 +1,5 @@
|
|
|
// Filename: geoMipTerrain.cxx
|
|
|
// Created by: pro-rsoft (29jun07)
|
|
|
-// Last updated by: pro-rsoft (17jan09)
|
|
|
//
|
|
|
////////////////////////////////////////////////////////////////////
|
|
|
//
|
|
|
@@ -82,17 +81,24 @@ generate_block(unsigned short mx,
|
|
|
|
|
|
if (_bruteforce) {
|
|
|
// LOD Level when rendering bruteforce is always 0 (no lod)
|
|
|
+ // Unless a minlevel is set- this is handled later.
|
|
|
level = 0;
|
|
|
}
|
|
|
|
|
|
// Do some calculations with the level
|
|
|
- level = min(short(max(_min_level, level)), short(_max_level));
|
|
|
+ level = min(max(_min_level, level), _max_level);
|
|
|
unsigned short reallevel = level;
|
|
|
level = int(pow(2.0, int(level)));
|
|
|
|
|
|
- // Stores the max and min heights.
|
|
|
- float minh = 1.0f;
|
|
|
- float maxh = 0.0f;
|
|
|
+ // Neighbor levels and junctions
|
|
|
+ unsigned short lnlevel = get_neighbor_level(mx, my, -1, 0);
|
|
|
+ unsigned short rnlevel = get_neighbor_level(mx, my, 1, 0);
|
|
|
+ unsigned short bnlevel = get_neighbor_level(mx, my, 0, -1);
|
|
|
+ unsigned short tnlevel = get_neighbor_level(mx, my, 0, 1);
|
|
|
+ bool ljunction = (lnlevel != reallevel);
|
|
|
+ bool rjunction = (rnlevel != reallevel);
|
|
|
+ bool bjunction = (bnlevel != reallevel);
|
|
|
+ bool tjunction = (tnlevel != reallevel);
|
|
|
|
|
|
// Confusing note:
|
|
|
// the variable level contains not the actual level as described
|
|
|
@@ -101,49 +107,43 @@ generate_block(unsigned short mx,
|
|
|
|
|
|
// This is the number of vertices at the certain level.
|
|
|
unsigned short lowblocksize = _block_size / level + 1;
|
|
|
-
|
|
|
+srand(time(NULL));
|
|
|
for (int x = 0; x <= _block_size; x++) {
|
|
|
for (int y = 0; y <= _block_size; y++) {
|
|
|
if ((x % level) == 0 && (y % level) == 0) {
|
|
|
if (_has_color_map) {
|
|
|
- LVecBase4d color = _color_map.get_xel_a(int((mx * _block_size + x)
|
|
|
- / double(_xsize) * _color_map.get_x_size()),
|
|
|
- int((my * _block_size + y)
|
|
|
- / double(_ysize) * _color_map.get_y_size()));
|
|
|
- cwriter.add_data4f(color.get_x(), color.get_y(),
|
|
|
- color.get_z(), color.get_w());
|
|
|
+ //LVecBase4d color = _color_map.get_xel_a(int((mx * _block_size + x)
|
|
|
+ /// double(_xsize) * _color_map.get_x_size()),
|
|
|
+// int((my * _block_size + y)
|
|
|
+// / double(_ysize) * _color_map.get_y_size()));
|
|
|
+ //cwriter.add_data4f(LCAST(float, color));
|
|
|
+
|
|
|
+ cwriter.add_data4f(rand() / float(RAND_MAX), rand() / float(RAND_MAX), rand() / float(RAND_MAX), 1);
|
|
|
}
|
|
|
float pval = get_pixel_value(mx, my, x, y);
|
|
|
- if (pval < minh) minh = pval;
|
|
|
- if (pval > maxh) maxh = pval;
|
|
|
vwriter.add_data3f(x - 0.5 * _block_size, y - 0.5 * _block_size, pval);
|
|
|
twriter.add_data2f((mx * _block_size + x) / double(_xsize - 1),
|
|
|
(my * _block_size + y) / double(_ysize - 1));
|
|
|
nwriter.add_data3f(get_normal(mx, my, x, y));
|
|
|
if (x > 0 && y > 0) {
|
|
|
- //left border
|
|
|
- if (!_bruteforce && x == level && mx > 0 && _levels[mx - 1][my] > reallevel) {
|
|
|
+ // Left border
|
|
|
+ if (x == level && ljunction) {
|
|
|
if (y > level && y < _block_size) {
|
|
|
- prim->add_vertex(min(max(sfav(y / level, _levels[mx - 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
+ prim->add_vertex(min(max(sfav(y / level, lnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
prim->add_vertex(vcounter - 1);
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- if (f_part((y / level) / float(pow(2.0, int(_levels[mx - 1][my] - reallevel)))) == 0.5) {
|
|
|
- prim->add_vertex(min(max(sfav(y / level + 1, _levels[mx - 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
- prim->add_vertex(min(max(sfav(y / level - 1, _levels[mx - 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
+ if (f_part((y / level) / float(pow(2.0, int(lnlevel - reallevel)))) == 0.5) {
|
|
|
+ prim->add_vertex(min(max(sfav(y / level + 1, lnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
+ prim->add_vertex(min(max(sfav(y / level - 1, lnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- } else if (_bruteforce ||
|
|
|
- (!(y == level && x > level && x < _block_size && my > 0
|
|
|
- && _levels[mx][my - 1] > reallevel) &&
|
|
|
- !(x == _block_size && mx < (_xsize - 1) / (_block_size) - 1
|
|
|
- && _levels[mx + 1][my] > reallevel) &&
|
|
|
- !(x == _block_size && y > level && y < _block_size && mx < (_xsize - 1) / (_block_size) - 1
|
|
|
- && _levels[mx + 1][my] > reallevel) &&
|
|
|
- !(y == _block_size && x > level && x < _block_size && my < (_ysize - 1) / (_block_size) - 1
|
|
|
- && _levels[mx][my + 1] > reallevel))) {
|
|
|
+ } else if (
|
|
|
+ (!(bjunction && y == level && x > level && x < _block_size) &&
|
|
|
+ !(rjunction && x == _block_size) &&
|
|
|
+ !(tjunction && y == _block_size && x > level && x < _block_size))) {
|
|
|
if ((x <= center && y <= center) || (x > center && y > center)) {
|
|
|
if (x > center) {
|
|
|
prim->add_vertex(vcounter - lowblocksize - 1);
|
|
|
@@ -167,36 +167,39 @@ generate_block(unsigned short mx,
|
|
|
}
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- //right border
|
|
|
- if (!_bruteforce && x == _block_size - level && mx < (_xsize - 1) / (_block_size) - 1 && _levels[mx + 1][my] > reallevel) {
|
|
|
- if (y > level && y < _block_size - level + 1) {
|
|
|
- prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level, _levels[mx + 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
+ // Right border
|
|
|
+ if (x == _block_size - level && rjunction) {
|
|
|
+ if (y > level && y < _block_size) {
|
|
|
+ prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level, rnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->add_vertex(vcounter - 1);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- if (f_part((y / level)/float(pow(2.0, int(_levels[mx + 1][my]-reallevel)))) == 0.5) {
|
|
|
- prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level - 1, _levels[mx + 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
- prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level + 1, _levels[mx + 1][my], reallevel), 0), lowblocksize - 1));
|
|
|
+ if (f_part((y / level) / float(pow(2.0, int(rnlevel - reallevel)))) == 0.5) {
|
|
|
+ prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level - 1, rnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
+ prim->add_vertex(lowblocksize * (lowblocksize - 1) + min(max(sfav(y / level + 1, rnlevel, reallevel), 0), lowblocksize - 1));
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
}
|
|
|
- //bottom border
|
|
|
- if (!_bruteforce && y == level && my > 0 && _levels[mx][my - 1] > reallevel) {
|
|
|
+ // Bottom border
|
|
|
+ if (y == level && bjunction) {
|
|
|
if (x > level && x < _block_size) {
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->add_vertex(vcounter - lowblocksize);
|
|
|
- prim->add_vertex(min(max(sfav(x / level, _levels[mx][my - 1], reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
+ prim->add_vertex(min(max(sfav(x / level, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- if (f_part((x / level)/float(pow(2.0, int(_levels[mx][my - 1]-reallevel)))) == 0.5) {
|
|
|
- prim->add_vertex(min(max(sfav(x / level - 1, _levels[mx][my - 1], reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
- prim->add_vertex(min(max(sfav(x / level + 1, _levels[mx][my - 1], reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
+ if (f_part((x / level) / float(pow(2.0, int(bnlevel - reallevel)))) == 0.5) {
|
|
|
+ prim->add_vertex(min(max(sfav(x / level - 1, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
+ prim->add_vertex(min(max(sfav(x / level + 1, bnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize);
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- } else if (_bruteforce || (!(x == level && y > level && y < _block_size && mx > 0 && _levels[mx - 1][my] > reallevel) && !(x == _block_size && y > level && y < _block_size && mx < (_xsize - 1) / (_block_size) - 1 && _levels[mx + 1][my] > reallevel) && !(x == _block_size && y > level && y < _block_size && mx < (_xsize - 1) / (_block_size) - 1 && _levels[mx + 1][my] > reallevel) && !(y == _block_size && my < (_ysize - 1) / (_block_size) - 1 && _levels[mx][my + 1] > reallevel))) {
|
|
|
+ } else if (
|
|
|
+ (!(ljunction && x == level && y > level && y < _block_size) &&
|
|
|
+ !(tjunction && y == _block_size) &&
|
|
|
+ !(rjunction && x == _block_size && y > level && y < _block_size))) {
|
|
|
if ((x <= center && y <= center) || (x > center && y > center)) {
|
|
|
if (y > center) {
|
|
|
prim->add_vertex(vcounter);
|
|
|
@@ -220,17 +223,17 @@ generate_block(unsigned short mx,
|
|
|
}
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- //top border
|
|
|
- if (!_bruteforce && y == _block_size - level && my < (_xsize - 1) / (_block_size) - 1 && _levels[mx][my + 1] > reallevel) {
|
|
|
- if (x > level && x < _block_size - level + 1) {
|
|
|
- prim->add_vertex(min(max(sfav(x / level, _levels[mx][my + 1], reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
+ // Top border
|
|
|
+ if (y == _block_size - level && tjunction) {
|
|
|
+ if (x > level && x < _block_size) {
|
|
|
+ prim->add_vertex(min(max(sfav(x / level, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
prim->add_vertex(vcounter - lowblocksize);
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
- if (f_part((x / level)/float(pow(2.0, int(_levels[mx][my + 1]-reallevel)))) == 0.5) {
|
|
|
- prim->add_vertex(min(max(sfav(x / level + 1, _levels[mx][my + 1], reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
- prim->add_vertex(min(max(sfav(x / level - 1, _levels[mx][my + 1], reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
+ if (f_part((x / level) / float(pow(2.0, int(tnlevel - reallevel)))) == 0.5) {
|
|
|
+ prim->add_vertex(min(max(sfav(x / level + 1, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
+ prim->add_vertex(min(max(sfav(x / level - 1, tnlevel, reallevel), 0), lowblocksize - 1) * lowblocksize + lowblocksize - 1);
|
|
|
prim->add_vertex(vcounter);
|
|
|
prim->close_primitive();
|
|
|
}
|
|
|
@@ -244,8 +247,10 @@ generate_block(unsigned short mx,
|
|
|
PT(Geom) geom = new Geom(vdata);
|
|
|
geom->add_primitive(prim);
|
|
|
geom->set_bounds_type(BoundingVolume::BT_box);
|
|
|
-
|
|
|
- PT(GeomNode) node = new GeomNode("gmm" + int_to_str(mx) + "x" + int_to_str(my));
|
|
|
+
|
|
|
+ ostringstream sname;
|
|
|
+ sname << "gmm" << mx << "x" << my;
|
|
|
+ PT(GeomNode) node = new GeomNode(sname.str());
|
|
|
node->add_geom(geom);
|
|
|
node->set_bounds_type(BoundingVolume::BT_box);
|
|
|
_old_levels.at(mx).at(my) = reallevel;
|
|
|
@@ -381,7 +386,7 @@ generate() {
|
|
|
_root_flattened = false;
|
|
|
for (unsigned int mx = 0; mx < (_xsize - 1) / _block_size; mx++) {
|
|
|
_old_levels[mx].resize(int((_ysize - 1) / _block_size));
|
|
|
- pvector<NodePath> tvector; //create temporary row
|
|
|
+ pvector<NodePath> tvector; // Create temporary row
|
|
|
for (unsigned int my = 0; my < (_ysize - 1) / _block_size; my++) {
|
|
|
if (_bruteforce) {
|
|
|
tvector.push_back(_root.attach_new_node(generate_block(mx, my, 0)));
|
|
|
@@ -390,7 +395,7 @@ generate() {
|
|
|
}
|
|
|
tvector[my].set_pos((mx + 0.5) * _block_size, (my + 0.5) * _block_size, 0);
|
|
|
}
|
|
|
- _blocks.push_back(tvector); //push the new row of NodePaths into the 2d vect
|
|
|
+ _blocks.push_back(tvector); // Push the new row of NodePaths into the 2d vect
|
|
|
tvector.clear();
|
|
|
}
|
|
|
auto_flatten();
|
|
|
@@ -600,3 +605,77 @@ update_block(unsigned short mx, unsigned short my,
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: GeoMipTerrain::set_heightfield
|
|
|
+// Access: Published
|
|
|
+// Description: Loads the specified heightmap image file into
|
|
|
+// the heightfield. Returns true if succeeded, or
|
|
|
+// false if an error has occured.
|
|
|
+// If the heightmap is not a power of two plus one,
|
|
|
+// it is scaled up using a gaussian filter.
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+bool GeoMipTerrain::
|
|
|
+set_heightfield(const Filename &filename, PNMFileType *ftype) {
|
|
|
+ // First, we need to load the header to determine the size and format.
|
|
|
+ PNMImageHeader imgheader;
|
|
|
+ if (imgheader.read_header(filename, ftype)) {
|
|
|
+ // Copy over the header to the heightfield image.
|
|
|
+ _heightfield.copy_header_from(imgheader);
|
|
|
+
|
|
|
+ if(!is_power_of_two(imgheader.get_x_size() - 1) || !is_power_of_two(imgheader.get_y_size() - 1)) {
|
|
|
+ // Calculate the nearest power-of-two-plus-one size.
|
|
|
+ unsigned int reqx, reqy;
|
|
|
+ reqx = max(3, (int) pow(2.0, ceil(log((double) max(2, imgheader.get_x_size() - 1)) / log(2.0))) + 1);
|
|
|
+ reqy = max(3, (int) pow(2.0, ceil(log((double) max(2, imgheader.get_y_size() - 1)) / log(2.0))) + 1);
|
|
|
+
|
|
|
+ // If it's not a valid size, tell PNMImage to resize it.
|
|
|
+ if (reqx != imgheader.get_x_size() || reqy != imgheader.get_y_size()) {
|
|
|
+ grutil_cat.warning() << "Rescaling heightfield image " << filename << " to "
|
|
|
+ << reqx << " by " << reqy << " pixels\n";
|
|
|
+ _heightfield.set_read_size(reqx, reqy);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // Read the real image now
|
|
|
+ if (!_heightfield.read(filename, ftype)) {
|
|
|
+ _heightfield.clear_read_size();
|
|
|
+ grutil_cat.error() << "Failed to read heightfield image " << filename << "!\n";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ _is_dirty = true;
|
|
|
+ _xsize = _heightfield.get_x_size();
|
|
|
+ _ysize = _heightfield.get_y_size();
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ grutil_cat.error() << "Failed to load heightfield image " << filename << "!\n";
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+// Function: GeoMipTerrain::get_neighbor_level
|
|
|
+// Access: Private
|
|
|
+// Description: Helper function for generate().
|
|
|
+////////////////////////////////////////////////////////////////////
|
|
|
+unsigned short GeoMipTerrain::
|
|
|
+get_neighbor_level(unsigned short mx, unsigned short my, short dmx, short dmy) {
|
|
|
+ // If we're across the terrain border, check if we want stitching.
|
|
|
+ // If not, return the same level as this one - it won't have to make junctions.
|
|
|
+ if (mx + dmx < 0 || mx + dmx >= (_xsize - 1) / _block_size ||
|
|
|
+ my + dmy < 0 || my + dmy >= (_ysize - 1) / _block_size) {
|
|
|
+ return (_stitching) ? _max_level : min(max(_min_level, _levels[mx][my]), _max_level);
|
|
|
+ }
|
|
|
+ // If we're rendering bruteforce, the level must be the same as this one.
|
|
|
+ if (_bruteforce) {
|
|
|
+ return min(max(_min_level, _levels[mx][my]), _max_level);
|
|
|
+ }
|
|
|
+ // Only if the level is higher than the current.
|
|
|
+ // Otherwise, the junctions will be made for the other chunk.
|
|
|
+ if (_levels[mx + dmx][my + dmy] > _levels[mx][my]) {
|
|
|
+ return min(max(_min_level, _levels[mx + dmx][my + dmy]), _max_level);
|
|
|
+ } else {
|
|
|
+ return min(max(_min_level, _levels[mx][my]), _max_level);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|