XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
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();
    }
}