From 1c259be0f997c7e39d483f9d506f64a2800a811c Mon Sep 17 00:00:00 2001 From: Hrnchamd Date: Sat, 8 Apr 2023 23:26:12 +0100 Subject: [PATCH] MGEXEgui: Build distant landscape per atlas region, to avoid allocating a huge but mostly empty heightmap to cover the whole world. --- MGEfuncs/LandTessellator.cpp | 9 +++- MGEgui/DistantLand/DistantLandForm.cs | 68 +++++++++++++++------------ 2 files changed, 45 insertions(+), 32 deletions(-) diff --git a/MGEfuncs/LandTessellator.cpp b/MGEfuncs/LandTessellator.cpp index bf0ad339..4a8b1212 100644 --- a/MGEfuncs/LandTessellator.cpp +++ b/MGEfuncs/LandTessellator.cpp @@ -98,13 +98,20 @@ class LandMesh { } static bool SaveMeshes(LPCSTR file_path, vector& meshes) { - HANDLE file = CreateFile(file_path, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0); + HANDLE file = CreateFile(file_path, GENERIC_READ|GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0); if (file == INVALID_HANDLE_VALUE) { return false; } DWORD unused, mesh_count = meshes.size(); + if (GetFileSize(file, NULL) > 0) { + DWORD existing_count; + ReadFile(file, &existing_count, sizeof(existing_count), &unused, 0); + mesh_count += existing_count; + SetFilePointer(file, 0, NULL, FILE_BEGIN); + } WriteFile(file, &mesh_count, sizeof(mesh_count), &unused, 0); + SetFilePointer(file, 0, NULL, FILE_END); for (size_t i = 0; i < meshes.size(); ++i) { if (!meshes[i].Save(file)) { diff --git a/MGEgui/DistantLand/DistantLandForm.cs b/MGEgui/DistantLand/DistantLandForm.cs index 0100a45c..fa73c9d4 100644 --- a/MGEgui/DistantLand/DistantLandForm.cs +++ b/MGEgui/DistantLand/DistantLandForm.cs @@ -2231,30 +2231,6 @@ private void GenerateWorldMesh(int detail, string path) { tolerance = toleranceOptions[detail]; } - // Produce large heightmap array - int MapSpanX = MapMaxX - MapMinX + 1; - int MapSpanY = MapMaxY - MapMinY + 1; - int DataSpanX = MapSpanX * 64; - int DataSpanY = MapSpanY * 64; - - var height_data = new float[DataSpanX * DataSpanY]; - - for (int y1 = MapMinY; y1 <= MapMaxY; y1++) { - for (int y2 = 0; y2 < 64; y2++) { - for (int x1 = MapMinX; x1 <= MapMaxX; x1++) { - for (int x2 = 0; x2 < 64; x2++) { - int y = (y1 - MapMinY) * 64 + y2; - int x = (x1 - MapMinX) * 64 + x2; - if (LandMap[x1, y1] != null) { - height_data[y * DataSpanX + x] = (float)LandMap[x1, y1].Heights[x2, y2] * 8.0f; - } else { - height_data[y * DataSpanX + x] = -2048.0f; - } - } - } - } - } - // Produce packed atlas data var atlas_data = new float[8 * Atlas.Count]; var iAtlas = 0; @@ -2270,14 +2246,44 @@ private void GenerateWorldMesh(int detail, string path) { iAtlas += 8; } - // Generate optimized landscape mesh - float minX = (float)MapMinX * 8192.0f; - float maxX = (float)(MapMaxX + 1) * 8192.0f; - float minY = (float)MapMinY * 8192.0f; - float maxY = (float)(MapMaxY + 1) * 8192.0f; + // Ensure previous landscape data is erased + if (File.Exists(path)) { + File.Delete(path); + } - backgroundWorker.ReportProgress(10, strings["LandTessellating"]); - NativeMethods.TessellateLandscapeAtlased(path, height_data, (uint)DataSpanX, (uint)DataSpanY, atlas_data, (uint)Atlas.Count, minX, minY, maxX, maxY, tolerance); + // Generate optimized landscape mesh + foreach (var r in Atlas) { + // Produce atlas region heightmap array + int RegionSpanX = r.MaxX - r.MinX + 1; + int RegionSpanY = r.MaxY - r.MinY + 1; + int DataSpanX = RegionSpanX * 64; + int DataSpanY = RegionSpanY * 64; + var height_data = new float[DataSpanX * DataSpanY]; + + for (int y1 = r.MinY; y1 <= r.MaxY; y1++) { + for (int y2 = 0; y2 < 64; y2++) { + for (int x1 = r.MinX; x1 <= r.MaxX; x1++) { + for (int x2 = 0; x2 < 64; x2++) { + int y = (y1 - r.MinY) * 64 + y2; + int x = (x1 - r.MinX) * 64 + x2; + if (LandMap[x1, y1] != null) { + height_data[y * DataSpanX + x] = (float)LandMap[x1, y1].Heights[x2, y2] * 8.0f; + } else { + height_data[y * DataSpanX + x] = -2048.0f; + } + } + } + } + } + + float minX = (float)r.MinX * 8192.0f; + float maxX = (float)(r.MaxX + 1) * 8192.0f; + float minY = (float)r.MinY * 8192.0f; + float maxY = (float)(r.MaxY + 1) * 8192.0f; + + backgroundWorker.ReportProgress(10, strings["LandTessellating"]); + NativeMethods.TessellateLandscapeAtlased(path, height_data, (uint)DataSpanX, (uint)DataSpanY, atlas_data, (uint)Atlas.Count, minX, minY, maxX, maxY, tolerance); + } } /* Statics tab properties */