15 #include "heightfieldTesselator.h" 17 #include "transformState.h" 18 #include "sceneGraphReducer.h" 30 void HeightfieldTesselator::
31 fix_heightfield(
int size) {
36 int xcells = (xsize + size - 2) / size;
37 int ycells = (ysize + size - 2) / size;
38 int xpadded = xcells * size + 1;
39 int ypadded = ycells * size + 1;
50 _heightfield.
clear(xpadded, ypadded, 1,
53 for (
int y = 0; y < ysize; y++) {
54 for (
int x = 0; x < xsize; x++) {
55 _heightfield.
set_gray_val(x, y, unfixed.get_gray_val(x, y));
58 for (
int y = ysize; y < ypadded; y++) {
59 for (
int x = xsize; x < xpadded; x++) {
77 int size = 1 << scale;
78 fix_heightfield(size);
89 double xoffs = x - xlo;
90 double yoffs = y - ylo;
91 double grayxlyl = _heightfield.
get_gray(xlo,ylo);
92 double grayxhyl = _heightfield.
get_gray(xhi,ylo);
93 double grayxlyh = _heightfield.
get_gray(xlo,yhi);
94 double grayxhyh = _heightfield.
get_gray(xhi,yhi);
95 double lerpyl = grayxhyl * xoffs + grayxlyl * (1.0 - xoffs);
96 double lerpyh = grayxhyh * xoffs + grayxlyh * (1.0 - xoffs);
97 return lerpyh * yoffs + lerpyl * (1.0 - yoffs);
106 int HeightfieldTesselator::
107 get_vertex(
int x,
int y) {
109 int vtx = _vertex_index[x+y*xsize];
123 LVector3 normal(drx * _vertical_scale * 0.5, dry * _vertical_scale * 0.5, _horizontal_scale);
125 double z = _heightfield.
get_gray(x,y);
126 _vertex_writer->
add_data3(x*_horizontal_scale,-y*_horizontal_scale,z*_vertical_scale);
129 _dirty_vertices[vtx] = x+y*xsize;
130 _vertex_index[x+y*xsize] = vtx;
144 int size = 1 << scale;
145 fix_heightfield(size);
148 int xcells = (xsize + size - 2) / size;
149 int ycells = (ysize + size - 2) / size;
151 _vertex_index =
new int[xsize * ysize];
152 _dirty_vertices =
new int[xsize * ysize];
153 _triangle_totals =
new int[xsize * ysize];
154 for (
int y=0; y<ysize; y++) {
155 for (
int x=0; x<xsize; x++) {
156 _vertex_index[y*xsize+x] = -1;
160 if (!_radii_calculated) {
161 int saved_focal_x = _focal_x;
162 int saved_focal_y = _focal_y;
167 calculate_radii(scale);
169 _focal_x = saved_focal_x;
170 _focal_y = saved_focal_y;
172 _radii_calculated =
true;
179 for (
int y=0; y<ycells; y++) {
180 for (
int x=0; x<xcells; x++) {
181 total += count_triangles(scale,x*size,y*size);
184 for (
int y=0; y<ycells; y++) {
185 for (
int x=0; x<xcells; x++) {
186 generate_square(root,scale,x*size,y*size,
true);
189 delete[] _vertex_index;
190 delete[] _dirty_vertices;
191 delete[] _triangle_totals;
206 void HeightfieldTesselator::
207 calculate_radii(
int scale) {
208 int size = 1 << scale;
211 int xcells = (xsize + size - 2) / size;
212 int ycells = (ysize + size - 2) / size;
217 double mid = (lo + hi) * 0.5;
218 for (
int i=0; i<16; i++) {
219 _radii[i] = (int)(mid * (1<<i));
222 for (
int y=0; y<ycells; y++) {
223 for (
int x=0; x<xcells; x++) {
224 total += count_triangles(scale,x*size,y*size);
227 if (total > _poly_count) {
236 double mid = (lo + hi) * 0.5;
237 for (
int i=0; i<16; i++) {
238 _radii[i] = (int)(mid * (1<<i));
262 void HeightfieldTesselator::
263 generate_square(
NodePath root,
int scale,
int x,
int y,
bool forceclose) {
276 #define POINTA get_vertex(x ,y) 277 #define POINTB get_vertex(x+hsize,y) 278 #define POINTC get_vertex(x+size ,y) 279 #define POINTD get_vertex(x ,y+hsize) 280 #define POINTE get_vertex(x+hsize,y+hsize) 281 #define POINTF get_vertex(x+size ,y+hsize) 282 #define POINTG get_vertex(x ,y+size) 283 #define POINTH get_vertex(x+hsize,y+size) 284 #define POINTI get_vertex(x+size ,y+size) 286 if (_triangles == 0) {
289 if (subdivide(scale, x, y)) {
290 int xc = x+(size>>1);
291 int yc = y+(size>>1);
292 if (_triangle_totals[yc*_heightfield.
get_x_size()+xc] > _max_triangles) {
293 if (_next_index) close_geom(root);
295 generate_square(subroot, scale-1, x, y ,
true);
296 generate_square(subroot, scale-1, xc, y ,
true);
297 generate_square(subroot, scale-1, xc, yc,
true);
298 generate_square(subroot, scale-1, x, yc,
true);
300 generate_square(root, scale-1, x, y ,
false);
301 generate_square(root, scale-1, xc, y ,
false);
302 generate_square(root, scale-1, xc, yc,
false);
303 generate_square(root, scale-1, x, yc,
false);
305 }
else if (subdivide(scale, x+size, y)) {
306 add_quad(POINTG,POINTA,POINTI,POINTF);
307 add_quad(POINTA,POINTA,POINTF,POINTC);
308 }
else if (subdivide(scale, x-size, y)) {
309 add_quad(POINTG,POINTD,POINTI,POINTI);
310 add_quad(POINTD,POINTA,POINTI,POINTC);
311 }
else if (subdivide(scale, x, y+size)) {
312 add_quad(POINTG,POINTA,POINTH,POINTA);
313 add_quad(POINTH,POINTA,POINTI,POINTC);
314 }
else if (subdivide(scale, x, y-size)) {
315 add_quad(POINTG,POINTA,POINTI,POINTB);
316 add_quad(POINTI,POINTB,POINTI,POINTC);
318 add_quad(POINTG,POINTA,POINTI,POINTC);
320 if (forceclose || (_next_index > _max_triangles)) {
333 int HeightfieldTesselator::
334 count_triangles(
int scale,
int x,
int y) {
336 if (subdivide(scale, x, y)) {
337 int xc = x + (size>>1);
338 int yc = y + (size>>1);
340 n += count_triangles(scale-1, x, y );
341 n += count_triangles(scale-1, xc, y );
342 n += count_triangles(scale-1, x, yc);
343 n += count_triangles(scale-1, xc, yc);
344 _triangle_totals[yc*_heightfield.
get_x_size() + xc] = n;
346 }
else if (subdivide(scale, x+size, y)) {
348 }
else if (subdivide(scale, x-size, y)) {
350 }
else if (subdivide(scale, x, y+size)) {
352 }
else if (subdivide(scale, x, y-size)) {
364 void HeightfieldTesselator::
365 add_quad_to_strip(
int v1,
int v2,
int v3,
int v4) {
366 if ((v1 != v2)&&(v2 != v3)&&(v1 != v3)) {
367 _triangles->add_vertices(v1,v3,v2);
369 if ((v3 != v2)&&(v2 != v4)&&(v4 != v3)) {
370 _triangles->add_vertices(v3,v4,v2);
388 void HeightfieldTesselator::
389 add_quad(
int v1,
int v2,
int v3,
int v4) {
390 add_quad_to_strip(v1, v2, v3, v4);
399 void HeightfieldTesselator::
402 (
"heightfield", GeomVertexFormat::get_v3n3(), Geom::UH_static);
406 _triangles->set_shade_model(Geom::SM_uniform);
418 void HeightfieldTesselator::
420 if (_triangles == 0) {
423 _triangles->close_primitive();
425 geom->add_primitive(_triangles);
427 gnode->add_geom(geom);
429 delete _vertex_writer;
430 delete _normal_writer;
432 for (
int i=0; i<_next_index; i++) {
433 _vertex_index[_dirty_vertices[i]] = -1;
void set_gray_val(int x, int y, xelval gray)
Sets the gray component color at the indicated pixel.
A basic node of the scene graph or data graph.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
This is a three-component vector distance (as opposed to a three-component point, which represents a ...
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
void add_data3(PN_stdfloat x, PN_stdfloat y, PN_stdfloat z)
Sets the write row to a particular 3-component value, and advances the write row. ...
NodePath generate()
Generates a tree of nodes that represents the heightfield.
double get_elevation(double x, double y)
Fetches the elevation at (x,y), where the input coordinate is specified in pixels.
void clear()
Frees all memory allocated for the image, and clears all its parameters (size, color, type, etc).
Defines a series of disconnected triangles.
bool normalize()
Normalizes the vector in place.
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
A node that holds Geom objects, renderable pieces of geometry.