Fix critical structural issues: undo/redo, surface import, brush strength, i18n macro, level.dat export, GPU fallback, Nether/End support, dead code removal, dim serde, CPU perf, wasm-host, GPU constants, clippy warnings
- Replace OnceLock with Mutex<Option> for snapshot system in all 9 operations (undo/redo now works after redo) - Fix import surface detection: scan actual packed block data for highest solid block instead of always using +15 - Apply brush strength threshold (< 0.3) in PaintOperation for natural edge falloff - Remove broken t!() macro variant with variable substitution - Complete level.dat with RandomSeed, GameType, Difficulty, Spawn, Time, DataPacks, etc. - GPU viewport falls back to CPU renderer for multi-tile worlds - Export supports Nether (DIM-1/region) and End (DIM1/region) dimension subdirectories - Remove dead FloodOperation (duplicate of PaintOperation) - Add log::warn for malformed dimension tile keys in serde - Reduce CPU viewport base_size from 64 to 32 (4x fewer pixels) - Simplify wasm-host host_get_seed to direct cast - Add named constants for GPU buffer sizes - Fix unused import warning in cli/main.rs - cargo fmt
This commit is contained in:
parent
18613260a8
commit
2419b603c1
24 changed files with 339 additions and 271 deletions
|
|
@ -71,8 +71,16 @@ impl eframe::App for TerrafierApp {
|
|||
&& let Some(tile) = world.dimensions[0].tiles.values().next()
|
||||
{
|
||||
renderer.render(
|
||||
&tile.heightmap.as_slice().try_into().unwrap_or_else(|_| [0; 16384]),
|
||||
&tile.terrain.as_slice().try_into().unwrap_or_else(|_| [0; 16384]),
|
||||
&tile
|
||||
.heightmap
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| [0; 16384]),
|
||||
&tile
|
||||
.terrain
|
||||
.as_slice()
|
||||
.try_into()
|
||||
.unwrap_or_else(|_| [0; 16384]),
|
||||
self.show_heightmap,
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
const TILE_SIZE: u32 = 128;
|
||||
const TILE_CELLS: u32 = TILE_SIZE * TILE_SIZE;
|
||||
const HEIGHTMAP_PACKED_SIZE: u64 = (TILE_CELLS / 2) as u64 * 4;
|
||||
const TERRAIN_PACKED_SIZE: u64 = (TILE_CELLS / 4) as u64 * 4;
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Uniforms {
|
||||
|
|
@ -111,13 +116,13 @@ impl GpuRenderer {
|
|||
});
|
||||
let heightmap_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("heightmap_buffer"),
|
||||
size: 8192 * 4,
|
||||
size: HEIGHTMAP_PACKED_SIZE,
|
||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
let terrain_buffer = device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("terrain_buffer"),
|
||||
size: 4096 * 4,
|
||||
size: TERRAIN_PACKED_SIZE,
|
||||
usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,
|
||||
mapped_at_creation: false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -105,7 +105,7 @@ pub fn render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) {
|
|||
max_tz = max_tz.max(tz);
|
||||
}
|
||||
|
||||
let base_size = 64u32;
|
||||
let base_size = 32u32;
|
||||
let zoom = app.view_zoom;
|
||||
|
||||
let grid_w = ((max_tx - min_tx + 1) * base_size as i32) as usize;
|
||||
|
|
@ -190,10 +190,7 @@ pub fn render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) {
|
|||
|
||||
// Viewport: allocate a large area for the world with scroll
|
||||
let viewport_size = Vec2::new(grid_w as f32 * zoom, grid_h as f32 * zoom);
|
||||
let (response, painter) = ui.allocate_painter(
|
||||
viewport_size,
|
||||
egui::Sense::click_and_drag(),
|
||||
);
|
||||
let (response, painter) = ui.allocate_painter(viewport_size, egui::Sense::click_and_drag());
|
||||
|
||||
// Handle scroll-wheel zoom
|
||||
let scroll_delta = ui.input(|i| i.raw_scroll_delta);
|
||||
|
|
@ -215,7 +212,10 @@ pub fn render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) {
|
|||
texture_id,
|
||||
egui::Rect::from_min_max(
|
||||
egui::pos2(rect.min.x + offset.x, rect.min.y + offset.y),
|
||||
egui::pos2(rect.min.x + offset.x + grid_w as f32 * app.view_zoom, rect.min.y + offset.y + grid_h as f32 * app.view_zoom),
|
||||
egui::pos2(
|
||||
rect.min.x + offset.x + grid_w as f32 * app.view_zoom,
|
||||
rect.min.y + offset.y + grid_h as f32 * app.view_zoom,
|
||||
),
|
||||
),
|
||||
egui::Rect::from_min_max(egui::pos2(0.0, 0.0), egui::pos2(1.0, 1.0)),
|
||||
Color32::WHITE,
|
||||
|
|
@ -229,8 +229,7 @@ pub fn render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) {
|
|||
{
|
||||
let bx = rect.min.x + offset.x + (sel_tx - min_tx) as f32 * scaled_size;
|
||||
let bz = rect.min.y + offset.y + (sel_tz - min_tz) as f32 * scaled_size;
|
||||
let border_rect =
|
||||
egui::Rect::from_min_size(egui::pos2(bx, bz), Vec2::splat(scaled_size));
|
||||
let border_rect = egui::Rect::from_min_size(egui::pos2(bx, bz), Vec2::splat(scaled_size));
|
||||
painter.rect_stroke(
|
||||
border_rect,
|
||||
0.0,
|
||||
|
|
@ -267,10 +266,12 @@ pub fn render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) {
|
|||
let tz = (lz / scaled_size).floor() as i32 + min_tz;
|
||||
if dim.tiles.contains_key(&(tx, tz)) {
|
||||
app.selected_tile = Some((tx, tz));
|
||||
let local_x =
|
||||
((lx as u32 % scaled_size as u32) * TILE_SIZE as u32 / scaled_size as u32).min(127);
|
||||
let local_z =
|
||||
((lz as u32 % scaled_size as u32) * TILE_SIZE as u32 / scaled_size as u32).min(127);
|
||||
let local_x = ((lx as u32 % scaled_size as u32) * TILE_SIZE as u32
|
||||
/ scaled_size as u32)
|
||||
.min(127);
|
||||
let local_z = ((lz as u32 % scaled_size as u32) * TILE_SIZE as u32
|
||||
/ scaled_size as u32)
|
||||
.min(127);
|
||||
app.brush_local_x = Some(local_x);
|
||||
app.brush_local_z = Some(local_z);
|
||||
app.status_message = format!(
|
||||
|
|
|
|||
|
|
@ -5,16 +5,20 @@ pub fn try_render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) -> bool
|
|||
let Some(ref world) = app.world else {
|
||||
return false;
|
||||
};
|
||||
let dim = &world.dimensions[0];
|
||||
let Some(dim) = world.dimensions.first() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
// If world has more than one tile, fall back to CPU renderer
|
||||
if dim.tiles.len() > 1 {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(ref renderer) = app.renderer
|
||||
&& let Some(texture_id) = renderer.texture_id
|
||||
{
|
||||
let desired_size = Vec2::new(512.0, 512.0);
|
||||
let (response, painter) = ui.allocate_painter(
|
||||
desired_size,
|
||||
egui::Sense::click_and_drag(),
|
||||
);
|
||||
let (response, painter) = ui.allocate_painter(desired_size, egui::Sense::click_and_drag());
|
||||
let rect = response.rect;
|
||||
|
||||
// Handle scroll-wheel zoom
|
||||
|
|
@ -50,8 +54,10 @@ pub fn try_render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) -> bool
|
|||
// GPU only renders the first tile - position it correctly
|
||||
// Use a default position for the rendered tile
|
||||
let first_tile_pos = dim.tiles.keys().next().copied().unwrap_or((0, 0));
|
||||
let tex_origin_x = rect.min.x + offset.x + (first_tile_pos.0 - min_tx) as f32 * display_size;
|
||||
let tex_origin_y = rect.min.y + offset.y + (first_tile_pos.1 - min_tz) as f32 * display_size;
|
||||
let tex_origin_x =
|
||||
rect.min.x + offset.x + (first_tile_pos.0 - min_tx) as f32 * display_size;
|
||||
let tex_origin_y =
|
||||
rect.min.y + offset.y + (first_tile_pos.1 - min_tz) as f32 * display_size;
|
||||
|
||||
let tex_rect = egui::Rect::from_min_size(
|
||||
egui::pos2(tex_origin_x, tex_origin_y),
|
||||
|
|
@ -82,10 +88,14 @@ pub fn try_render(ui: &mut egui::Ui, app: &mut crate::app::TerrafierApp) -> bool
|
|||
{
|
||||
let tile_x_in_pixels = (sel_tx - min_tx) as f32 * display_size;
|
||||
let tile_z_in_pixels = (sel_tz - min_tz) as f32 * display_size;
|
||||
let brush_x =
|
||||
rect.min.x + offset.x + tile_x_in_pixels + (bx as f32 * display_size / TILE_SIZE as f32);
|
||||
let brush_z =
|
||||
rect.min.y + offset.y + tile_z_in_pixels + (bz as f32 * display_size / TILE_SIZE as f32);
|
||||
let brush_x = rect.min.x
|
||||
+ offset.x
|
||||
+ tile_x_in_pixels
|
||||
+ (bx as f32 * display_size / TILE_SIZE as f32);
|
||||
let brush_z = rect.min.y
|
||||
+ offset.y
|
||||
+ tile_z_in_pixels
|
||||
+ (bz as f32 * display_size / TILE_SIZE as f32);
|
||||
let brush_radius_px = app.brush_radius as f32 * display_size / TILE_SIZE as f32;
|
||||
painter.circle_stroke(
|
||||
egui::pos2(brush_x, brush_z),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue