using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Rendering;
using XFEEDToolBox.Rendering;
using static Vortice.Direct3D11.D3D11;
static void Require(bool condition,string text){if(!condition)throw new Exception(text);}
Require(Marshal.SizeOf<GalaxyBlackHoleInstance>()==52,"Actual source instance must remain52B");
Require(GalaxyOriginalBlackHole.Payload.Length==181248&&GalaxyOriginalBlackHole.Mips.Count==10,"Exact source texture must be complete");
Require(GalaxyOriginalBlackHole.IsSpecial(41)&&GalaxyOriginalBlackHole.IsSpecial((ushort)(42|18<<10))&&!GalaxyOriginalBlackHole.IsSpecial(40),"Source types must not be guessed from public labels");
Require(GalaxyOriginalBlackHole.HalfExtent(.7f)==(float)(Half).7f&&GalaxyOriginalBlackHole.HalfExtent(.00001f)<.001f&&
GalaxyOriginalBlackHole.HalfExtent(0)==0&&GalaxyOriginalBlackHole.HalfExtent(float.NaN)==0,"Original half conversion must have no positive size floor");
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 rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);
const int width=480,height=300;var reports=new List<object>();var maximumDifference=0f;
var output=Path.GetFullPath("artifacts/galaxy-black-hole-shader-validation");Directory.CreateDirectory(output);
foreach(var (view,distance,yaw,pitch,position) in new[]{("near",6d,0d,0d,new Vector3(0,0,6)),
("oblique",100d,.3,.45,new Vector3(1,2,3)),("far",800d,0d,0d,new Vector3(0,0,64))})
foreach(var dpi in new[]{1,2})foreach(var destinationAlpha in new[]{0f,1f})foreach(var write in new[]{1f,1f/256})
{
var camera=GalaxyCamera.Create(new(0,0,0),width,height,yaw,pitch,GalaxyOriginalProjection.FocalLength(width,height)/distance);
using var texture=device.CreateTexture2D(Format.R32G32B32A32_Float,(uint)(width*dpi),(uint)(height*dpi),mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
var projected=camera.ProjectForCatalogue(new(position.X,position.Y,position.Z));
Require(projected.IsVisible,"Explicit fixture must lie in catalogue envelope");
var star=new GalaxyStar(new((float)projected.X,(float)projected.Y),1,0,Vector4.One,new(position,13),.7f,OriginalBlackHole:true);
var clear=new Color4(.04f,.08f,.12f,destinationAlpha);
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width*dpi,height*dpi));context.ClearRenderTargetView(target,clear);
renderer.Draw([star],camera,true,true,write);var actual=Read(texture);
context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,clear);renderer.DrawOriginalDxbc(camera,write);var original=Read(texture);
float maximum=0;double total=0;var changed=0;var nonfinite=0;var negative=0;
for(var i=0;i<actual.Length;i++)
{
if(!float.IsFinite(actual[i])||!float.IsFinite(original[i])){nonfinite++;continue;}
var delta=Math.Abs(actual[i]-original[i]);maximum=Math.Max(maximum,delta);total+=delta;
var channel=i%4;var initial=channel switch{0=>clear.R,1=>clear.G,2=>clear.B,_=>clear.A};
if(Math.Abs(original[i]-initial)>1e-7)changed++;
if(original[i]<0)negative++;
}
Require(nonfinite==0&&total/actual.Length<.0001&&maximum<.05f,$"Original BlackHole DXBC mismatch {view}/dpi{dpi}/alpha{destinationAlpha}/write{write}: max={maximum},mean={total/actual.Length}");
maximumDifference=Math.Max(maximumDifference,maximum);
reports.Add(new{view,dpi,destinationAlpha,write,sourceInstances=renderer.OriginalBlackHolesDrawn,sourceWorldHalfSize=(float)(Half).7f,
projectedHalfSize=.7*camera.FocalLength/projected.Depth,maximumDifference=maximum,meanDifference=total/actual.Length,changedChannels=changed,negativeChannels=negative,nonfinite});
if(dpi==1)
{
var cut=$"{view}-destination-alpha{destinationAlpha}-write{(write==1?"1":"1over256")}";
File.WriteAllBytes(Path.Combine(output,cut+".r32"),MemoryMarshal.AsBytes(actual.AsSpan()).ToArray());
var image=new byte[width*height*4];
for(var i=0;i<actual.Length;i+=4){image[i]=(byte)(Math.Clamp(actual[i+2],0,1)*255);image[i+1]=(byte)(Math.Clamp(actual[i+1],0,1)*255);image[i+2]=(byte)(Math.Clamp(actual[i],0,1)*255);image[i+3]=255;}
File.WriteAllBytes(Path.Combine(output,cut+".bgra"),image);
}
}
var checkCamera=GalaxyCamera.Create(new(0,0,0),width,height,0,0,4);
var checkPosition=checkCamera.Focus;var fixture=new GalaxyStar(new(width/2,height/2),1,0,Vector4.One,new((float)checkPosition.X,(float)checkPosition.Y,(float)checkPosition.Z,13),.7f,OriginalBlackHole:true);
using(var texture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget))
using(var target=device.CreateRenderTargetView(texture))
{
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width,height));
// Kind0 is the general ShowMarkers=false path; it must not suppress this
// original NavigationMarkers-enabled source material.
renderer.Draw([fixture with{Kind=0}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==1,"ShowMarkers=false/ShowRoute=true must retain actual blackhole");
renderer.Draw([fixture with{Kind=3}],checkCamera,true,false,1);Require(renderer.OriginalBlackHolesDrawn==0,"ShowMarkers=true/ShowRoute=false must not submit source blackhole");
renderer.Draw([fixture],checkCamera,false,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Classified views keep their ordinary source sprite");
renderer.Draw([fixture with{OriginalBlackHole=false}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"No original classification receipt cannot claim special shader");
renderer.Draw([fixture with{OriginalSize=0}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Zero original size cannot be resurrected");
renderer.Draw([fixture with{Colour=Vector4.Zero}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Zero source alpha cannot be resurrected");
var forcedPosition=new Vector3(0,0,(float)(checkCamera.Distance*5));
Require(!checkCamera.ProjectForCatalogue(new(0,0,forcedPosition.Z)).IsVisible&&checkCamera.Project(new(0,0,forcedPosition.Z)).IsVisible,"Fixture must distinguish source projection and fallback query boundary");
renderer.Draw([fixture with{World=new(forcedPosition,13)}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==1,"Already retained whole-cell/D50 input must not be re-cut by reconstructed4D lens");
}
var report=new{cases=reports.Count,passed=reports.Count,failed=0,actualOriginalVsAndPs=true,
vertexShaderSha256=GalaxyOriginalBlackHole.VertexShaderSha256,pixelShaderSha256=GalaxyOriginalBlackHole.PixelShaderSha256,
textureSha256=GalaxyOriginalBlackHole.PayloadSha256,blend="Actual named publisher RGB+alpha: SourceAlpha/One/Add (overrides authored FGM destination7)",branchChecks=12,maximumDifference,
gameProcessAccess=false,gameCalls=0,fullGameScenePass=false,
limits=new[]{"Default runtime Glow and named-publisher blend overrides are explicit.","Scene order and runtime alternate material selector are not a full scene parity claim."},reports};
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(report,new JsonSerializerOptions{WriteIndented=true}));
Console.WriteLine(JsonSerializer.Serialize(new{report.cases,report.failed,report.branchChecks,report.maximumDifference}));
float[] Read(ID3D11Texture2D texture)
{
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());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 values=new float[desc.Width*desc.Height*4];
try{for(var y=0;y<desc.Height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),values,(int)(y*desc.Width*4),(int)desc.Width*4);}
finally{context.Unmap(staging,0);}return values;
}
namespace XFEEDToolBox.Rendering
{
internal readonly record struct GalaxyStar(Vector2 Position,float Radius,float Kind,Vector4 Colour,Vector4 World=default,float OriginalSize=0,bool PowerTerritorySize=false,int OriginalSprite=13,Vector4? OriginalColour=null,bool OriginalBlackHole=false);
internal sealed partial class GalaxyGraphics:IDisposable
{
private readonly ID3D11Device device;private readonly ID3D11DeviceContext context;private readonly ID3D11SamplerState sampler;
private const int StarCapacity=65536;public int DrawCalls {get;private set;}
private readonly ID3D11VertexShader sourceVs;private readonly ID3D11PixelShader sourcePs;private readonly ID3D11InputLayout sourceLayout;
private readonly ID3D11Buffer sourceVertices,sourceCamera,sourceShared,sourceMaterial;
internal GalaxyGraphics(ID3D11Device device,ID3D11DeviceContext context)
{
this.device=device;this.context=context;sampler=device.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Clamp,TextureAddressMode.Clamp,TextureAddressMode.Clamp));
InitializeOriginalBlackHoles(Path.GetFullPath("XFEEDToolBox/Assets/GalaxyBlackHole.hlsl"));
byte[] Load(string stage,string hash)
{var bytes=File.ReadAllBytes($"artifacts/galaxy-query-research/power-outer-sources/effects/{stage}_BackgroundBlackHole_Forward0_0_Win64_SM50.dxbc");if(Convert.ToHexStringLower(SHA256.HashData(bytes))!=hash)throw new InvalidDataException("Pinned original shader changed");return bytes;}
var vs=Load("vs",GalaxyOriginalBlackHole.VertexShaderSha256);sourceVs=device.CreateVertexShader(vs);sourcePs=device.CreatePixelShader(Load("ps",GalaxyOriginalBlackHole.PixelShaderSha256));
sourceLayout=device.CreateInputLayout([
new InputElementDescription("TEXCOORD",0,Format.R16G16B16A16_Float,0,0),
new InputElementDescription("POSITION",0,Format.R32G32B32_Float,0,1,InputClassification.PerInstanceData,1),
new InputElementDescription("POSITION",2,Format.R32G32B32A32_Float,12,1,InputClassification.PerInstanceData,1),
new InputElementDescription("TEXCOORD",3,Format.R16G16B16A16_Float,28,1,InputClassification.PerInstanceData,1),
new InputElementDescription("POSITION",4,Format.R32G32B32A32_Float,36,1,InputClassification.PerInstanceData,1)],vs);
Vector4[] corners=[new(0,1,-1,-1),new(0,0,-1,1),new(1,0,1,1),new(1,0,1,1),new(1,1,1,-1),new(0,1,-1,-1)];
var halves=corners.SelectMany(v=>new[]{(Half)v.X,(Half)v.Y,(Half)v.Z,(Half)v.W}).ToArray();sourceVertices=device.CreateBuffer<Half>(halves,BindFlags.VertexBuffer);
sourceCamera=device.CreateBuffer(8*16,BindFlags.ConstantBuffer);sourceShared=device.CreateBuffer(279*16,BindFlags.ConstantBuffer);sourceMaterial=device.CreateBuffer(16,BindFlags.ConstantBuffer);
}
internal void Draw(ReadOnlySpan<GalaxyStar> stars,GalaxyCamera camera,bool realistic,bool navigation,float write)=>DrawOriginalBlackHoles(stars,camera,realistic,navigation,write);
internal void DrawOriginalDxbc(GalaxyCamera camera,float write)
{
Vector3 V(Vector3d v)=>new((float)v.X,(float)v.Y,(float)v.Z);
var r=V(camera.Right);var up=V(camera.Up);var f=V(camera.Forward);var eye=new Vector3((float)camera.Eye.X,(float)camera.Eye.Y,(float)camera.Eye.Z);
Vector4 Row(Vector3 direction,float scale)=>new(direction*scale,-Vector3.Dot(eye,direction)*scale);
var projection=new Vector4[8];projection[4]=Row(r,(float)(camera.FocalLength/(camera.Width*.5)));projection[5]=Row(up,(float)(camera.FocalLength/(camera.Height*.5)));
projection[6]=new(0,0,0,(float)camera.Near);projection[7]=Row(f,1);
var shared=new Vector4[279];shared[90]=new(0,write,0,0);shared[277]=new(r,0);shared[278]=new(up,0);
var material=GalaxyOriginalBlackHole.Material();context.UpdateSubresource<Vector4>(projection,sourceCamera);context.UpdateSubresource<Vector4>(shared,sourceShared);context.UpdateSubresource(in material,sourceMaterial);
context.VSSetConstantBuffer(0,sourceCamera);context.VSSetConstantBuffer(1,sourceShared);context.VSSetConstantBuffer(2,sourceMaterial);
context.PSSetConstantBuffer(1,sourceShared);context.PSSetConstantBuffer(2,sourceMaterial);context.PSSetShaderResource(0,blackHoleView);context.PSSetSampler(0,sampler);
context.IASetInputLayout(sourceLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);context.IASetVertexBuffer(0,sourceVertices,8);context.IASetVertexBuffer(1,blackHoleBuffer,52);
context.VSSetShader(sourceVs);context.PSSetShader(sourcePs);context.OMSetBlendState(blackHoleBlend);context.DrawInstanced(6,(uint)OriginalBlackHolesDrawn,0,0);context.PSSetShaderResource(0,null!);
}
private unsafe void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> data)where T:unmanaged
{var map=context.Map(buffer,0,MapMode.WriteDiscard);try{MemoryMarshal.AsBytes(data).CopyTo(new Span<byte>((void*)map.DataPointer,data.Length*Marshal.SizeOf<T>()));}finally{context.Unmap(buffer,0);}}
public void Dispose(){DisposeOriginalBlackHoles();sampler.Dispose();sourceVs.Dispose();sourcePs.Dispose();sourceLayout.Dispose();sourceVertices.Dispose();sourceCamera.Dispose();sourceShared.Dispose();sourceMaterial.Dispose();}
}
}
using System.Numerics;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text.Json;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using XFEEDToolBox.Core.Galaxy;
using XFEEDToolBox.Core.Navigation;
using XFEEDToolBox.Core.Rendering;
using XFEEDToolBox.Rendering;
using static Vortice.Direct3D11.D3D11;
static void Require(bool condition,string text){if(!condition)throw new Exception(text);}
Require(Marshal.SizeOf<GalaxyBlackHoleInstance>()==52,"Actual source instance must remain52B");
Require(GalaxyOriginalBlackHole.Payload.Length==181248&&GalaxyOriginalBlackHole.Mips.Count==10,"Exact source texture must be complete");
Require(GalaxyOriginalBlackHole.IsSpecial(41)&&GalaxyOriginalBlackHole.IsSpecial((ushort)(42|18<<10))&&!GalaxyOriginalBlackHole.IsSpecial(40),"Source types must not be guessed from public labels");
Require(GalaxyOriginalBlackHole.HalfExtent(.7f)==(float)(Half).7f&&GalaxyOriginalBlackHole.HalfExtent(.00001f)<.001f&&
GalaxyOriginalBlackHole.HalfExtent(0)==0&&GalaxyOriginalBlackHole.HalfExtent(float.NaN)==0,"Original half conversion must have no positive size floor");
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 rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
using var noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);
const int width=480,height=300;var reports=new List<object>();var maximumDifference=0f;
var output=Path.GetFullPath("artifacts/galaxy-black-hole-shader-validation");Directory.CreateDirectory(output);
foreach(var (view,distance,yaw,pitch,position) in new[]{("near",6d,0d,0d,new Vector3(0,0,6)),
("oblique",100d,.3,.45,new Vector3(1,2,3)),("far",800d,0d,0d,new Vector3(0,0,64))})
foreach(var dpi in new[]{1,2})foreach(var destinationAlpha in new[]{0f,1f})foreach(var write in new[]{1f,1f/256})
{
var camera=GalaxyCamera.Create(new(0,0,0),width,height,yaw,pitch,GalaxyOriginalProjection.FocalLength(width,height)/distance);
using var texture=device.CreateTexture2D(Format.R32G32B32A32_Float,(uint)(width*dpi),(uint)(height*dpi),mipLevels:1,bindFlags:BindFlags.RenderTarget);
using var target=device.CreateRenderTargetView(texture);
var projected=camera.ProjectForCatalogue(new(position.X,position.Y,position.Z));
Require(projected.IsVisible,"Explicit fixture must lie in catalogue envelope");
var star=new GalaxyStar(new((float)projected.X,(float)projected.Y),1,0,Vector4.One,new(position,13),.7f,OriginalBlackHole:true);
var clear=new Color4(.04f,.08f,.12f,destinationAlpha);
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width*dpi,height*dpi));context.ClearRenderTargetView(target,clear);
renderer.Draw([star],camera,true,true,write);var actual=Read(texture);
context.OMSetRenderTargets(target);context.ClearRenderTargetView(target,clear);renderer.DrawOriginalDxbc(camera,write);var original=Read(texture);
float maximum=0;double total=0;var changed=0;var nonfinite=0;var negative=0;
for(var i=0;i<actual.Length;i++)
{
if(!float.IsFinite(actual[i])||!float.IsFinite(original[i])){nonfinite++;continue;}
var delta=Math.Abs(actual[i]-original[i]);maximum=Math.Max(maximum,delta);total+=delta;
var channel=i%4;var initial=channel switch{0=>clear.R,1=>clear.G,2=>clear.B,_=>clear.A};
if(Math.Abs(original[i]-initial)>1e-7)changed++;
if(original[i]<0)negative++;
}
Require(nonfinite==0&&total/actual.Length<.0001&&maximum<.05f,$"Original BlackHole DXBC mismatch {view}/dpi{dpi}/alpha{destinationAlpha}/write{write}: max={maximum},mean={total/actual.Length}");
maximumDifference=Math.Max(maximumDifference,maximum);
reports.Add(new{view,dpi,destinationAlpha,write,sourceInstances=renderer.OriginalBlackHolesDrawn,sourceWorldHalfSize=(float)(Half).7f,
projectedHalfSize=.7*camera.FocalLength/projected.Depth,maximumDifference=maximum,meanDifference=total/actual.Length,changedChannels=changed,negativeChannels=negative,nonfinite});
if(dpi==1)
{
var cut=$"{view}-destination-alpha{destinationAlpha}-write{(write==1?"1":"1over256")}";
File.WriteAllBytes(Path.Combine(output,cut+".r32"),MemoryMarshal.AsBytes(actual.AsSpan()).ToArray());
var image=new byte[width*height*4];
for(var i=0;i<actual.Length;i+=4){image[i]=(byte)(Math.Clamp(actual[i+2],0,1)*255);image[i+1]=(byte)(Math.Clamp(actual[i+1],0,1)*255);image[i+2]=(byte)(Math.Clamp(actual[i],0,1)*255);image[i+3]=255;}
File.WriteAllBytes(Path.Combine(output,cut+".bgra"),image);
}
}
var checkCamera=GalaxyCamera.Create(new(0,0,0),width,height,0,0,4);
var checkPosition=checkCamera.Focus;var fixture=new GalaxyStar(new(width/2,height/2),1,0,Vector4.One,new((float)checkPosition.X,(float)checkPosition.Y,(float)checkPosition.Z,13),.7f,OriginalBlackHole:true);
using(var texture=device.CreateTexture2D(Format.R32G32B32A32_Float,width,height,mipLevels:1,bindFlags:BindFlags.RenderTarget))
using(var target=device.CreateRenderTargetView(texture))
{
context.OMSetRenderTargets(target);context.RSSetViewport(new Viewport(width,height));
// Kind0 is the general ShowMarkers=false path; it must not suppress this
// original NavigationMarkers-enabled source material.
renderer.Draw([fixture with{Kind=0}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==1,"ShowMarkers=false/ShowRoute=true must retain actual blackhole");
renderer.Draw([fixture with{Kind=3}],checkCamera,true,false,1);Require(renderer.OriginalBlackHolesDrawn==0,"ShowMarkers=true/ShowRoute=false must not submit source blackhole");
renderer.Draw([fixture],checkCamera,false,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Classified views keep their ordinary source sprite");
renderer.Draw([fixture with{OriginalBlackHole=false}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"No original classification receipt cannot claim special shader");
renderer.Draw([fixture with{OriginalSize=0}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Zero original size cannot be resurrected");
renderer.Draw([fixture with{Colour=Vector4.Zero}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==0,"Zero source alpha cannot be resurrected");
var forcedPosition=new Vector3(0,0,(float)(checkCamera.Distance*5));
Require(!checkCamera.ProjectForCatalogue(new(0,0,forcedPosition.Z)).IsVisible&&checkCamera.Project(new(0,0,forcedPosition.Z)).IsVisible,"Fixture must distinguish source projection and fallback query boundary");
renderer.Draw([fixture with{World=new(forcedPosition,13)}],checkCamera,true,true,1);Require(renderer.OriginalBlackHolesDrawn==1,"Already retained whole-cell/D50 input must not be re-cut by reconstructed4D lens");
}
var report=new{cases=reports.Count,passed=reports.Count,failed=0,actualOriginalVsAndPs=true,
vertexShaderSha256=GalaxyOriginalBlackHole.VertexShaderSha256,pixelShaderSha256=GalaxyOriginalBlackHole.PixelShaderSha256,
textureSha256=GalaxyOriginalBlackHole.PayloadSha256,blend="Actual named publisher RGB+alpha: SourceAlpha/One/Add (overrides authored FGM destination7)",branchChecks=12,maximumDifference,
gameProcessAccess=false,gameCalls=0,fullGameScenePass=false,
limits=new[]{"Default runtime Glow and named-publisher blend overrides are explicit.","Scene order and runtime alternate material selector are not a full scene parity claim."},reports};
File.WriteAllText(Path.Combine(output,"report.json"),JsonSerializer.Serialize(report,new JsonSerializerOptions{WriteIndented=true}));
Console.WriteLine(JsonSerializer.Serialize(new{report.cases,report.failed,report.branchChecks,report.maximumDifference}));
float[] Read(ID3D11Texture2D texture)
{
context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());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 values=new float[desc.Width*desc.Height*4];
try{for(var y=0;y<desc.Height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),values,(int)(y*desc.Width*4),(int)desc.Width*4);}
finally{context.Unmap(staging,0);}return values;
}
namespace XFEEDToolBox.Rendering
{
internal readonly record struct GalaxyStar(Vector2 Position,float Radius,float Kind,Vector4 Colour,Vector4 World=default,float OriginalSize=0,bool PowerTerritorySize=false,int OriginalSprite=13,Vector4? OriginalColour=null,bool OriginalBlackHole=false);
internal sealed partial class GalaxyGraphics:IDisposable
{
private readonly ID3D11Device device;private readonly ID3D11DeviceContext context;private readonly ID3D11SamplerState sampler;
private const int StarCapacity=65536;public int DrawCalls {get;private set;}
private readonly ID3D11VertexShader sourceVs;private readonly ID3D11PixelShader sourcePs;private readonly ID3D11InputLayout sourceLayout;
private readonly ID3D11Buffer sourceVertices,sourceCamera,sourceShared,sourceMaterial;
internal GalaxyGraphics(ID3D11Device device,ID3D11DeviceContext context)
{
this.device=device;this.context=context;sampler=device.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Clamp,TextureAddressMode.Clamp,TextureAddressMode.Clamp));
InitializeOriginalBlackHoles(Path.GetFullPath("XFEEDToolBox/Assets/GalaxyBlackHole.hlsl"));
byte[] Load(string stage,string hash)
{var bytes=File.ReadAllBytes($"artifacts/galaxy-query-research/power-outer-sources/effects/{stage}_BackgroundBlackHole_Forward0_0_Win64_SM50.dxbc");if(Convert.ToHexStringLower(SHA256.HashData(bytes))!=hash)throw new InvalidDataException("Pinned original shader changed");return bytes;}
var vs=Load("vs",GalaxyOriginalBlackHole.VertexShaderSha256);sourceVs=device.CreateVertexShader(vs);sourcePs=device.CreatePixelShader(Load("ps",GalaxyOriginalBlackHole.PixelShaderSha256));
sourceLayout=device.CreateInputLayout([
new InputElementDescription("TEXCOORD",0,Format.R16G16B16A16_Float,0,0),
new InputElementDescription("POSITION",0,Format.R32G32B32_Float,0,1,InputClassification.PerInstanceData,1),
new InputElementDescription("POSITION",2,Format.R32G32B32A32_Float,12,1,InputClassification.PerInstanceData,1),
new InputElementDescription("TEXCOORD",3,Format.R16G16B16A16_Float,28,1,InputClassification.PerInstanceData,1),
new InputElementDescription("POSITION",4,Format.R32G32B32A32_Float,36,1,InputClassification.PerInstanceData,1)],vs);
Vector4[] corners=[new(0,1,-1,-1),new(0,0,-1,1),new(1,0,1,1),new(1,0,1,1),new(1,1,1,-1),new(0,1,-1,-1)];
var halves=corners.SelectMany(v=>new[]{(Half)v.X,(Half)v.Y,(Half)v.Z,(Half)v.W}).ToArray();sourceVertices=device.CreateBuffer<Half>(halves,BindFlags.VertexBuffer);
sourceCamera=device.CreateBuffer(8*16,BindFlags.ConstantBuffer);sourceShared=device.CreateBuffer(279*16,BindFlags.ConstantBuffer);sourceMaterial=device.CreateBuffer(16,BindFlags.ConstantBuffer);
}
internal void Draw(ReadOnlySpan<GalaxyStar> stars,GalaxyCamera camera,bool realistic,bool navigation,float write)=>DrawOriginalBlackHoles(stars,camera,realistic,navigation,write);
internal void DrawOriginalDxbc(GalaxyCamera camera,float write)
{
Vector3 V(Vector3d v)=>new((float)v.X,(float)v.Y,(float)v.Z);
var r=V(camera.Right);var up=V(camera.Up);var f=V(camera.Forward);var eye=new Vector3((float)camera.Eye.X,(float)camera.Eye.Y,(float)camera.Eye.Z);
Vector4 Row(Vector3 direction,float scale)=>new(direction*scale,-Vector3.Dot(eye,direction)*scale);
var projection=new Vector4[8];projection[4]=Row(r,(float)(camera.FocalLength/(camera.Width*.5)));projection[5]=Row(up,(float)(camera.FocalLength/(camera.Height*.5)));
projection[6]=new(0,0,0,(float)camera.Near);projection[7]=Row(f,1);
var shared=new Vector4[279];shared[90]=new(0,write,0,0);shared[277]=new(r,0);shared[278]=new(up,0);
var material=GalaxyOriginalBlackHole.Material();context.UpdateSubresource<Vector4>(projection,sourceCamera);context.UpdateSubresource<Vector4>(shared,sourceShared);context.UpdateSubresource(in material,sourceMaterial);
context.VSSetConstantBuffer(0,sourceCamera);context.VSSetConstantBuffer(1,sourceShared);context.VSSetConstantBuffer(2,sourceMaterial);
context.PSSetConstantBuffer(1,sourceShared);context.PSSetConstantBuffer(2,sourceMaterial);context.PSSetShaderResource(0,blackHoleView);context.PSSetSampler(0,sampler);
context.IASetInputLayout(sourceLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);context.IASetVertexBuffer(0,sourceVertices,8);context.IASetVertexBuffer(1,blackHoleBuffer,52);
context.VSSetShader(sourceVs);context.PSSetShader(sourcePs);context.OMSetBlendState(blackHoleBlend);context.DrawInstanced(6,(uint)OriginalBlackHolesDrawn,0,0);context.PSSetShaderResource(0,null!);
}
private unsafe void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> data)where T:unmanaged
{var map=context.Map(buffer,0,MapMode.WriteDiscard);try{MemoryMarshal.AsBytes(data).CopyTo(new Span<byte>((void*)map.DataPointer,data.Length*Marshal.SizeOf<T>()));}finally{context.Unmap(buffer,0);}}
public void Dispose(){DisposeOriginalBlackHoles();sampler.Dispose();sourceVs.Dispose();sourcePs.Dispose();sourceLayout.Dispose();sourceVertices.Dispose();sourceCamera.Dispose();sourceShared.Dispose();sourceMaterial.Dispose();}
}
}