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 Microsoft.UI.Composition;
using Vortice.D3DCompiler;
using Vortice.Direct3D;
using Vortice.Direct3D11;
using Vortice.DXGI;
using Vortice.Mathematics;
using Vortice.WinUI.Composition;
using XFEEDToolBox.Core.Rendering;
using XFEEDToolBox.Core.Galaxy;
using static Vortice.Direct3D11.D3D11;

namespace XFEEDToolBox.Rendering;

[StructLayout(LayoutKind.Sequential)]
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);
[StructLayout(LayoutKind.Sequential)]
internal readonly record struct GalaxyStellarSprite(Vector2 Position,float Radius,float Kind,Vector4 Colour,Vector4 Appearance);
[StructLayout(LayoutKind.Sequential)]
internal readonly record struct GalaxyLineVertex(Vector2 Position,float Distance,float Dashed,Vector4 Colour);

/// <summary>One instanced star draw and one line draw, independent of the number of retained XAML/Composition nodes.</summary>
internal sealed partial class GalaxyGraphics : IDisposable
{
    private readonly ID3D11Device device;
    private readonly ID3D11DeviceContext context;
    private readonly ID3D11Buffer starBuffer,lineBuffer,constants;
    private readonly ID3D11VertexShader starsVs,linesVs,skyVs,overviewVs;
    private readonly ID3D11PixelShader starsPs,linesPs,skyPs,overviewPs,inspectSkyPs;
    private readonly ID3D11InputLayout starsLayout,linesLayout;
    private readonly ID3D11BlendState additive;
    private readonly ID3D11SamplerState sampler;
    private readonly ID3D11RasterizerState rasterizer;
    private readonly ID3D11DepthStencilState noDepth;
    private readonly CompositionGraphicsDevice compositionDevice;
    private readonly ICompositionDrawingSurfaceInterop interop;
    private readonly BeginDraw beginDraw;
    private readonly ResizeDraw resizeDraw;
    private ID3D11Texture2D? pixels,skyTexture;
    private ID3D11RenderTargetView? target;
    private ID3D11ShaderResourceView? sky;
    private ID3D11Texture2D? densityTexture;
    private ID3D11ShaderResourceView? density;
    private GalaxyDensityMap? densityMap;
    private int width,height;
    private long nextSkyCheck;
    private readonly GalaxyStellarSprite[] stellarSprites=new GalaxyStellarSprite[StarCapacity];
    public CompositionDrawingSurface Surface { get; }
    public const int StarCapacity=65536,LineVertexCapacity=52000;
    public long Frames { get; private set; }
    public int DrawCalls { get; private set; }
    internal bool UnresolvedStarBackgroundEnabled {get;private set;}
    public string SkyboxSource { get; private set; }="";
    public GalaxyDensityMap? Overview=>densityMap;
    internal (int Width,int Height,byte[] Pixels) ReadPixels()
    {
        if(pixels is null)throw new InvalidOperationException("星图尚未绘制。");
        var description=pixels.Description;description.BindFlags=BindFlags.None;description.CPUAccessFlags=CpuAccessFlags.Read;
        description.Usage=ResourceUsage.Staging;description.MiscFlags=ResourceOptionFlags.None;
        using var staging=device.CreateTexture2D(description);context.CopyResource(staging,pixels);
        var mapped=context.Map(staging,0,MapMode.Read);
        try
        {
            var result=new byte[width*height*4];
            for(var y=0;y<height;y++)Marshal.Copy(mapped.DataPointer+(int)(y*mapped.RowPitch),result,y*width*4,width*4);
            return(width,height,result);
        }
        finally{context.Unmap(staging,0);}
    }
    internal GalaxyGraphics(Compositor compositor)
    {
        D3D11CreateDevice(IntPtr.Zero,DriverType.Hardware,DeviceCreationFlags.BgraSupport,
            [FeatureLevel.Level_11_1,FeatureLevel.Level_11_0],out device,out _,out context).CheckError();
        using(var unknown=new SharpGen.Runtime.ComObject(WinRT.MarshalInspectable<Compositor>.FromManaged(compositor)))
        using(var api=unknown.QueryInterface<ICompositorInterop>())
        {api.CreateGraphicsDevice(device,out var created).CheckError();compositionDevice=created!;}
        Surface=compositionDevice.CreateDrawingSurface(new Windows.Foundation.Size(1,1),
            Microsoft.Graphics.DirectX.DirectXPixelFormat.B8G8R8A8UIntNormalized,Microsoft.Graphics.DirectX.DirectXAlphaMode.Premultiplied);
        using(var unknown=new SharpGen.Runtime.ComObject(WinRT.MarshalInspectable<CompositionDrawingSurface>.FromManaged(Surface)))
            interop=unknown.QueryInterface<ICompositionDrawingSurfaceInterop>();
        beginDraw=Marshal.GetDelegateForFunctionPointer<BeginDraw>(Marshal.ReadIntPtr(Marshal.ReadIntPtr(interop.NativePointer),3*IntPtr.Size));
        resizeDraw=Marshal.GetDelegateForFunctionPointer<ResizeDraw>(Marshal.ReadIntPtr(Marshal.ReadIntPtr(interop.NativePointer),5*IntPtr.Size));
        starBuffer=device.CreateBuffer(StarCapacity*48,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
        lineBuffer=device.CreateBuffer(LineVertexCapacity*32,BindFlags.VertexBuffer,ResourceUsage.Dynamic,CpuAccessFlags.Write);
        constants=device.CreateBuffer(80,BindFlags.ConstantBuffer);
        var shader=Path.Combine(AppContext.BaseDirectory,"Assets","GalaxyMap.hlsl");
        InitializeNebulae(shader);
        InitializeGalacticZones(shader);
        InitializePowerContours(shader);
        InitializeOriginalSprites();
        InitializeOriginalBlackHoles(Path.Combine(Path.GetDirectoryName(shader)!,"GalaxyBlackHole.hlsl"));
        InitializeOriginalPowerActivityRing(shader);
        InitializeOriginalPowerActivityBillboard(shader);
        InitializeOriginalMilkyWay(shader);
        InitializeOriginalGrid(shader);
        InitializeOriginalCurrentTrade(shader);
        InitializeOriginalCore(Path.Combine(Path.GetDirectoryName(shader)!,"GalaxyCore.hlsl"));
        InitializeOriginalHdr(Path.Combine(Path.GetDirectoryName(shader)!,"GalaxyHdr.hlsl"));
        InitializeOriginalExposure(shader);
        InitializeOriginalPlane(Path.Combine(Path.GetDirectoryName(shader)!,"GalaxyPlane.hlsl"));
        var a=Compiler.CompileFromFile(shader,"VSStar","vs_5_0");starsVs=device.CreateVertexShader(a.Span);
        starsLayout=device.CreateInputLayout([
            new InputElementDescription("POSITION",0,Format.R32G32_Float,0,0,InputClassification.PerInstanceData,1),
            new InputElementDescription("RADIUS",0,Format.R32G32_Float,8,0,InputClassification.PerInstanceData,1),
            new InputElementDescription("COLOR",0,Format.R32G32B32A32_Float,16,0,InputClassification.PerInstanceData,1),
            new InputElementDescription("APPEARANCE",0,Format.R32G32B32A32_Float,32,0,InputClassification.PerInstanceData,1)],a.Span);
        var b=Compiler.CompileFromFile(shader,"VSLine","vs_5_0");linesVs=device.CreateVertexShader(b.Span);
        linesLayout=device.CreateInputLayout([
            new InputElementDescription("POSITION",0,Format.R32G32_Float,0,0),
            new InputElementDescription("TEXCOORD",0,Format.R32G32_Float,8,0),
            new InputElementDescription("COLOR",0,Format.R32G32B32A32_Float,16,0)],b.Span);
        starsPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSStar","ps_5_0").Span);
        linesPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSLine","ps_5_0").Span);
        skyVs=device.CreateVertexShader(Compiler.CompileFromFile(shader,"VSSky","vs_5_0").Span);
        skyPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSSky","ps_5_0").Span);
        inspectSkyPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSInspectSky","ps_5_0").Span);
        overviewVs=device.CreateVertexShader(Compiler.CompileFromFile(shader,"VSOverview","vs_5_0").Span);
        overviewPs=device.CreatePixelShader(Compiler.CompileFromFile(shader,"PSOverview","ps_5_0").Span);
        additive=device.CreateBlendState(new BlendDescription(Blend.One,Blend.InverseSourceAlpha));
        sampler=device.CreateSamplerState(new SamplerDescription(Filter.MinMagMipLinear,TextureAddressMode.Clamp,TextureAddressMode.Clamp,TextureAddressMode.Clamp));
        rasterizer=device.CreateRasterizerState(new RasterizerDescription(CullMode.None,FillMode.Solid));
        noDepth=device.CreateDepthStencilState(new DepthStencilDescription(false,DepthWriteMask.Zero,ComparisonFunction.Always));
    }
    private void Resize(int w,int h)
    {
        if(width==w&&height==h)return;
        context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());target?.Dispose();pixels?.Dispose();
        Marshal.ThrowExceptionForHR(resizeDraw(interop.NativePointer,new(w,h)));width=w;height=h;
        pixels=device.CreateTexture2D(Format.B8G8R8A8_UNorm,(uint)w,(uint)h,mipLevels:1,bindFlags:BindFlags.RenderTarget);
        target=device.CreateRenderTargetView(pixels);
    }
    private unsafe void Upload<T>(ID3D11Buffer buffer,ReadOnlySpan<T> data) where T:unmanaged
    {
        if(data.Length==0)return;
        var mapped=context.Map(buffer,0,MapMode.WriteDiscard);
        try{var bytes=MemoryMarshal.AsBytes(data);bytes.CopyTo(new Span<byte>((void*)mapped.DataPointer,bytes.Length));}
        finally{context.Unmap(buffer,0);}
    }
    public void Draw(ReadOnlySpan<GalaxyStar> stars,ReadOnlySpan<GalaxyLineVertex> lines,double w,double h,double raster,double yaw,double pitch,Vector3 centre,float scale,float panX,float panY,bool realistic=true,bool showBackground=true,bool showUnresolvedStars=true,bool navigationMarkers=true)
    {
        UnresolvedStarBackgroundEnabled=showBackground&&showUnresolvedStars;
        Resize(Math.Clamp((int)Math.Ceiling(w*raster),1,7680),Math.Clamp((int)Math.Ceiling(h*raster),1,4320));
        RefreshSky();
        PrepareNebulae(w,h,yaw,pitch,centre,scale,panX,panY,showBackground);
        var backgroundCamera=GalaxyCamera.Create(new(centre.X,centre.Y,centre.Z),w,h,yaw,pitch,scale,panX,panY);
        // Pass the same recovered Core lens/clip values to every world pass.
        // optionsZW and densityExtentZW were unused in the normal map b0.
        var camera=new Camera(new((float)w,(float)h,(float)yaw,(float)pitch),new(sky is null?0:1,density is null?0:1,(float)backgroundCamera.FocalLength,(float)backgroundCamera.Distance),
            new(centre,scale),new(panX,panY,(float)(densityMap?.OriginX??0),(float)(densityMap?.OriginZ??0)),
            new((float)(densityMap?.ExtentX??1),(float)(densityMap?.ExtentZ??1),(float)backgroundCamera.Near,(float)backgroundCamera.ProjectionFar));
        context.UpdateSubresource(in camera,constants);context.VSSetConstantBuffer(0,constants);context.PSSetConstantBuffer(0,constants);
        context.OMSetRenderTargets(target!);context.RSSetViewport(new Viewport(width,height));context.RSSetState(rasterizer);context.OMSetDepthStencilState(noDepth);context.OMSetBlendState(null);
        context.ClearRenderTargetView(target!,new Color4(.011f,.014f,.019f,1));DrawCalls=0;
        // The captured cockpit cube is only 256px/face and includes the local
        // resolved star field. Magnifying it here creates ten-pixel square stars
        // and duplicates catalogue stars. Keep it available for resource
        // inspection, but draw map stars exclusively from the real catalogue.
        context.OMSetBlendState(additive);
        OriginalSceneHdrDrawn=false;
        OriginalBackgroundHdrDrawn=false;
        BeginOriginalHdr(width,height,new Color4(0,0,0,1));
        BindOriginalSourceOutput(GalaxyOriginalHdr.WriteScale,false);
        if(showBackground)
        {
            DrawOriginalPlane(backgroundCamera,true,GalaxyOriginalHdr.WriteScale);
            DrawOriginalCore(backgroundCamera,true,GalaxyOriginalHdr.WriteScale,GalaxyOriginalHdr.ReadScale);
            DrawOriginalMilkyWay(backgroundCamera,true,GalaxyOriginalHdr.WriteScale);
            OriginalBackgroundHdrDrawn=true;
        }
        if(showBackground&&showUnresolvedStars&&!OriginalMilkyWayReady&&density is not null&&scale<.2f)
        {
            context.IASetInputLayout(null);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
            context.VSSetShader(overviewVs);context.PSSetShader(overviewPs);context.PSSetShaderResource(1,density);context.PSSetSampler(0,sampler);context.Draw(6,0);
            context.PSSetShaderResource(1,null!);DrawCalls++;
        }
        // The legacy nebula/zone paths explicitly adapt RGB to scene storage;
        // their source materials remain incomplete. Recovered passes below
        // use their actual RGB-only Write and independent alpha/blend state.
        DrawNebulae(originalHdrTarget);
        DrawGalacticZones();
        DrawPowerContours();
        ComputeOriginalManualExposure();
        DrawOriginalPowerActivityBillboard(backgroundCamera,GalaxyOriginalHdr.WriteScale);
        DrawOriginalPowerActivityRing(backgroundCamera,GalaxyOriginalHdr.WriteScale);
        DrawOriginalGrid(backgroundCamera,GalaxyOriginalHdr.WriteScale);
        DrawOriginalCurrentTrade(backgroundCamera,GalaxyOriginalHdr.WriteScale);
        if(stars.Length>0)
        {
            BindOriginalSourceOutput(GalaxyOriginalHdr.WriteScale);
            Upload(starBuffer,PrepareStellarSprites(ApplyNebulaTransmission(stars),backgroundCamera,realistic));context.IASetInputLayout(starsLayout);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
            context.IASetVertexBuffer(0,starBuffer,48);context.VSSetShader(starsVs);context.PSSetShader(starsPs);
            context.PSSetShaderResource(7,originalSprites!);context.PSSetSampler(0,sampler);
            context.DrawInstanced(6,(uint)stars.Length,0,0);context.PSSetShaderResource(7,null!);DrawCalls++;
        }
        DrawOriginalBlackHoles(stars,backgroundCamera,realistic,navigationMarkers,GalaxyOriginalHdr.WriteScale);
        EndOriginalHdr(target!);context.OMSetBlendState(additive);OriginalSceneHdrDrawn=true;
        // Tool navigation strokes are screen overlays, after scene tone mapping.
        if(lines.Length>0)
        {
            Upload(lineBuffer,lines);context.IASetInputLayout(linesLayout);context.IASetPrimitiveTopology(PrimitiveTopology.LineList);
            context.IASetVertexBuffer(0,lineBuffer,32);context.VSSetShader(linesVs);context.PSSetShader(linesPs);context.Draw((uint)lines.Length,0);DrawCalls++;
        }
        context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());
        var iid=typeof(ID3D11Texture2D).GUID;Marshal.ThrowExceptionForHR(beginDraw(interop.NativePointer,IntPtr.Zero,in iid,out var texture,out var offset));
        using(var destination=new ID3D11Texture2D(texture))
        {
            try{context.CopySubresourceRegion(destination,0,(uint)offset.X,(uint)offset.Y,0,pixels!,0,new Box(0,0,0,width,height,1));context.Flush();}
            finally{interop.EndDraw().CheckError();}
        }
        Frames++;
    }
    private ReadOnlySpan<GalaxyStellarSprite> PrepareStellarSprites(ReadOnlySpan<GalaxyStar> stars,GalaxyCamera camera,bool realistic)
    {
        var focus=camera.Focus;var forward=camera.Forward;var eye=camera.Eye;
        for(var i=0;i<stars.Length;i++)
        {
            var star=stars[i];
            // Original RGB is floating point (some palette entries exceed1).
            // Its alpha0 is a real hidden style, not an absent colour.
            var colour=star.OriginalColour??star.Colour;
            if(star.Radius<=0||colour.W<=0||!float.IsFinite(colour.X+colour.Y+colour.Z+colour.W))
            {stellarSprites[i]=new(star.Position,0,0,Vector4.Zero,Vector4.Zero);continue;}
            // Actual physical types41/42 use their separate BackgroundBlackHole
            // material. Retain only the tool's independent navigation glyph here.
            if(realistic&&star.OriginalBlackHole)
            {stellarSprites[i]=new(star.Position,star.Kind>=2?26:0,star.Kind,Vector4.Zero,Vector4.Zero);continue;}
            var dx=star.World.X-focus.X;var dy=star.World.Y-focus.Y;var dz=star.World.Z-focus.Z;
            var spectral=star.World.W>0?(int)MathF.Round(star.World.W)-1:13;
            var projectedScale=camera.FocalLength/Math.Max(camera.Near,camera.Distance+dx*forward.X+dy*forward.Y+dz*forward.Z);
            var originalPhysical=realistic&&float.IsFinite(star.OriginalSize)&&star.OriginalSize>0&&spectral!=12;
            if(!realistic||originalPhysical)
            {
                // Actual Galaxy chain3A441A0→39FB140→3C01470→3C10980
                // supplies six UV/corner vertices with cornerZW=±1. Producer
                // 3A431C0 supplies half(styleSize); original VS multiplies them.
                // No estimated profile, size floor, zoom curve or4x expansion.
                var size=originalPhysical?star.OriginalSize:star.Radius;
                if(star.PowerTerritorySize&&!realistic)
                {
                    var ex=star.World.X-eye.X;var ey=star.World.Y-eye.Y;var ez=star.World.Z-eye.Z;
                    size*=StellarAppearance.PowerTerritoryDistanceScale(Math.Sqrt(ex*ex+ey*ey+ez*ez));
                }
                var halfExtent=StellarAppearance.OriginalProjectedHalfExtent(size,projectedScale);
                stellarSprites[i]=new(star.Position,halfExtent>0?Math.Max(halfExtent,star.Kind>=2?26:0):0,star.Kind,colour,
                    new(halfExtent,Math.Clamp(star.OriginalSprite,0,27),originalPhysical?2:0,0));
            }
            else
            {
                // Public catalogue rows without native physical appearance
                // retain an explicit estimate; they cannot claim a native branch.
                var profile=StellarAppearance.Sprite(spectral,Math.Sqrt(dx*dx+dy*dy+dz*dz),projectedScale,(int)star.Kind);
                var relative=float.IsFinite(star.Radius)?Math.Clamp(star.Radius,.01f,8):1;
                profile=profile with{CoreRadius=profile.CoreRadius*relative,Radius=Math.Max(profile.Radius*relative,star.Kind>=2?26:0)};
                stellarSprites[i]=new(star.Position,profile.Radius,star.Kind,colour with{W=colour.W*profile.Opacity},
                    new(profile.CoreRadius,(float)profile.Morphology,1,profile.Corona));
            }
        }
        return stellarSprites.AsSpan(0,stars.Length);
    }
    private void RefreshSky()
    {
        if(Environment.TickCount64<nextSkyCheck)return;nextSkyCheck=Environment.TickCount64+2000;
        if(density is null)
        {
            var mapPath=Path.Combine(App.Runtime.DataDirectory,"galaxy","galaxy-density.bin");
            if(File.Exists(mapPath))
            {
                var map=GalaxyDensityMap.Read(mapPath);var pinned=GCHandle.Alloc(map.Values,GCHandleType.Pinned);
                try{densityTexture=device.CreateTexture2D(new Texture2DDescription{Width=(uint)map.Width,Height=(uint)map.Height,MipLevels=1,ArraySize=1,Format=map.FloatValues?Format.R32_Float:Format.R16_UNorm,
                    SampleDescription=new(1,0),Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource},[new SubresourceData(pinned.AddrOfPinnedObject(),(uint)(map.Width*(map.FloatValues?4:2)),0)]);
                    density=device.CreateShaderResourceView(densityTexture);densityMap=map;}
                finally{pinned.Free();}
            }
        }
    }
    private void LoadSky(string path)
    {
        var cube=GameSkyboxCube.Read(path);
        var description=new Texture2DDescription{Width=(uint)cube.Size,Height=(uint)cube.Size,ArraySize=6,MipLevels=1,Format=(Format)cube.Format,
            SampleDescription=new(1,0),Usage=ResourceUsage.Immutable,BindFlags=BindFlags.ShaderResource,MiscFlags=ResourceOptionFlags.TextureCube};
        var handles=new GCHandle[6];var data=new SubresourceData[6];
        try
        {
            for(var i=0;i<6;i++){handles[i]=GCHandle.Alloc(cube.Faces[i],GCHandleType.Pinned);data[i]=new(handles[i].AddrOfPinnedObject(),(uint)cube.RowPitch,0);}
            var texture=device.CreateTexture2D(description,data);var view=device.CreateShaderResourceView(texture);
            sky?.Dispose();skyTexture?.Dispose();skyTexture=texture;sky=view;SkyboxSource="游戏实际天空立方体";
        }
        finally{foreach(var handle in handles)if(handle.IsAllocated)handle.Free();}
    }
    internal SkyboxPixels.Metrics[] InspectSky(string path)
    {
        LoadSky(path);Resize(256,256);var measurements=new SkyboxPixels.Metrics[6];
        context.OMSetRenderTargets(target!);context.RSSetViewport(new Viewport(width,height));context.RSSetState(rasterizer);
        context.OMSetDepthStencilState(noDepth);context.OMSetBlendState(null);context.IASetInputLayout(null);context.IASetPrimitiveTopology(PrimitiveTopology.TriangleList);
        context.VSSetShader(skyVs);context.PSSetShader(inspectSkyPs);context.PSSetShaderResource(0,sky!);context.PSSetSampler(0,sampler);
        for(var face=0;face<6;face++)
        {
            var camera=new Camera(new(256,256,0,0),new(0,0,face,0),default,default,default);
            context.UpdateSubresource(in camera,constants);context.VSSetConstantBuffer(0,constants);context.PSSetConstantBuffer(0,constants);context.Draw(3,0);
            var pixels=ReadPixels();measurements[face]=SkyboxPixels.Inspect(pixels.Pixels,pixels.Width,pixels.Height);
        }
        context.PSSetShaderResource(0,null!);context.OMSetRenderTargets(Array.Empty<ID3D11RenderTargetView>());return measurements;
    }
    public void Dispose()
    {
        context.ClearState();context.Flush();target?.Dispose();pixels?.Dispose();sky?.Dispose();skyTexture?.Dispose();
        DisposeNebulae();
        DisposeGalacticZones();
        DisposePowerContours();
        DisposeOriginalSprites();
        DisposeOriginalBlackHoles();
        DisposeOriginalExposure();
        DisposeOriginalPowerActivityRing();
        DisposeOriginalPowerActivityBillboard();
        DisposeOriginalMilkyWay();
        DisposeOriginalGrid();
        DisposeOriginalCurrentTrade();
        DisposeOriginalCore();
        DisposeOriginalHdr();
        DisposeOriginalPlane();
        interop.Dispose();Surface.Dispose();compositionDevice.Dispose();sampler.Dispose();rasterizer.Dispose();noDepth.Dispose();additive.Dispose();starsLayout.Dispose();linesLayout.Dispose();
        starsVs.Dispose();linesVs.Dispose();skyVs.Dispose();overviewVs.Dispose();starsPs.Dispose();linesPs.Dispose();skyPs.Dispose();overviewPs.Dispose();inspectSkyPs.Dispose();density?.Dispose();densityTexture?.Dispose();starBuffer.Dispose();lineBuffer.Dispose();constants.Dispose();context.Dispose();device.Dispose();
    }
    [StructLayout(LayoutKind.Sequential)] private readonly record struct Camera(Vector4 Viewport,Vector4 Options,Vector4 CentreScale,Vector4 PanOrigin,Vector4 DensityExtent);
    [StructLayout(LayoutKind.Sequential)] private readonly record struct PixelSize(int Width,int Height);
    [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int BeginDraw(nint surface,nint rectangle,in Guid iid,out nint texture,out Int2 offset);
    [UnmanagedFunctionPointer(CallingConvention.StdCall)] private delegate int ResizeDraw(nint surface,PixelSize size);
}