From e9657dc22d65328b07b16c48f147c611cc3ea361 Mon Sep 17 00:00:00 2001 From: Victor Giers Date: Sat, 2 May 2026 04:11:58 +0200 Subject: [PATCH] Add support for applying terrain foliage mask patches --- .../apply-terrain-brush-patch-command.ts | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/src/commands/apply-terrain-brush-patch-command.ts b/src/commands/apply-terrain-brush-patch-command.ts index 6cd9b91a..8b6d6c3a 100644 --- a/src/commands/apply-terrain-brush-patch-command.ts +++ b/src/commands/apply-terrain-brush-patch-command.ts @@ -5,6 +5,8 @@ import type { TerrainSampleValuePatch } from "../core/terrain-brush"; import { + getOrCreateTerrainFoliageMask, + isTerrainFoliageMaskEmpty, markTerrainRenderSamplesDirty, TERRAIN_LAYER_COUNT, updateTerrainBoundsCacheAfterHeightPatch, @@ -46,7 +48,11 @@ function assertValidPatchEntry( } export function isTerrainBrushPatchEmpty(patch: TerrainBrushPatch): boolean { - return patch.heightSamples.length === 0 && patch.paintWeights.length === 0; + return ( + patch.heightSamples.length === 0 && + patch.paintWeights.length === 0 && + patch.foliageMaskValues.length === 0 + ); } function mergeTerrainSampleIndexIntoBounds( @@ -80,7 +86,10 @@ export function createApplyTerrainBrushPatchCommand( const patch: TerrainBrushPatch = { terrainId: options.patch.terrainId, heightSamples: options.patch.heightSamples.map((entry) => ({ ...entry })), - paintWeights: options.patch.paintWeights.map((entry) => ({ ...entry })) + paintWeights: options.patch.paintWeights.map((entry) => ({ ...entry })), + foliageMaskValues: options.patch.foliageMaskValues.map((entry) => ({ + ...entry + })) }; let previousSelection: EditorSelection | null = null; let previousToolMode: ToolMode | null = null; @@ -132,6 +141,32 @@ export function createApplyTerrainBrushPatchCommand( ); } + for (const entry of patch.foliageMaskValues) { + if (currentDocument.foliageLayers[entry.layerId] === undefined) { + throw new Error( + `Foliage layer ${entry.layerId} does not exist for terrain mask patch.` + ); + } + + const mask = getOrCreateTerrainFoliageMask(terrain, entry.layerId); + assertValidPatchEntry( + entry, + mask.values.length, + "Terrain foliage mask" + ); + mask.values[entry.index] = + direction === "forward" ? entry.after : entry.before; + renderDirtyBounds = mergeTerrainSampleIndexIntoBounds( + renderDirtyBounds, + terrain, + entry.index + ); + + if (isTerrainFoliageMaskEmpty(mask)) { + delete terrain.foliageMasks[entry.layerId]; + } + } + markTerrainRenderSamplesDirty(terrain, renderDirtyBounds); context.setDocument({