using System.Numerics; using System.Runtime.InteropServices; using Vortice.D3DCompiler; using Vortice.Direct3D; using Vortice.Direct3D11; using Vortice.DXGI; using XFEEDToolBox.Core.Galaxy; using XFEEDToolBox.Core.Rendering; namespace XFEEDToolBox.Rendering; internal sealed partial class GalaxyGraphics { private ID3D11VertexShader powerActivityRingVs=null!; private ID3D11PixelShader powerActivityRingPs=null!; private ID3D11InputLayout powerActivityRingLayout=null!; private ID3D11Buffer powerActivityRingInstance=null!,powerActivityRingConstants=null!; private ID3D11BlendState powerActivityRingBlend=null!; private GalaxyOriginalPowerActivityRing? powerActivityRing; private float? powerActivityRingEmissive; private bool powerActivityRingDefaultKnown; private bool powerActivityRingInvalidSource; internal int PreparedPowerActivityRings=>powerActivityRing is null?0:1; internal int SubmittedPowerActivityRings {get;private set;} internal bool PowerActivityRingSourceUnknown=>powerActivityRing is not null&&(powerActivityRingInvalidSource||powerActivityRingEmissive is null&&!OriginalExposureReady); internal bool PowerActivityRingSourceDefaultKnown=>powerActivityRing is not null&&(powerActivityRingDefaultKnown|| !powerActivityRingInvalidSource&&powerActivityRingEmissive is null&&OriginalExposureState==GalaxyOriginalExposureState.DefaultCreated); internal bool PowerActivityRingUsesToolManualExposure=>powerActivityRing is not null&&!powerActivityRingInvalidSource&&powerActivityRingEmissive is null&&OriginalExposureIsToolManual; internal bool OriginalPowerActivityRingGeometryRestored=>true; internal bool OriginalPowerActivityRingFullRestored=>false; // No guessed unity exposure in production. A source-space probe may pass // an explicitly labelled synthetic scalar; unknown runtime input hides it. internal void SetOriginalPowerActivityRing(GalaxyOriginalPowerActivityRing? ring,float? emissiveRescaling,bool originalDefaultBoundKnown=false) { powerActivityRing=ring is{} value&&GalaxyOriginalPowerActivityRingGeometry.IsValid(value)?value:null; // The flag means the original six-texel zero resource is actually // created/bound and ready in this view. Static bytes alone are not a // runtime readiness signal. Explicit invalid inputs remain unknown. powerActivityRingDefaultKnown=originalDefaultBoundKnown&&emissiveRescaling is null; powerActivityRingEmissive=powerActivityRingDefaultKnown?0:emissiveRescaling is{} scalar&&float.IsFinite(scalar)&&scalar>=0?scalar:null; powerActivityRingInvalidSource=emissiveRescaling is{} supplied&&(!float.IsFinite(supplied)||supplied<0); SubmittedPowerActivityRings=0; } private void InitializeOriginalPowerActivityRing(string shader) { if(Marshal.SizeOf()!=64)throw new InvalidDataException("原活动范围实例格式无效。"); var path=Path.Combine(Path.GetDirectoryName(shader)!,"GalaxyPowerActivityRing.hlsl"); var vs=Compiler.CompileFromFile(path,"VSOriginalPowerActivityRing","vs_5_0");powerActivityRingVs=device.CreateVertexShader(vs.Span); powerActivityRingPs=device.CreatePixelShader(Compiler.CompileFromFile(path,"PSOriginalPowerActivityRing","ps_5_0").Span); powerActivityRingLayout=device.CreateInputLayout([ new InputElementDescription("POSITION",0,Format.R32G32B32A32_Float,0,0,InputClassification.PerInstanceData,1), new InputElementDescription("UAXISINNER",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1), new InputElementDescription("VAXISOUTER",0,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1), new InputElementDescription("USERDATA",0,Format.R32G32B32A32_Float,48,0,InputClassification.PerInstanceData,1)],vs.Span); powerActivityRingInstance=device.CreateBuffer(64,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write); powerActivityRingConstants=device.CreateBuffer(96,BindFlags.ConstantBuffer); // Actual FocusRing kind5 effect bytecode:One/InverseSourceAlpha/Add. // Original range record's source alpha0 makes the RGB additive. powerActivityRingBlend=device.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha)); } private void DrawOriginalPowerActivityRing(GalaxyCamera camera,float hdrWrite) { SubmittedPowerActivityRings=0; if(powerActivityRing is not{} ring||powerActivityRingInvalidSource)return; var useTexture=powerActivityRingEmissive is null&&OriginalExposureReady; if(powerActivityRingEmissive is null&&!useTexture)return; var emissive=powerActivityRingEmissive??OriginalManualExposureResult?.Type2EmissiveRescaling??0; if(emissive==0&&ring.Colour.W==0)return; if(!float.IsFinite(hdrWrite)||hdrWrite<=0)return; var eye=camera.Eye;var right=camera.Right;var up=camera.Up;var forward=camera.Forward; var frame=new PowerActivityRingCamera(new((float)eye.X,(float)eye.Y,(float)eye.Z,(float)camera.FocalLength), new((float)right.X,(float)right.Y,(float)right.Z,(float)camera.Width),new((float)up.X,(float)up.Y,(float)up.Z,(float)camera.Height), new((float)forward.X,(float)forward.Y,(float)forward.Z,(float)camera.Near), new(GalaxyOriginalPowerActivityRingGeometry.QuadCount,GalaxyOriginalPowerActivityRingGeometry.RadialFeather,GalaxyOriginalPowerActivityRingGeometry.SegmentFeather,GalaxyOriginalPowerActivityRingGeometry.SolidRatio), new(GalaxyOriginalPowerActivityRingGeometry.SegmentCount,emissive,hdrWrite,useTexture?1:0)); Upload(powerActivityRingInstance,new[]{ring});context.UpdateSubresource(in frame,powerActivityRingConstants); context.VSSetConstantBuffer(11,powerActivityRingConstants);context.PSSetConstantBuffer(11,powerActivityRingConstants); context.IASetInputLayout(powerActivityRingLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleStrip); context.IASetVertexBuffer(0,powerActivityRingInstance,64);context.VSSetShader(powerActivityRingVs);context.PSSetShader(powerActivityRingPs); context.PSSetShaderResource(20,useTexture?originalExposureView!:null!); context.OMSetBlendState(powerActivityRingBlend);context.DrawInstanced(GalaxyOriginalPowerActivityRingGeometry.VertexCount,1,0,0); context.PSSetShaderResource(20,null!); DrawCalls++;SubmittedPowerActivityRings=1; } private void DisposeOriginalPowerActivityRing() { powerActivityRingVs.Dispose();powerActivityRingPs.Dispose();powerActivityRingLayout.Dispose(); powerActivityRingInstance.Dispose();powerActivityRingConstants.Dispose();powerActivityRingBlend.Dispose(); } [StructLayout(LayoutKind.Sequential)] private readonly record struct PowerActivityRingCamera(Vector4 EyeFocal,Vector4 RightWidth,Vector4 UpHeight,Vector4 ForwardNear,Vector4 Material,Vector4 Output); }