@@ -175,10 +175,14 @@ impl Ground {
175175 // continuous — the renderer's hard `> 0.5` threshold then traces
176176 // a clean curved shoreline contour instead of the raw ESA 10 m
177177 // rectangular grid edge.
178- let w00 = lc. water_blend_grid [ z0] [ x0] ;
179- let w10 = lc. water_blend_grid [ z0] [ x1] ;
180- let w01 = lc. water_blend_grid [ z1] [ x0] ;
181- let w11 = lc. water_blend_grid [ z1] [ x1] ;
178+ // Widen f32 storage to f64 for the bilinear arithmetic. This
179+ // doesn't recover the ~10⁻⁷ precision lost at storage, but it
180+ // prevents extra rounding from accumulating in the four
181+ // multiply-adds + the threshold comparison downstream.
182+ let w00 = lc. water_blend_grid [ z0] [ x0] as f64 ;
183+ let w10 = lc. water_blend_grid [ z0] [ x1] as f64 ;
184+ let w01 = lc. water_blend_grid [ z1] [ x0] as f64 ;
185+ let w11 = lc. water_blend_grid [ z1] [ x1] as f64 ;
182186
183187 // Bilinear interpolation
184188 let top = w00 * ( 1.0 - tx) + w10 * tx;
@@ -297,10 +301,17 @@ impl Ground {
297301 let z1 = ( z0 + 1 ) . min ( data. height - 1 ) ;
298302 let dx = fx - x0 as f64 ;
299303 let dz = fz - z0 as f64 ;
300- let v00 = data. heights [ z0] [ x0] ;
301- let v10 = data. heights [ z0] [ x1] ;
302- let v01 = data. heights [ z1] [ x0] ;
303- let v11 = data. heights [ z1] [ x1] ;
304+ // Widen f32 storage to f64 for the bilinear arithmetic. The real
305+ // property we rely on: across the Minecraft Y range (roughly −64 up
306+ // through a few thousand even with --disable-height-limit), f32's
307+ // mantissa gives ~10⁻⁷ precision per stored cell, which is far
308+ // smaller than the 0.5-block half-width used by `round()` below.
309+ // So for any value that isn't pathologically close to a half-integer
310+ // boundary, the final `result.round() as i32` matches the f64 path.
311+ let v00 = data. heights [ z0] [ x0] as f64 ;
312+ let v10 = data. heights [ z0] [ x1] as f64 ;
313+ let v01 = data. heights [ z1] [ x0] as f64 ;
314+ let v11 = data. heights [ z1] [ x1] as f64 ;
304315 let lerp_top = v00 + ( v10 - v00) * dx;
305316 let lerp_bot = v01 + ( v11 - v01) * dx;
306317 let result = lerp_top + ( lerp_bot - lerp_top) * dz;
@@ -318,7 +329,12 @@ impl Ground {
318329 world_height : usize ,
319330 ) {
320331 if let Some ( ref mut data) = self . elevation_data {
321- data. heights = heights;
332+ // Rotation operators build a fresh f64 work grid; downcast here to
333+ // match `ElevationData::heights`'s f32 storage layout.
334+ data. heights = heights
335+ . into_iter ( )
336+ . map ( |row| row. into_iter ( ) . map ( |v| v as f32 ) . collect ( ) )
337+ . collect ( ) ;
322338 data. width = grid_width;
323339 data. height = grid_height;
324340 data. world_width = world_width;
@@ -389,8 +405,8 @@ impl Ground {
389405 let mut img: image:: ImageBuffer < Rgb < u8 > , Vec < u8 > > =
390406 RgbImage :: new ( width as u32 , height as u32 ) ;
391407
392- let mut min_height: f64 = f64 :: MAX ;
393- let mut max_height: f64 = f64 :: MIN ;
408+ let mut min_height: f32 = f32 :: MAX ;
409+ let mut max_height: f32 = f32 :: MIN ;
394410
395411 for row in heights {
396412 for & h in row {
0 commit comments