using System.Numerics;
using System.Runtime.InteropServices;
using Vortice.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using XFEEDToolBox.Core.Rendering;
namespace XFEEDToolBox.Rendering;
[StructLayout(LayoutKind.Sequential)]
internal readonly record struct GalaxyPowerContour(Vector3 Centre,float Radius,Vector4 LinearColour);
internal sealed partial class GalaxyGraphics
{
private const int PowerContourCapacity=4096;
private readonly GalaxyPowerContour[] powerContours=new GalaxyPowerContour[PowerContourCapacity];
private ID3D11VertexShader powerContoursVs=null!;
private ID3D11PixelShader powerContoursPs=null!;
private ID3D11InputLayout powerContoursLayout=null!;
private ID3D11Buffer powerContoursBuffer=null!;
private ID3D11Texture2D powerGlowTexture=null!;
private ID3D11ShaderResourceView powerGlowView=null!;
private int powerContourCount;
internal int SubmittedPowerContours=>powerContourCount;
internal bool PowerContoursDrawn {get;private set;}
// 3A27E60 -> 3C056F0 -> SimpleBillboardGlow: actual32B records,
// camera-axis quad and original BC4 mask. Original prepared-frame fade,
// shared RGB multiplier and final HDR output remain separate work.
internal bool OriginalPowerTerritoryBillboardRestored=>true;
internal bool OriginalPowerTerritoryFillRestored=>false;
internal void SetPowerContours(ReadOnlySpan<GalaxyPowerContour> contours)
{
powerContourCount=0;
foreach(var contour in contours)
{
if(powerContourCount==PowerContourCapacity)break;
if(!float.IsFinite(contour.Centre.X)||!float.IsFinite(contour.Centre.Y)||!float.IsFinite(contour.Centre.Z)||
!float.IsFinite(contour.Radius)||contour.Radius<=0||contour.Radius>1_000_000||
!float.IsFinite(contour.LinearColour.X)||!float.IsFinite(contour.LinearColour.Y)||!float.IsFinite(contour.LinearColour.Z)||
!float.IsFinite(contour.LinearColour.W)||contour.LinearColour.W<=0||contour.LinearColour.W>1)continue;
powerContours[powerContourCount++]=contour;
}
}
private void InitializePowerContours(string shader)
{
var vertex=Compiler.CompileFromFile(shader,"VSPowerContour","vs_5_0");
powerContoursVs=device.CreateVertexShader(vertex.Span);
powerContoursPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSPowerContour","ps_5_0").Span);
powerContoursLayout=device.CreateInputLayout([
new InputElementDescription("POSITION",0,Format.R32G32B32A32_Float,0,0,InputClassification.PerInstanceData,1),
new InputElementDescription("COLOR",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1)],vertex.Span);
powerContoursBuffer=device.CreateBuffer(PowerContourCapacity*32,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
var source=GalaxyOriginalTerritoryGlow.Reference;
if(!MemoryMarshal.TryGetArray(source.Payload,out ArraySegment<byte> payload)||payload.Array is null)
throw new InvalidDataException("原势力区域辉光缓冲区不可用。");
var pin=GCHandle.Alloc(payload.Array,GCHandleType.Pinned);
try
{
var slices=source.Mips.Select(m=>new SubresourceData(pin.AddrOfPinnedObject()+payload.Offset+m.Offset,(uint)m.RowPitch,(uint)m.DepthPitch)).ToArray();
powerGlowTexture=device.CreateTexture2D(new Texture2DDescription{Width=GalaxyOriginalTerritoryGlow.Width,Height=GalaxyOriginalTerritoryGlow.Height,
ArraySize=1,MipLevels=GalaxyOriginalTerritoryGlow.MipCount,Format=Format.BC4_UNorm,SampleDescription=new(1,0),
Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource},slices);
powerGlowView=device.CreateShaderResourceView(powerGlowTexture);
}
finally{pin.Free();}
}
private void DrawPowerContours()
{
PowerContoursDrawn=false;if(powerContourCount==0)return;
Upload<GalaxyPowerContour>(powerContoursBuffer,powerContours.AsSpan(0,powerContourCount));
context.IASetInputLayout(powerContoursLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
context.IASetVertexBuffer(0,powerContoursBuffer,32);context.VSSetShader(powerContoursVs);context.PSSetShader(powerContoursPs);
context.PSSetShaderResource(8,powerGlowView);context.PSSetSampler(0,sampler);
context.DrawInstanced(6,(uint)powerContourCount,0,0);context.PSSetShaderResource(8,null!);DrawCalls++;PowerContoursDrawn=true;
}
private void DisposePowerContours()
{
powerContoursVs.Dispose();powerContoursPs.Dispose();powerContoursLayout.Dispose();powerContoursBuffer.Dispose();
powerGlowView.Dispose();powerGlowTexture.Dispose();
}
}
using System.Numerics;
using System.Runtime.InteropServices;
using Vortice.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using XFEEDToolBox.Core.Rendering;
namespace XFEEDToolBox.Rendering;
[StructLayout(LayoutKind.Sequential)]
internal readonly record struct GalaxyPowerContour(Vector3 Centre,float Radius,Vector4 LinearColour);
internal sealed partial class GalaxyGraphics
{
private const int PowerContourCapacity=4096;
private readonly GalaxyPowerContour[] powerContours=new GalaxyPowerContour[PowerContourCapacity];
private ID3D11VertexShader powerContoursVs=null!;
private ID3D11PixelShader powerContoursPs=null!;
private ID3D11InputLayout powerContoursLayout=null!;
private ID3D11Buffer powerContoursBuffer=null!;
private ID3D11Texture2D powerGlowTexture=null!;
private ID3D11ShaderResourceView powerGlowView=null!;
private int powerContourCount;
internal int SubmittedPowerContours=>powerContourCount;
internal bool PowerContoursDrawn {get;private set;}
// 3A27E60 -> 3C056F0 -> SimpleBillboardGlow: actual32B records,
// camera-axis quad and original BC4 mask. Original prepared-frame fade,
// shared RGB multiplier and final HDR output remain separate work.
internal bool OriginalPowerTerritoryBillboardRestored=>true;
internal bool OriginalPowerTerritoryFillRestored=>false;
internal void SetPowerContours(ReadOnlySpan<GalaxyPowerContour> contours)
{
powerContourCount=0;
foreach(var contour in contours)
{
if(powerContourCount==PowerContourCapacity)break;
if(!float.IsFinite(contour.Centre.X)||!float.IsFinite(contour.Centre.Y)||!float.IsFinite(contour.Centre.Z)||
!float.IsFinite(contour.Radius)||contour.Radius<=0||contour.Radius>1_000_000||
!float.IsFinite(contour.LinearColour.X)||!float.IsFinite(contour.LinearColour.Y)||!float.IsFinite(contour.LinearColour.Z)||
!float.IsFinite(contour.LinearColour.W)||contour.LinearColour.W<=0||contour.LinearColour.W>1)continue;
powerContours[powerContourCount++]=contour;
}
}
private void InitializePowerContours(string shader)
{
var vertex=Compiler.CompileFromFile(shader,"VSPowerContour","vs_5_0");
powerContoursVs=device.CreateVertexShader(vertex.Span);
powerContoursPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSPowerContour","ps_5_0").Span);
powerContoursLayout=device.CreateInputLayout([
new InputElementDescription("POSITION",0,Format.R32G32B32A32_Float,0,0,InputClassification.PerInstanceData,1),
new InputElementDescription("COLOR",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1)],vertex.Span);
powerContoursBuffer=device.CreateBuffer(PowerContourCapacity*32,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
var source=GalaxyOriginalTerritoryGlow.Reference;
if(!MemoryMarshal.TryGetArray(source.Payload,out ArraySegment<byte> payload)||payload.Array is null)
throw new InvalidDataException("原势力区域辉光缓冲区不可用。");
var pin=GCHandle.Alloc(payload.Array,GCHandleType.Pinned);
try
{
var slices=source.Mips.Select(m=>new SubresourceData(pin.AddrOfPinnedObject()+payload.Offset+m.Offset,(uint)m.RowPitch,(uint)m.DepthPitch)).ToArray();
powerGlowTexture=device.CreateTexture2D(new Texture2DDescription{Width=GalaxyOriginalTerritoryGlow.Width,Height=GalaxyOriginalTerritoryGlow.Height,
ArraySize=1,MipLevels=GalaxyOriginalTerritoryGlow.MipCount,Format=Format.BC4_UNorm,SampleDescription=new(1,0),
Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource},slices);
powerGlowView=device.CreateShaderResourceView(powerGlowTexture);
}
finally{pin.Free();}
}
private void DrawPowerContours()
{
PowerContoursDrawn=false;if(powerContourCount==0)return;
Upload<GalaxyPowerContour>(powerContoursBuffer,powerContours.AsSpan(0,powerContourCount));
context.IASetInputLayout(powerContoursLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
context.IASetVertexBuffer(0,powerContoursBuffer,32);context.VSSetShader(powerContoursVs);context.PSSetShader(powerContoursPs);
context.PSSetShaderResource(8,powerGlowView);context.PSSetSampler(0,sampler);
context.DrawInstanced(6,(uint)powerContourCount,0,0);context.PSSetShaderResource(8,null!);DrawCalls++;PowerContoursDrawn=true;
}
private void DisposePowerContours()
{
powerContoursVs.Dispose();powerContoursPs.Dispose();powerContoursLayout.Dispose();powerContoursBuffer.Dispose();
powerGlowView.Dispose();powerGlowTexture.Dispose();
}
}