Editor/TerrainShapes/Volcanic.cs
using Editor;
using Sandbox;
using Sandbox.UI;
using System;

namespace Sturnus.TerrainGenerationTool;
public static class Volcanic
{
	public static float Default(
		int x,
		int y,
		int width,
		int height,
		long seed,
		float minHeight,
		bool warp,
		float warpSize,
		float warpStrength
	)
	{
		Random random = new Random( (int)(seed & 0xFFFFFFFF) );
		float nx = (x / (float)width) * 2 - 1; // Normalize x to range [-1, 1]
		float ny = (y / (float)height) * 2 - 1; // Normalize y to range [-1, 1]

		float craterRadius = 0.3f;        // Average radius of the central crater
		float rimHeight = 0.25f;          // Height of the crater rim
		float rimWidth = 0f;           // Width of the rim
		float outerSlopeStrength = 0.5f;  // Strength of the gradient for the exterior slope
		float innerSlopeStrength = 2.0f;  // Strength of the gradient for the interior slope
		float baseHeight = 0.1f;          // Minimum base height
		float noiseStrength = 0.02f; // General noise strength
		float distance = MathF.Sqrt( nx * nx + ny * ny );

		// Calculate distance from the center of the heightmap
		float centerX = 0f, centerY = 0f; // Center of the heightmap
		float distanceToCenter = MathF.Sqrt( (nx - centerX) * (nx - centerX) + (ny - centerY) * (ny - centerY) );

		// Apply domain warping for irregularity
		if ( warp )
		{
			float warpX = OpenSimplex2S.Noise2( seed + 10, nx * warpSize, ny * warpSize ) * warpStrength;
			float warpY = OpenSimplex2S.Noise2( seed + 11, nx * warpSize, ny * warpSize ) * warpStrength;
			nx += warpX;
			ny += warpY;
		}

		// Introduce irregularity to the crater radius
		float craterIrregularity = OpenSimplex2S.Noise2( seed + 20, nx * 4.0f, ny * 4.0f ) * 0.1f;
		float dynamicCraterRadius = craterRadius + craterIrregularity;

		// Initialize height components
		float crater = 0f;
		float rim = 0f;
		float outerSlope = 0f;

		// Crater: Smooth inward slope towards the center of the crater
		if ( distanceToCenter < dynamicCraterRadius )
		{
			float craterDepth = (1f - (distanceToCenter));
			crater = MathF.Pow( craterDepth, innerSlopeStrength ) ; // Inward slope
		}

		// Rim: Uneven ridge around the crater
		if ( distanceToCenter >= dynamicCraterRadius && distanceToCenter < dynamicCraterRadius + rimWidth )
		{
			float rimFalloff = (distanceToCenter - dynamicCraterRadius) / rimWidth;
			float rimNoise = OpenSimplex2S.Noise2( seed + 30, nx * 8.0f, ny * 8.0f ) * noiseStrength;
			rim = (1f - rimFalloff) * rimHeight + rimNoise; // Add noise for unevenness
		}

		// Outer slope: Smooth gradient with noise towards the edges
		if ( distanceToCenter >= dynamicCraterRadius + rimWidth )
		{
			float slopeDistance = 1f - distanceToCenter; // Decrease height as we approach the edge
			float slopeNoise = OpenSimplex2S.Noise2( seed + 40, nx * 4.0f, ny * 4.0f ) * noiseStrength;
			outerSlope = MathF.Max( 0, slopeDistance ) * outerSlopeStrength + slopeNoise;
		}

		// Combine components
		float heightValue = baseHeight + crater + rim + outerSlope;

		// Smooth transition towards the crater center for a more natural look
		if ( distanceToCenter < dynamicCraterRadius )
		{
			float centerFalloff = MathF.Pow( 1f - (distanceToCenter / dynamicCraterRadius), 2f );
			heightValue = centerFalloff * baseHeight; // Slight bump for a smoother slope
		}


		heightValue = Math.Max( heightValue, baseHeight );

		var heightValueBase = Math.Max( heightValue, minHeight );

		// Clamp the final height
		return Math.Clamp( heightValueBase, 0, 1 );
	}

}