Editor/TerrainLineTool.Guide.cs
using System;
using Sandbox;
namespace TerrainLines;
public sealed partial class TerrainLineTool
{
internal Vector3 GuidePoint( Terrain terrain, Vector3 point )
{
point.z = _edit is { IsCurrent: true } ? _edit.SampleHeight( point.x, point.y ) : LineRaster.SampleHeight( terrain.Storage, point.x, point.y );
return point + Vector3.Up * (2 / terrain.WorldScale.x);
}
private void DrawGuide( Terrain terrain, bool hasHit, Vector3 hit )
{
using var scope = Gizmo.Scope( "terrain-lines" );
Gizmo.Transform = terrain.WorldTransform;
Gizmo.Draw.IgnoreDepth = true;
Gizmo.Draw.Color = Color.Cyan;
Gizmo.Draw.LineThickness = 2;
for ( int i = 1; i < _path.Count; i++ ) DrawSurfaceLine( terrain, _path[i - 1], _path[i] );
if ( !hasHit || _editingPoints ) return;
float halfWidth = Math.Max( 1, Settings.PathWidth ) * 0.5f / terrain.WorldScale.x;
DrawSurfaceCircle( terrain, hit, halfWidth );
DrawSurfaceCircle( terrain, hit, halfWidth + Math.Max( 0, Settings.ShoulderWidth ) / terrain.WorldScale.x );
if ( _points.Count > 0 && (!_drawing || _straightGesture) ) DrawSurfaceLine( terrain, _points[^1], hit );
}
private void DrawSurfaceLine( Terrain terrain, Vector3 a, Vector3 b )
{
float spacing = terrain.Storage.TerrainSize / terrain.Storage.Resolution;
int count = Math.Max( 1, (int)MathF.Ceiling( LineRaster.Distance2D( a, b ) / spacing ) );
var previous = GuidePoint( terrain, a );
for ( int i = 1; i <= count; i++ )
{
var point = GuidePoint( terrain, a + (b - a) * ((float)i / count) );
Gizmo.Draw.Line( previous, point );
previous = point;
}
}
private void DrawSurfaceCircle( Terrain terrain, Vector3 center, float radius )
{
var previous = GuidePoint( terrain, center + new Vector3( radius, 0, 0 ) );
for ( int i = 1; i <= 64; i++ )
{
float angle = i * MathF.PI / 32;
var point = GuidePoint( terrain, center + new Vector3( MathF.Cos( angle ) * radius, MathF.Sin( angle ) * radius, 0 ) );
Gizmo.Draw.Line( previous, point );
previous = point;
}
}
private void UpdatePointEditing( Terrain terrain, bool hasHit, Vector3 hit )
{
using var scope = Gizmo.Scope( "terrain-line-points" );
Gizmo.Transform = terrain.WorldTransform;
Gizmo.Draw.IgnoreDepth = true;
for ( int i = 0; i < _points.Count; i++ )
{
using var pointScope = Gizmo.Scope( $"point-{i}" );
var point = GuidePoint( terrain, _points[i] );
float size = Math.Max( 2, Gizmo.Camera.Position.Distance( terrain.WorldTransform.PointToWorld( point ) ) * 0.004f ) / terrain.WorldScale.x;
Gizmo.Hitbox.DepthBias = 0.01f;
Gizmo.Hitbox.Sphere( new Sphere( point, size * 2 ) );
if ( Gizmo.Pressed.This )
{
if ( _movingPoint < 0 ) { BeginGesture( terrain ); _movingPoint = i; }
if ( _movingPoint == i && hasHit ) MovePoint( i, hit );
}
else if ( _movingPoint == i )
{
EndGesture( "Move terrain line point" );
_movingPoint = -1;
}
Gizmo.Draw.Color = Gizmo.IsHovered ? Color.Yellow : Color.Cyan;
Gizmo.Draw.SolidSphere( point, size );
}
}
}