25 void HeightfieldTesselator::
26 fix_heightfield(
int size) {
31 int xcells = (xsize + size - 2) / size;
32 int ycells = (ysize + size - 2) / size;
33 int xpadded = xcells * size + 1;
34 int ypadded = ycells * size + 1;
45 _heightfield.
clear(xpadded, ypadded, 1,
48 for (
int y = 0; y < ysize; y++) {
49 for (
int x = 0; x < xsize; x++) {
50 _heightfield.
set_gray_val(x, y, unfixed.get_gray_val(x, y));
53 for (
int y = ysize; y < ypadded; y++) {
54 for (
int x = xsize; x < xpadded; x++) {
68 int size = 1 << scale;
69 fix_heightfield(size);
80 double xoffs = x - xlo;
81 double yoffs = y - ylo;
82 double grayxlyl = _heightfield.
get_gray(xlo,ylo);
83 double grayxhyl = _heightfield.
get_gray(xhi,ylo);
84 double grayxlyh = _heightfield.
get_gray(xlo,yhi);
85 double grayxhyh = _heightfield.
get_gray(xhi,yhi);
86 double lerpyl = grayxhyl * xoffs + grayxlyl * (1.0 - xoffs);
87 double lerpyh = grayxhyh * xoffs + grayxlyh * (1.0 - xoffs);
88 return lerpyh * yoffs + lerpyl * (1.0 - yoffs);
94 int HeightfieldTesselator::
95 get_vertex(
int x,
int y) {
97 int vtx = _vertex_index[x+y*xsize];
111 LVector3 normal(drx * _vertical_scale * 0.5, dry * _vertical_scale * 0.5, _horizontal_scale);
113 double z = _heightfield.
get_gray(x,y);
114 _vertex_writer->
add_data3(x*_horizontal_scale,-y*_horizontal_scale,z*_vertical_scale);
117 _dirty_vertices[vtx] = x+y*xsize;
118 _vertex_index[x+y*xsize] = vtx;
130 int size = 1 << scale;
131 fix_heightfield(size);
134 int xcells = (xsize + size - 2) / size;
135 int ycells = (ysize + size - 2) / size;
137 _vertex_index =
new int[xsize * ysize];
138 _dirty_vertices =
new int[xsize * ysize];
139 _triangle_totals =
new int[xsize * ysize];
140 for (
int y=0; y<ysize; y++) {
141 for (
int x=0; x<xsize; x++) {
142 _vertex_index[y*xsize+x] = -1;
146 if (!_radii_calculated) {
147 int saved_focal_x = _focal_x;
148 int saved_focal_y = _focal_y;
153 calculate_radii(scale);
155 _focal_x = saved_focal_x;
156 _focal_y = saved_focal_y;
158 _radii_calculated =
true;
165 for (
int y=0; y<ycells; y++) {
166 for (
int x=0; x<xcells; x++) {
167 total += count_triangles(scale,x*size,y*size);
170 for (
int y=0; y<ycells; y++) {
171 for (
int x=0; x<xcells; x++) {
172 generate_square(root,scale,x*size,y*size,
true);
175 delete[] _vertex_index;
176 delete[] _dirty_vertices;
177 delete[] _triangle_totals;
178 _vertex_index =
nullptr;
179 _dirty_vertices =
nullptr;
180 _triangle_totals =
nullptr;
189 void HeightfieldTesselator::
190 calculate_radii(
int scale) {
191 int size = 1 << scale;
194 int xcells = (xsize + size - 2) / size;
195 int ycells = (ysize + size - 2) / size;
200 double mid = (lo + hi) * 0.5;
201 for (
int i=0; i<16; i++) {
202 _radii[i] = (int)(mid * (1<<i));
205 for (
int y=0; y<ycells; y++) {
206 for (
int x=0; x<xcells; x++) {
207 total += count_triangles(scale,x*size,y*size);
210 if (total > _poly_count) {
219 double mid = (lo + hi) * 0.5;
220 for (
int i=0; i<16; i++) {
221 _radii[i] = (int)(mid * (1<<i));
240 void HeightfieldTesselator::
241 generate_square(
NodePath root,
int scale,
int x,
int y,
bool forceclose) {
250 #define POINTA get_vertex(x ,y) 251 #define POINTB get_vertex(x+hsize,y) 252 #define POINTC get_vertex(x+size ,y) 253 #define POINTD get_vertex(x ,y+hsize) 254 #define POINTE get_vertex(x+hsize,y+hsize) 255 #define POINTF get_vertex(x+size ,y+hsize) 256 #define POINTG get_vertex(x ,y+size) 257 #define POINTH get_vertex(x+hsize,y+size) 258 #define POINTI get_vertex(x+size ,y+size) 260 if (_triangles ==
nullptr) {
263 if (subdivide(scale, x, y)) {
264 int xc = x+(size>>1);
265 int yc = y+(size>>1);
266 if (_triangle_totals[yc*_heightfield.
get_x_size()+xc] > _max_triangles) {
267 if (_next_index) close_geom(root);
269 generate_square(subroot, scale-1, x, y ,
true);
270 generate_square(subroot, scale-1, xc, y ,
true);
271 generate_square(subroot, scale-1, xc, yc,
true);
272 generate_square(subroot, scale-1, x, yc,
true);
274 generate_square(root, scale-1, x, y ,
false);
275 generate_square(root, scale-1, xc, y ,
false);
276 generate_square(root, scale-1, xc, yc,
false);
277 generate_square(root, scale-1, x, yc,
false);
279 }
else if (subdivide(scale, x+size, y)) {
280 add_quad(POINTG,POINTA,POINTI,POINTF);
281 add_quad(POINTA,POINTA,POINTF,POINTC);
282 }
else if (subdivide(scale, x-size, y)) {
283 add_quad(POINTG,POINTD,POINTI,POINTI);
284 add_quad(POINTD,POINTA,POINTI,POINTC);
285 }
else if (subdivide(scale, x, y+size)) {
286 add_quad(POINTG,POINTA,POINTH,POINTA);
287 add_quad(POINTH,POINTA,POINTI,POINTC);
288 }
else if (subdivide(scale, x, y-size)) {
289 add_quad(POINTG,POINTA,POINTI,POINTB);
290 add_quad(POINTI,POINTB,POINTI,POINTC);
292 add_quad(POINTG,POINTA,POINTI,POINTC);
294 if (forceclose || (_next_index > _max_triangles)) {
303 int HeightfieldTesselator::
304 count_triangles(
int scale,
int x,
int y) {
306 if (subdivide(scale, x, y)) {
307 int xc = x + (size>>1);
308 int yc = y + (size>>1);
310 n += count_triangles(scale-1, x, y );
311 n += count_triangles(scale-1, xc, y );
312 n += count_triangles(scale-1, x, yc);
313 n += count_triangles(scale-1, xc, yc);
314 _triangle_totals[yc*_heightfield.
get_x_size() + xc] = n;
316 }
else if (subdivide(scale, x+size, y)) {
318 }
else if (subdivide(scale, x-size, y)) {
320 }
else if (subdivide(scale, x, y+size)) {
322 }
else if (subdivide(scale, x, y-size)) {
332 void HeightfieldTesselator::
333 add_quad_to_strip(
int v1,
int v2,
int v3,
int v4) {
334 if ((v1 != v2)&&(v2 != v3)&&(v1 != v3)) {
335 _triangles->add_vertices(v1,v3,v2);
337 if ((v3 != v2)&&(v2 != v4)&&(v4 != v3)) {
338 _triangles->add_vertices(v3,v4,v2);
351 void HeightfieldTesselator::
352 add_quad(
int v1,
int v2,
int v3,
int v4) {
353 add_quad_to_strip(v1, v2, v3, v4);
360 void HeightfieldTesselator::
367 _triangles->set_shade_model(Geom::SM_uniform);
377 void HeightfieldTesselator::
379 if (_triangles ==
nullptr) {
382 _triangles->close_primitive();
384 geom->add_primitive(_triangles);
386 gnode->add_geom(geom);
388 delete _vertex_writer;
389 delete _normal_writer;
391 for (
int i=0; i<_next_index; i++) {
392 _vertex_index[_dirty_vertices[i]] = -1;
398 _vertex_writer =
nullptr;
399 _normal_writer =
nullptr;
400 _triangles =
nullptr;
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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,...
Defines a series of disconnected triangles.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.