Code/Stamping/StampComponent.cs
using System;
using Sandbox;

namespace Sandbox.Stamping;

public class StampComponent : Component
{
	[Property, Group( "Setup" )] public Texture HeightmapTexture { get; set; }
	[Property, Group( "Setup" )] public Terrain Terrain { get; set; }

	[Property, Group( "Height" ), Range( 0f, 1f )] public float HeightScale { get; set; } = 1f;
	[Property, Group( "Height" ), Range( 0f, 1f )] public float HeightOffset { get; set; } = 0f;

	[Property, Group( "Smoothing" ), Range( 0, 20 )] public int SmoothIterations { get; set; } = 5;
	[Property, Group( "Smoothing" ), Range( 1, 8 )]  public int SmoothRadius { get; set; } = 1;

	[Button]
	public void LoadHeightmap()
	{
		if ( Terrain?.Storage == null ) { Log.Warning( "No terrain" ); return; }
		if ( HeightmapTexture == null ) { Log.Warning( "No texture" ); return; }
		
		var storage = Terrain.Storage;
		int res = storage.Resolution;
		var pixels = HeightmapTexture.GetPixels();

		if ( pixels == null ) { Log.Warning( "No pixels" ); return; }

		Log.Info( $"Loading heightmap {HeightmapTexture.Width}x{HeightmapTexture.Height} -> terrain {res}x{res}" );

		// Write heights
		for ( int y = 0; y < res; y++ )
		{
			for ( int x = 0; x < res; x++ )
			{
				int px = (int)((float)x / res * HeightmapTexture.Width);
				int py = (int)((float)y / res * HeightmapTexture.Height);

				var c = pixels[py * HeightmapTexture.Width + px];
				float luminance = (c.r * 0.299f + c.g * 0.587f + c.b * 0.114f) / 255f;
				float height = Math.Clamp( luminance * HeightScale + HeightOffset, 0f, 1f );

				storage.HeightMap[y * res + x] = (ushort)(height * ushort.MaxValue);
			}
		}

		// Smooth pass
		for ( int iter = 0; iter < SmoothIterations; iter++ )
		{
			for ( int y = SmoothRadius; y < res - SmoothRadius; y++ )
			{
				for ( int x = SmoothRadius; x < res - SmoothRadius; x++ )
				{
					float sum = 0f;
					int count = 0;

					for ( int ky = -SmoothRadius; ky <= SmoothRadius; ky++ )
					{
						for ( int kx = -SmoothRadius; kx <= SmoothRadius; kx++ )
						{
							sum += storage.HeightMap[(y + ky) * res + (x + kx)];
							count++;
						}
					}

					storage.HeightMap[y * res + x] = (ushort)(sum / count);
				}
			}
		}

		Terrain.SyncGPUTexture();
		Log.Info( "Heightmap loaded successfully" );
	}

	[Button]
	public void ClearHeightmap()
	{
		if ( Terrain?.Storage == null ) { Log.Warning( "No terrain" ); return; }

		var storage = Terrain.Storage;
		for ( int i = 0; i < storage.HeightMap.Length; i++ )
			storage.HeightMap[i] = 0;

		Terrain.SyncGPUTexture();
		Log.Info( "Heightmap cleared" );
	}
}