qstbak/Auspex/Auspex/LightRenderer.cs
2026-08-17 20:25:32 +10:00

104 lines
3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Auspex.Lighting.Internal;
using Auspex.Vfx.Internal;
namespace Auspex;
public sealed class LightRenderer : IDisposable
{
private static readonly Dictionary<AxLightType, string> LightTypeNames = Enum.GetValues<AxLightType>().ToDictionary((AxLightType v) => v, (AxLightType v) => v.ToString());
private FrameLifetimeTracker<NativeLightHandle> trackedLights;
public LightRenderer()
{
trackedLights = new FrameLifetimeTracker<NativeLightHandle>();
}
public static Vector3 LinearToGameHDR(Vector3 linearRgb)
{
linearRgb *= 4f;
return linearRgb * linearRgb;
}
public static Vector3 GameHDRToLinear(Vector3 gameHdr)
{
return Vector3.SquareRoot(gameHdr) / 4f;
}
public void AddDirectionalLight(string id, Vector3 position, AxLightConfig? config = null)
{
ArgumentNullException.ThrowIfNull((object)id, "id");
CreateOrUpdateLight(id, AxLightType.Directional, position, config ?? AxLightConfig.Default);
}
public void AddPointLight(string id, Vector3 position, AxLightConfig? config = null)
{
ArgumentNullException.ThrowIfNull((object)id, "id");
CreateOrUpdateLight(id, AxLightType.PointLight, position, config ?? AxLightConfig.Default);
}
public void AddSpotLight(string id, Vector3 position, AxLightConfig? config = null)
{
ArgumentNullException.ThrowIfNull((object)id, "id");
CreateOrUpdateLight(id, AxLightType.SpotLight, position, config ?? AxLightConfig.Default);
}
public void AddAreaLight(string id, Vector3 position, AxLightConfig? config = null)
{
ArgumentNullException.ThrowIfNull((object)id, "id");
CreateOrUpdateLight(id, AxLightType.AreaLight, position, config ?? AxLightConfig.Default);
}
private void CreateOrUpdateLight(string id, AxLightType lightType, Vector3 position, AxLightConfig config)
{
(string, string) key = (id, LightTypeNames[lightType]);
if (trackedLights.IsTouched(key))
{
return;
}
if (trackedLights.TryTouchExisting(key, out NativeLightHandle o))
{
o.UpdatePosition(position);
if (config.Rotation.HasValue)
{
o.UpdateRotation(config.Rotation.Value);
}
o.UpdateColor(config.Color);
o.UpdateIntensity(config.Intensity);
o.UpdateRange(config.Range);
o.UpdateAngles(config.LightAngle, config.FalloffAngle);
o.UpdateFlags(config.Flags);
o.UpdateFalloff(config.FalloffType, config.FalloffPower);
o.UpdateShadow(config.ShadowNear, config.ShadowFar, config.CharaShadowRange);
}
else
{
trackedLights.TouchNew(key, NativeLightHandle.Create(position, lightType, config));
}
}
public bool RemoveLight(string id, AxLightType lightType)
{
ArgumentNullException.ThrowIfNull((object)id, "id");
return trackedLights.Remove((id, LightTypeNames[lightType]));
}
internal void Update()
{
trackedLights.Update();
trackedLights.ForEachActive(delegate(NativeLightHandle light)
{
light.Tick();
});
}
public void Dispose()
{
trackedLights.Dispose();
GC.SuppressFinalize(this);
}
}