Code/FoliageRenderer.cs
using System;
using System.Text.Json.Serialization;
using Sandbox.Engine.Settings;
namespace Foliage;
public class FoliageRenderer : Component, Component.ExecuteInEditor
{
public List<FoliageSceneObject> Renderers { get; set; } = new();
[Property,Hide] Dictionary<int,List<Transform>> FoliageRenderers { get; set; } = new();
[Property] private int ChunkSize { get; set; } = 512;
[Property] OptionsWidget Options { get; set; }
public void PaintFoliage(FoliageResource foliage, Transform transform)
{
if ( FoliageRenderers.TryGetValue(foliage.ResourceId, out var renderer) )
{
renderer.Add( transform );
UpdateRenderers();
}
else
{
FoliageRenderers.Add( foliage.ResourceId, new List<Transform> { transform } );
FoliageRenderers[foliage.ResourceId].Add( transform );
UpdateRenderers();
}
}
public void EraseFoliage( Vector3 position,float size, int id )
{
List<Transform> toRemove = new();
if ( id != 0 )
{
foreach ( var testPos in FoliageRenderers[id] )
{
if ( testPos.Position.DistanceSquared( position ) <= size * size )
{
toRemove.Add( testPos );
}
}
foreach ( var remove in toRemove )
{
FoliageRenderers[id].Remove( remove );
}
return;
}
foreach ( var testVal in FoliageRenderers )
{
foreach ( var testPos in testVal.Value )
{
if ( testPos.Position.DistanceSquared( position ) <= size * size )
{
toRemove.Add( testPos );
}
}
foreach ( var remove in toRemove )
{
testVal.Value.Remove( remove );
}
}
}
protected override void OnStart()
{
UpdateRenderers();
}
protected override void OnEnabled()
{
base.OnEnabled();
UpdateRenderers();
}
protected override void OnDestroy()
{
foreach ( var val in Renderers )
{
val.Delete();
}
base.OnDestroy();
}
protected override void OnDisabled()
{
foreach ( var val in Renderers )
{
val.Delete();
}
base.OnDisabled();
}
public void UpdateRenderers()
{
foreach ( var val in Renderers )
{
val.Delete();
}
Renderers.Clear();
foreach ( var folRenderer in FoliageRenderers )
{
var transformMins = new Vector3( 0 );
var transformMaxs = new Vector3( 0 );
foreach ( var testTrans in folRenderer.Value )
{
transformMins = Vector3.Min( transformMins, testTrans.Position );
transformMaxs = Vector3.Max( transformMaxs, testTrans.Position );
}
var transformSize = transformMaxs - transformMins;
var transformArray = folRenderer.Value.ToArray();
var folInstance = ResourceLibrary.Get<FoliageResource>( folRenderer.Key );
for ( int x = 0; x < (transformSize.x / ChunkSize).CeilToInt(); x++ )
{
for ( int y = 0; y < (transformSize.y / ChunkSize).CeilToInt(); y++ )
{
List<Transform> newTransforms = new();
var transformedMins = transformMins + new Vector3( (x * ChunkSize)+ChunkSize, (y * ChunkSize)+ChunkSize, 10000 );
var testBBox = new BBox( transformMins+ new Vector3( x * ChunkSize, y * ChunkSize, -500 ),transformedMins );
foreach ( var testTrans in folRenderer.Value )
{
if ( testBBox.Contains( testTrans.Position ) )
{
newTransforms.Add( testTrans );
}
}
if ( newTransforms.Count <= 0 )
{
continue;
}
var renderModelLargestAxis = folInstance.Model.Bounds.Size;
var boundsMin = Vector3.Zero;
var boundsMax = Vector3.Zero;
for ( int i = 0; i < newTransforms.Count; i++ )
{
boundsMin = Vector3.Min( boundsMin, newTransforms[i].Position);
boundsMax = Vector3.Max( boundsMax, newTransforms[i].Position);
}
var folSceneObject = new FoliageSceneObject( GameObject.Scene.SceneWorld, folInstance.Model )
{
Bounds = new BBox( boundsMin-renderModelLargestAxis,boundsMax+renderModelLargestAxis ),
Transforms = newTransforms.ToArray()
};
folSceneObject.Flags.CastShadows = true;
Renderers.Add( folSceneObject );
}
}
}
}
public void ClearAll()
{
foreach ( var val in FoliageRenderers )
{
val.Value.Clear();
}
UpdateRenderers();
}
public class OptionsWidget { }
}
public class FoliageSceneObject : SceneCustomObject
{
public Model RenderModel;
public Transform[] Transforms = Array.Empty<Transform>();
public FoliageSceneObject(SceneWorld sceneWorld, Model renderModel) : base(sceneWorld)
{
RenderModel = renderModel;
}
public void AddTransform(Transform transform)
{
//Transforms.Add( transform );
}
public override void RenderSceneObject()
{
base.RenderSceneObject();
Graphics.DrawModelInstanced( RenderModel, Transforms.AsSpan() );
}
}