Files
2026-07-13 13:15:05 +08:00

172 lines
5.2 KiB
C#

using System.Runtime.InteropServices;
using SharpDX;
using SharpDX.Direct3D11;
using T3.Core.Logging;
using T3.Core.Resource;
namespace T3.Core.Rendering;
[StructLayout(LayoutKind.Explicit, Size = 3 * 16)]
public struct PointLight
{
public PointLight(System.Numerics.Vector3 position, float intensity, System.Numerics.Vector4 color, float range, float decay =2)
{
Position = position;
Intensity = intensity;
Color = color;
Range = range;
Decay = decay;
}
[FieldOffset(0)]
public System.Numerics.Vector3 Position;
[FieldOffset(3*4)]
public float Intensity;
[FieldOffset(4*4)]
public System.Numerics.Vector4 Color;
[FieldOffset(8*4)]
public float Range;
[FieldOffset(9*4)]
public float Decay;
}
public class PointLightStack
{
public const int MaxPointLights = 8;
public Buffer ConstBuffer
{
get
{
if (_currentSize == 0)
{
return GetDefaultBuffer();
}
if (_isConstBufferDirty)
{
UpdateConstBuffer(ref _pointLights, ref _constBuffer , _currentSize);
_isConstBufferDirty = false;
}
return _constBuffer;
}
}
public void Clear()
{
_currentSize = 0;
_isConstBufferDirty = true;
}
public bool Push(PointLight pointLight)
{
if (_currentSize == MaxPointLights)
{
Log.Warning($"Trying to push a new point light, but limit {MaxPointLights} reached");
return false;
}
_pointLights[_currentSize++] = pointLight;
_isConstBufferDirty = true;
return true;
}
public void Pop()
{
if (_currentSize > 0)
{
_currentSize--;
_isConstBufferDirty = true;
}
}
private static void UpdateConstBuffer(ref PointLight[] pointLights, ref Buffer constBuffer, int activeLightCount)
{
var size = Marshal.SizeOf<PointLight>() * MaxPointLights + 16;
using (var data = new DataStream(size, true, true))
{
foreach (var light in pointLights)
{
data.Write(light);
}
data.Write(activeLightCount);
data.Position = 0;
if (constBuffer == null)
{
var bufferDesc = new BufferDescription
{
Usage = ResourceUsage.Default,
SizeInBytes = size,
BindFlags = BindFlags.ConstantBuffer
};
constBuffer = new Buffer(ResourceManager.Device, data, bufferDesc) { DebugName = "PointLightsConstBuffer" };
}
else
{
ResourceManager.Device.ImmediateContext.UpdateSubresource(new DataBox(data.DataPointer, 0, 0), constBuffer, 0);
}
}
}
private Buffer GetDefaultBuffer()
{
if (_defaultConstBuffer == null)
{
_defaultPointLights[0] = new PointLight
{
Position = new Vector3(8,20,3),
Intensity = 4,
Color = new System.Numerics.Vector4(1,0.93f,0.95f,1),
Range = 1,
Decay = 2
};
_defaultPointLights[1] = new PointLight
{
Position = new Vector3(-8,-20,-8),
Intensity = 3f,
Color = new System.Numerics.Vector4(0.97f,0.96f,1,1),
Range = 1,
Decay = 2,
};
UpdateConstBuffer(ref _defaultPointLights, ref _defaultConstBuffer, 2);
}
return _defaultConstBuffer;
}
public int Count => _currentSize > 0 ? _currentSize : 2;
public PointLight GetPointLight(int index)
{
var useDefaultLights = _currentSize == 0;
if (index >= Count)
{
Log.Warning($"Requested light index {index} exceed current count of {Count}");
index = Count - 1;
}
return useDefaultLights
? _defaultPointLights[index]
: _pointLights[index];
}
private PointLight[] _pointLights = new PointLight[MaxPointLights];
private int _currentSize = 0;
private bool _isConstBufferDirty = true;
private Buffer _constBuffer = null;
private static PointLight[] _defaultPointLights = new PointLight[MaxPointLights];
private static Buffer _defaultConstBuffer;
}