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;