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 System.Text.Json;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Rendering;
using XFEEDToolBox.Rendering;
using static Vortice.Direct3D11.D3D11;

const int width=1600,height=900;
D3D11CreateDevice(IntPtr.Zero,DriverType.Warp,DeviceCreationFlags.BgraSupport,[FeatureLevel.Level_11_0],out var device,out _,out var context).CheckError();
using var d=device;using var c=context;using var renderer=new GalaxyGraphics(device,context);
using var texture=device.CreateTexture2D(Format.B8G8R8A8_UNorm,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
using var rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width,height));context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);
var output=Path.GetFullPath("artifacts/galaxy-trade-shader-validation");Directory.CreateDirectory(output);var reports=new List<object>();
var flows=Enumerable.Range(0,13).Select(i=>
{
    var from=new GalacticSystem("Synthetic from",new(-8,(i-6)*1.5,0),9007199254740993+i,"G");
    var to=new GalacticSystem("Synthetic to",new(8,(i-6)*1.5,2),9007199254741993+i,"G");
    return new GalaxyCurrentTradeRenderFlow(new(from.SystemAddress!.Value,to.SystemAddress!.Value,i,.025f+i*.05f,[]),from,to);
}).ToArray();
renderer.SetCurrentTradeFlows(flows);
foreach(var (name,yaw,pitch,scale) in new[]{("front",0d,0d,20d),("tilted",.3,.4,16d),("oblique",-.5,-.3,25d)})
{
    var camera=GalaxyCamera.Create(new(0,0,0),width,height,yaw,pitch,scale);
    renderer.Prepare(camera);
    foreach(var hotspot in new[]{false,true})
    {
        context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.DrawPort(hotspot);var port=Read();
        context.ClearRenderTargetView(target,new Color4(0,0,0,1));renderer.DrawOriginal(camera,hotspot);var original=Read();
        var key=name+(hotspot?"-hotspots":"-routes");File.WriteAllBytes(Path.Combine(output,key+".bgra"),port);File.WriteAllBytes(Path.Combine(output,key+"-original.bgra"),original);
        long difference=0;var divergent=0;var lit=0;
        for(var i=0;i<port.Length;i+=4)
        {
            var delta=0;for(var channel=0;channel<3;channel++)delta=Math.Max(delta,Math.Abs(port[i+channel]-original[i+channel]));
            difference+=delta;if(delta>3)divergent++;
            if(Math.Max(port[i],Math.Max(port[i+1],port[i+2]))>3)lit++;
        }
        var mean=difference/(double)(width*height);
        reports.Add(new{key,meanDifference=mean,divergentPixels=divergent,litPixels=lit,renderer.SubmittedCurrentTradeRoutes,renderer.SubmittedCurrentTradeHotspots,
            controlledNormalScale=2,controlledNormalOffset=-1,controlledSharedMultiplier=1,originalBlend="SourceAlpha/One/Add",fullParity=false});
        if(mean>.5||divergent>width*height*.01||lit<20)
        {
            File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(reports,new JsonSerializerOptions{WriteIndented=true}));
            throw new InvalidOperationException($"Trade shader diverged from original DXBC: {key},mean{mean},pixels{divergent},lit{lit}.");
        }
    }
}
renderer.SetCurrentTradeFlows([]);renderer.Prepare(GalaxyCamera.Create(new(0,0,0),width,height,0,0,20));
if(renderer.SubmittedCurrentTradeRoutes!=0||renderer.SubmittedCurrentTradeHotspots!=0||renderer.HasOriginalCurrentTradeAnimation)throw new InvalidOperationException("Disabled current route buffer remained active.");
reports.Add(new{disabledClear=true,gameProcessAccess=false,syntheticCoordinatesAndFlows=true});
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(reports,new JsonSerializerOptions{WriteIndented=true}));Console.WriteLine(JsonSerializer.Serialize(reports));

byte[] Read()
{
    var desc=texture.Description;desc.BindFlags=BindFlags.None;desc.CPUAccessFlags=CpuAccessFlags.Read;desc.Usage=ResourceUsage.Staging;
    using var staging=device.CreateTexture2D(desc);context.CopyResource(staging,texture);var mapped=context.Map(staging,0,MapMode.Read);var bytes=new byte[width*height*4];
    for(var y=0;y<height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),bytes,y*width*4,width*4);context.Unmap(staging,0);return bytes;
}

namespace XFEEDToolBox.Rendering
{
    internal sealed partial class GalaxyGraphics:IDisposable
    {
        private readonly ID3D11Device device;private readonly ID3D11DeviceContext context;private readonly ID3D11SamplerState sampler;private readonly ID3D11BlendState additive;
        internal int DrawCalls;
        private readonly ID3D11VertexShader originalRouteVs,originalHotspotVs;
        private readonly ID3D11PixelShader originalRoutePs,originalHotspotPs;
        private readonly ID3D11Buffer originalB0,originalB1,originalRouteB2,originalHotspotB2;
        internal GalaxyGraphics(ID3D11Device d,ID3D11DeviceContext c)
        {
            device=d;context=c;sampler=d.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Wrap,TextureAddressMode.Wrap,TextureAddressMode.Wrap));additive=d.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha));
            InitializeOriginalCurrentTrade(Path.GetFullPath("XFEEDToolBox/Assets/GalaxyMap.hlsl"));
            var folder="artifacts/galaxy-query-research/current-trade/effects/";
            originalRouteVs=d.CreateVertexShader(File.ReadAllBytes(folder+"vs_RouteInstances_Forward0_0_Win64_SM50.dxbc"));originalRoutePs=d.CreatePixelShader(File.ReadAllBytes(folder+"ps_RouteInstances_Forward0_0_Win64_SM50.dxbc"));
            originalHotspotVs=d.CreateVertexShader(File.ReadAllBytes(folder+"vs_RouteHotspotInstances_Forward0_0_Win64_SM50.dxbc"));originalHotspotPs=d.CreatePixelShader(File.ReadAllBytes(folder+"ps_RouteHotspotInstances_Forward0_0_Win64_SM50.dxbc"));
            originalB0=d.CreateBuffer(128,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);originalB1=d.CreateBuffer(280*16,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
            originalRouteB2=d.CreateBuffer(96,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);originalHotspotB2=d.CreateBuffer(80,BindFlags.ConstantBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
        }
        internal void Prepare(GalaxyCamera camera)
        {
            currentTradeTimers0=new(.21f,.37f,.53f,.79f);currentTradeTimers1=new(.31f,.47f,.63f,.83f);currentTradeLastFrame=0;
            DrawOriginalCurrentTrade(camera);
        }
        internal void DrawPort(bool hotspot)
        {
            context.VSSetConstantBuffer(5,currentTradeConstants);context.PSSetConstantBuffer(5,currentTradeConstants);
            context.IASetInputLayout(currentTradeLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);context.OMSetBlendState(currentTradeBlend);
            context.IASetVertexBuffer(0,hotspot?currentTradeHotspotMesh:currentTradeRouteMesh,8);context.IASetVertexBuffer(1,hotspot?currentTradeHotspotBuffer!:currentTradeRouteBuffer!,44);
            context.IASetIndexBuffer(hotspot?currentTradeHotspotIndices:currentTradeRouteIndices,Format.R16_UInt,0);
            context.VSSetShader(hotspot?currentTradeHotspotVs:currentTradeRouteVs);context.PSSetShader(hotspot?currentTradeHotspotPs:currentTradeRoutePs);
            context.PSSetShaderResource(13,currentTradeRouteView);context.PSSetShaderResource(14,currentTradeTrailView);context.PSSetShaderResource(15,currentTradeHotspotView);context.PSSetSampler(0,currentTradeSampler);
            context.DrawIndexedInstanced(hotspot?6u:192u,(uint)(hotspot?SubmittedCurrentTradeHotspots:SubmittedCurrentTradeRoutes),0,0,0);
        }
        internal void DrawOriginal(GalaxyCamera camera,bool hotspot)
        {
            var eye=new Vector3((float)(camera.Eye.X+49985),(float)(camera.Eye.Y+40985),(float)(camera.Eye.Z+24105));
            var right=new Vector3((float)camera.Right.X,(float)camera.Right.Y,(float)camera.Right.Z);var up=new Vector3((float)camera.Up.X,(float)camera.Up.Y,(float)camera.Up.Z);var forward=new Vector3((float)camera.Forward.X,(float)camera.Forward.Y,(float)camera.Forward.Z);
            var x=right*(float)(camera.FocalLength*2/camera.Width);var y=up*(float)(camera.FocalLength*2/camera.Height);
            Vector4[] projection=[new(0,0,0,2),new(0,0,0,-1),default,default,new(x,-Vector3.Dot(x,eye)),new(y,-Vector3.Dot(y,eye)),new(0,0,0,(float)camera.Near),new(forward,-Vector3.Dot(forward,eye))];
            var globals=new Vector4[280];globals[90]=new(0,1,0,0);globals[277]=new(right,0);globals[278]=new(up,0);globals[279]=new(forward,0);
            Upload<Vector4>(originalB0,projection);Upload<Vector4>(originalB1,globals);
            if(hotspot)Upload<Vector4>(originalHotspotB2,[new(2,1,1,.25f),new(.75f,3,2,1),currentTradeTimers0,currentTradeTimers1,new(.65f,0,0,0)]);
            else Upload<Vector4>(originalRouteB2,[new(5,1,1,.25f),new(.75f,3,2,1),new(4,0,0,0),currentTradeTimers0,currentTradeTimers1,new(1,0,0,0)]);
            context.VSSetConstantBuffer(0,originalB0);context.VSSetConstantBuffer(1,originalB1);context.PSSetConstantBuffer(1,originalB1);context.VSSetConstantBuffer(2,hotspot?originalHotspotB2:originalRouteB2);context.PSSetConstantBuffer(2,hotspot?originalHotspotB2:originalRouteB2);
            context.PSSetShaderResource(0,hotspot?currentTradeHotspotView:currentTradeRouteView);context.PSSetShaderResource(1,currentTradeTrailView);
            context.VSSetShader(hotspot?originalHotspotVs:originalRouteVs);context.PSSetShader(hotspot?originalHotspotPs:originalRoutePs);
            context.DrawIndexedInstanced(hotspot?6u:192u,(uint)(hotspot?SubmittedCurrentTradeHotspots:SubmittedCurrentTradeRoutes),0,0,0);
        }
        private unsafe void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> data) where T:unmanaged
        {var mapped=context.Map(buffer,0,MapMode.WriteDiscard);try{MemoryMarshal.AsBytes(data).CopyTo(new Span<byte>((void*)mapped.DataPointer,data.Length*Marshal.SizeOf<T>()));}finally{context.Unmap(buffer,0);}}
        public void Dispose(){DisposeOriginalCurrentTrade();sampler.Dispose();additive.Dispose();originalRouteVs.Dispose();originalRoutePs.Dispose();originalHotspotVs.Dispose();originalHotspotPs.Dispose();originalB0.Dispose();originalB1.Dispose();originalRouteB2.Dispose();originalHotspotB2.Dispose();}
    }
}