qstbak/Auspex/Auspex.Rendering.Direct3D/Direct3DRenderer.cs
2026-08-17 20:25:32 +10:00

787 lines
28 KiB
C#

using System;
using System.Collections.Generic;
using System.Numerics;
using System.Runtime.InteropServices;
using FFXIVClientStructs.FFXIV.Client.Game;
using FFXIVClientStructs.FFXIV.Client.Game.Control;
using FFXIVClientStructs.FFXIV.Client.Graphics.Kernel;
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
using TerraFX.Interop.DirectX;
using TerraFX.Interop.Windows;
namespace Auspex.Rendering.Direct3D;
internal sealed class Direct3DRenderer : IDisposable
{
public const int MAX_FANS = 2048;
public const int MAX_TRIS = 65536;
public const int MAX_STROKE_SEGMENTS = 245760;
public const int MAX_CLIP_ZONES = 3072;
public const int MAX_TEXTURED_QUADS = 256;
private unsafe ID3D11DepthStencilState* _clipZoneDSS;
private unsafe ID3D11DepthStencilState* _shapeDSS;
private readonly TriangleFillShader.Data _triFillDynamicData;
private TriangleFillShader.Data.Builder? _triFillDynamicBuilder;
private readonly FanFillShader.Data _fanFillDynamicData;
private FanFillShader.Data.Builder? _fanFillDynamicBuilder;
private readonly StrokeShader.Data _strokeDynamicData;
private StrokeShader.Data.Builder? _strokeDynamicBuilder;
private readonly QuadBlitter.Data _texturedQuadDynamicData;
private QuadBlitter.Data.Builder? _texturedQuadDynamicBuilder;
internal readonly List<Vector3> SharedPath = new List<Vector3>();
private unsafe ID3D11RasterizerState* _rasterizerState;
public FrameRenderContext FrameRenderContext { get; init; } = new FrameRenderContext();
internal FrameRenderTarget? FrameRenderTarget { get; private set; }
public TriangleFillShader TriangleFillShader { get; init; }
public FanFillShader FanFillShader { get; init; }
public StrokeShader StrokeShader { get; init; }
public QuadBlitter QuadBlitter { get; init; }
public FullscreenPassShader? FSP { get; init; }
public ClipZoneShader ClipZone { get; init; }
internal SceneDepthCapture SceneDepth { get; init; }
public Matrix4x4 ViewProj { get; private set; }
public Vector2 ViewportSize { get; private set; }
public Vector3 CameraRight { get; private set; }
public Vector3 CameraUp { get; private set; }
public bool FanDegraded { get; private set; }
public bool StrokeDegraded { get; private set; }
public bool FSPDegraded { get; private set; }
public bool TexturedQuadDegraded { get; private set; }
internal HighResFontAtlas? WorldFont { get; private set; }
public Direct3DRenderer()
{
try
{
FanFillShader = new FanFillShader(FrameRenderContext);
}
catch (Exception exception)
{
AuspexService.Log.Error(exception, "[Auspex] Failed to compile fan shader; starting in degraded mode.");
FanDegraded = true;
}
_fanFillDynamicData = new FanFillShader.Data(FrameRenderContext, FanDegraded ? 1 : 2048, dynamic: true);
try
{
StrokeShader = new StrokeShader(FrameRenderContext);
}
catch (Exception exception2)
{
AuspexService.Log.Error(exception2, "[Auspex] Failed to compile stroke shader; starting in degraded mode.");
StrokeDegraded = true;
}
_strokeDynamicData = new StrokeShader.Data(FrameRenderContext, StrokeDegraded ? 1 : 245760, dynamic: true);
try
{
QuadBlitter = new QuadBlitter(FrameRenderContext);
}
catch (Exception exception3)
{
AuspexService.Log.Error(exception3, "[Auspex] Failed to compile textured quad shader; starting in degraded mode.");
TexturedQuadDegraded = true;
}
_texturedQuadDynamicData = new QuadBlitter.Data(FrameRenderContext, TexturedQuadDegraded ? 1 : 1536, dynamic: true);
if (!TexturedQuadDegraded)
{
try
{
WorldFont = new HighResFontAtlas(FrameRenderContext);
}
catch (Exception exception4)
{
AuspexService.Log.Error(exception4, "[Auspex] Failed to create high-res world text font; world text will use low-res fallback.");
}
}
try
{
TriangleFillShader = new TriangleFillShader(FrameRenderContext);
_triFillDynamicData = new TriangleFillShader.Data(FrameRenderContext, 65536 + (FanDegraded ? 737280 : 0), dynamic: true);
}
catch
{
Dispose();
throw;
}
try
{
FSP = new FullscreenPassShader(FrameRenderContext);
}
catch (Exception exception5)
{
AuspexService.Log.Error(exception5, "[Auspex] Failed to compile FSP shader; starting in degraded mode.");
FSPDegraded = true;
}
SceneDepth = new SceneDepthCapture();
ClipZone = new ClipZoneShader(FrameRenderContext, 3072);
CreateRasterizerState();
CreateDepthStencilStates();
}
private unsafe void CreateRasterizerState()
{
D3D11_RASTERIZER_DESC d3D11_RASTERIZER_DESC = new D3D11_RASTERIZER_DESC
{
FillMode = D3D11_FILL_MODE.D3D11_FILL_SOLID,
CullMode = D3D11_CULL_MODE.D3D11_CULL_NONE,
DepthClipEnable = true,
ScissorEnable = true
};
ID3D11RasterizerState* rasterizerState = default(ID3D11RasterizerState*);
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateRasterizerState(&d3D11_RASTERIZER_DESC, &rasterizerState));
_rasterizerState = rasterizerState;
}
private unsafe void CreateDepthStencilStates()
{
D3D11_DEPTH_STENCILOP_DESC d3D11_DEPTH_STENCILOP_DESC = new D3D11_DEPTH_STENCILOP_DESC
{
StencilFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
StencilDepthFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
StencilPassOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_REPLACE,
StencilFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_ALWAYS
};
D3D11_DEPTH_STENCIL_DESC d3D11_DEPTH_STENCIL_DESC = new D3D11_DEPTH_STENCIL_DESC
{
DepthEnable = false,
DepthWriteMask = D3D11_DEPTH_WRITE_MASK.D3D11_DEPTH_WRITE_MASK_ZERO,
StencilEnable = true,
StencilReadMask = byte.MaxValue,
StencilWriteMask = byte.MaxValue,
FrontFace = d3D11_DEPTH_STENCILOP_DESC,
BackFace = d3D11_DEPTH_STENCILOP_DESC
};
ID3D11DepthStencilState* ptr = default(ID3D11DepthStencilState*);
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateDepthStencilState(&d3D11_DEPTH_STENCIL_DESC, &ptr));
_clipZoneDSS = ptr;
D3D11_DEPTH_STENCILOP_DESC d3D11_DEPTH_STENCILOP_DESC2 = new D3D11_DEPTH_STENCILOP_DESC
{
StencilFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
StencilDepthFailOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
StencilPassOp = D3D11_STENCIL_OP.D3D11_STENCIL_OP_KEEP,
StencilFunc = D3D11_COMPARISON_FUNC.D3D11_COMPARISON_EQUAL
};
D3D11_DEPTH_STENCIL_DESC d3D11_DEPTH_STENCIL_DESC2 = new D3D11_DEPTH_STENCIL_DESC
{
DepthEnable = false,
DepthWriteMask = D3D11_DEPTH_WRITE_MASK.D3D11_DEPTH_WRITE_MASK_ZERO,
StencilEnable = true,
StencilReadMask = byte.MaxValue,
StencilWriteMask = 0,
FrontFace = d3D11_DEPTH_STENCILOP_DESC2,
BackFace = d3D11_DEPTH_STENCILOP_DESC2
};
Marshal.ThrowExceptionForHR(FrameRenderContext.Device->CreateDepthStencilState(&d3D11_DEPTH_STENCIL_DESC2, &ptr));
_shapeDSS = ptr;
}
public unsafe void Dispose()
{
WorldFont?.Dispose();
FrameRenderTarget?.Dispose();
_triFillDynamicBuilder?.Dispose();
_triFillDynamicData?.Dispose();
_fanFillDynamicBuilder?.Dispose();
_fanFillDynamicData?.Dispose();
_strokeDynamicBuilder?.Dispose();
_strokeDynamicData?.Dispose();
_texturedQuadDynamicBuilder?.Dispose();
_texturedQuadDynamicData?.Dispose();
if (!FanDegraded)
{
FanFillShader.Dispose();
}
if (!StrokeDegraded)
{
StrokeShader.Dispose();
}
if (!TexturedQuadDegraded)
{
QuadBlitter.Dispose();
}
TriangleFillShader?.Dispose();
FSP?.Dispose();
SceneDepth.Dispose();
ClipZone.Dispose();
if (_clipZoneDSS != null)
{
_clipZoneDSS->Release();
_clipZoneDSS = null;
}
if (_shapeDSS != null)
{
_shapeDSS->Release();
_shapeDSS = null;
}
if (_rasterizerState != null)
{
_rasterizerState->Release();
_rasterizerState = null;
}
FrameRenderContext.Dispose();
GC.SuppressFinalize(this);
}
internal unsafe void BeginFrame()
{
Device* ptr = Device.Instance();
ViewportSize = new Vector2(ptr->Width, ptr->Height);
Control* ptr2 = Control.Instance();
ViewProj = *(Matrix4x4*)(&ptr2->ViewProjectionMatrix);
SceneDepth.Update();
FFXIVClientStructs.FFXIV.Client.Game.Camera* activeCamera = ptr2->CameraManager.GetActiveCamera();
FFXIVClientStructs.FFXIV.Client.Graphics.Render.Camera* ptr3 = ((activeCamera != null) ? activeCamera->SceneCamera.RenderCamera : null);
if (ptr3 != null && Matrix4x4.Invert(ptr3->ProjectionMatrix, out var result))
{
Matrix4x4 matrix4x = ViewProj * result;
CameraRight = Vector3.Normalize(new Vector3(matrix4x.M11, matrix4x.M21, matrix4x.M31));
CameraUp = Vector3.Normalize(new Vector3(matrix4x.M12, matrix4x.M22, matrix4x.M32));
}
else
{
CameraRight = Vector3.UnitX;
CameraUp = Vector3.UnitY;
}
Vector2 pixelToUv = ((SceneDepth.SRV != null) ? (SceneDepth.UvScale / ViewportSize) : Vector2.Zero);
TriangleFillShader.UpdateConstants(FrameRenderContext, new TriangleFillShader.Constants
{
ViewProj = ViewProj,
PixelToUv = pixelToUv
});
if (!FanDegraded)
{
FanFillShader.UpdateConstants(FrameRenderContext, new FanFillShader.Constants
{
ViewProj = ViewProj,
PixelToUv = pixelToUv
});
}
if (!StrokeDegraded)
{
StrokeShader.UpdateConstants(FrameRenderContext, new StrokeShader.Constants
{
ViewProj = ViewProj,
RenderTargetSize = new Vector2(ViewportSize.X, ViewportSize.Y),
PixelToUv = pixelToUv
});
}
if (!TexturedQuadDegraded)
{
QuadBlitter.UpdateConstants(FrameRenderContext, new QuadBlitter.Constants
{
ViewProj = ViewProj
});
}
if (!FSPDegraded)
{
bool flag = AuspexService.Hints.ClipNativeUI && !SceneDepth.IsResolutionScaled;
FSP.UpdateConstants(FrameRenderContext, new FullscreenPassShader.Constants
{
MaxAlpha = AuspexService.Hints.MaxAlphaFraction,
ClipNativeUI = (flag ? 1f : 0f)
});
}
if (FrameRenderTarget == null || FrameRenderTarget.Size != ViewportSize)
{
FrameRenderTarget?.Dispose();
FrameRenderTarget = new FrameRenderTarget(FrameRenderContext, (int)ViewportSize.X, (int)ViewportSize.Y, AuspexService.Hints.AlphaBlendMode);
}
FrameRenderTarget.Bind(FrameRenderContext);
FrameRenderContext.Context->RSSetState(_rasterizerState);
RECT rECT = new RECT
{
left = 0,
top = 0,
right = (int)ViewportSize.X,
bottom = (int)ViewportSize.Y
};
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
}
internal void Flush()
{
if (_triFillDynamicBuilder != null)
{
_triFillDynamicBuilder.Dispose();
_triFillDynamicBuilder = null;
TriangleFillShader.Bind(FrameRenderContext);
_triFillDynamicData.DrawAll(FrameRenderContext);
}
if (!FanDegraded && _fanFillDynamicBuilder != null)
{
_fanFillDynamicBuilder.Dispose();
_fanFillDynamicBuilder = null;
FanFillShader.Bind(FrameRenderContext);
_fanFillDynamicData.DrawAll(FrameRenderContext);
}
if (!StrokeDegraded && _strokeDynamicBuilder != null)
{
_strokeDynamicBuilder.Dispose();
_strokeDynamicBuilder = null;
StrokeShader.Bind(FrameRenderContext);
_strokeDynamicData.DrawAll(FrameRenderContext);
}
if (!TexturedQuadDegraded && _texturedQuadDynamicBuilder != null)
{
_texturedQuadDynamicBuilder.Dispose();
_texturedQuadDynamicBuilder = null;
QuadBlitter.Draw(FrameRenderContext, _texturedQuadDynamicData);
}
}
internal unsafe void SetScissorRect(Vector2 min, Vector2 max)
{
Flush();
RECT rECT = new RECT
{
left = (int)min.X,
top = (int)min.Y,
right = (int)max.X,
bottom = (int)max.Y
};
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
}
internal unsafe void ClearScissorRect()
{
Flush();
RECT rECT = new RECT
{
left = 0,
top = 0,
right = (int)ViewportSize.X,
bottom = (int)ViewportSize.Y
};
FrameRenderContext.Context->RSSetScissorRects(1u, &rECT);
}
public void AddClipZone(Vector2 min, Vector2 max)
{
ClipZone.Add(min, max);
}
internal unsafe FrameRenderTarget EndFrame()
{
bool num = _triFillDynamicBuilder != null || (!FanDegraded && _fanFillDynamicBuilder != null) || (!StrokeDegraded && _strokeDynamicBuilder != null) || (!TexturedQuadDegraded && _texturedQuadDynamicBuilder != null);
bool hasPending = ClipZone.HasPending;
if (num && SceneDepth.SRV != null)
{
ID3D11DepthStencilView* clipStencilDSV = FrameRenderTarget.ClipStencilDSV;
FrameRenderContext.Context->OMSetRenderTargets(0u, null, clipStencilDSV);
FrameRenderContext.Context->ClearDepthStencilView(clipStencilDSV, 2u, 0f, 0);
if (hasPending)
{
ClipZone.UpdateConstants(new ClipZoneShader.Constants
{
ViewportSize = new Vector2(ViewportSize.X, ViewportSize.Y)
});
FrameRenderContext.Context->OMSetDepthStencilState(_clipZoneDSS, 1u);
ClipZone.Flush();
}
ID3D11RenderTargetView* baseRTV = FrameRenderTarget.BaseRTV;
FrameRenderContext.Context->OMSetRenderTargets(1u, &baseRTV, clipStencilDSV);
FrameRenderContext.Context->OMSetDepthStencilState(_shapeDSS, 0u);
ID3D11ShaderResourceView* sRV = SceneDepth.SRV;
FrameRenderContext.Context->PSSetShaderResources(0u, 1u, &sRV);
}
else
{
ClipZone.Discard();
}
Flush();
if (SceneDepth.SRV != null)
{
ID3D11ShaderResourceView* ptr = null;
FrameRenderContext.Context->PSSetShaderResources(0u, 1u, &ptr);
}
if (!FSPDegraded)
{
Device* ptr2 = Device.Instance();
if (ptr2 != null && ptr2->SwapChain != null && ptr2->SwapChain->BackBuffer != null && ptr2->SwapChain->BackBuffer->D3D11Texture2D != null)
{
ID3D11Texture2D* d3D11Texture2D = (ID3D11Texture2D*)ptr2->SwapChain->BackBuffer->D3D11Texture2D;
FrameRenderTarget.ExecuteFSP(FrameRenderContext, d3D11Texture2D, FSP, AuspexService.Hints.ClipNativeUI && !SceneDepth.IsResolutionScaled);
}
else
{
AuspexService.Log.Warning("[Auspex] Direct3DRenderer.EndFrame: Device or BackBuffer is null; skipping combined pass.");
}
}
else
{
FrameRenderTarget.CopyBaseToProcessed(FrameRenderContext);
}
FrameRenderContext.Execute();
return FrameRenderTarget;
}
public void DrawTriangle(Vector3 a, Vector3 b, Vector3 c, uint colorA, uint colorB, uint colorC, AxDxParams p)
{
TriangleFillShader.Data.Builder triFills = GetTriFills();
triFills.Add(a, colorA.ToVector4(), p);
triFills.Add(b, colorB.ToVector4(), p);
triFills.Add(c, colorC.ToVector4(), p);
}
private void DrawTriangle(Vector3 a, Vector3 b, Vector3 c, Vector4 colorA, Vector4 colorB, Vector4 colorC, AxDxParams p)
{
TriangleFillShader.Data.Builder triFills = GetTriFills();
triFills.Add(a, colorA, p);
triFills.Add(b, colorB, p);
triFills.Add(c, colorC, p);
}
private TriangleFillShader.Data.Builder GetTriFills()
{
return _triFillDynamicBuilder ?? (_triFillDynamicBuilder = _triFillDynamicData.Map(FrameRenderContext));
}
private void DrawTriangleFan(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
{
float num = maxAngle - minAngle;
if (num == 0f)
{
return;
}
if (numSegments == 0)
{
numSegments = (uint)(MathF.Abs(num) * 8f);
}
float num2 = num / (float)numSegments;
Vector4 vector = innerColor.ToVector4();
Vector4 vector2 = outerColor.ToVector4();
Vector3 vector3 = default(Vector3);
for (int i = 0; i <= numSegments; i++)
{
float num3 = (float)Math.PI / 2f + minAngle + (float)i * num2;
Vector3 vector4 = new Vector3(MathF.Cos(num3), 0f, MathF.Sin(num3));
if (i > 0)
{
if (innerRadius > 0f)
{
DrawTriangle(center + innerRadius * vector3, center + outerRadius * vector3, center + outerRadius * vector4, vector, vector2, vector2, p);
DrawTriangle(center + outerRadius * vector4, center + innerRadius * vector4, center + innerRadius * vector3, vector2, vector, vector, p);
}
else
{
DrawTriangle(center, center + outerRadius * vector3, center + outerRadius * vector4, vector, vector2, vector2, p);
}
}
vector3 = vector4;
}
}
internal void DrawTriangleFanGradient<T>(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, T gradient, uint numSegments = 0u, AxDxParams p = default(AxDxParams)) where T : IPctGradient
{
float num = maxAngle - minAngle;
if (num == 0f)
{
return;
}
if (numSegments == 0)
{
numSegments = (uint)(MathF.Abs(num) * 8f);
}
float num2 = num / (float)numSegments;
Vector3 vector = default(Vector3);
for (int i = 0; i <= numSegments; i++)
{
float num3 = (float)Math.PI / 2f + minAngle + (float)i * num2;
Vector3 vector2 = new Vector3(MathF.Cos(num3), 0f, MathF.Sin(num3));
if (i > 0)
{
if (innerRadius > 0f)
{
Vector3 vector3 = center + innerRadius * vector;
Vector3 vector4 = center + outerRadius * vector;
Vector3 vector5 = center + outerRadius * vector2;
Vector3 vector6 = center + innerRadius * vector2;
DrawTriangle(vector3, vector4, vector5, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector5).ToVector4(), p);
DrawTriangle(vector5, vector6, vector3, gradient.ColorAt(vector5).ToVector4(), gradient.ColorAt(vector6).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
}
else
{
Vector3 vector7 = center + outerRadius * vector;
Vector3 vector8 = center + outerRadius * vector2;
DrawTriangle(center, vector7, vector8, gradient.ColorAt(center).ToVector4(), gradient.ColorAt(vector7).ToVector4(), gradient.ColorAt(vector8).ToVector4(), p);
}
}
vector = vector2;
}
}
internal void DrawTerrainFan(Vector3 origin, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, float resolution, float yOffset, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
{
float num = maxAngle - minAngle;
if (num == 0f)
{
return;
}
uint num2 = ((numSegments != 0) ? numSegments : ((uint)MathF.Ceiling(MathF.Abs(num) * outerRadius / resolution)));
if (num2 == 0)
{
num2 = 1u;
}
int num3 = Math.Max(1, (int)MathF.Ceiling((outerRadius - innerRadius) / resolution));
float num4 = num / (float)num2;
Vector4 value = innerColor.ToVector4();
Vector4 value2 = outerColor.ToVector4();
Vector3 a = ((innerRadius == 0f) ? TerrainVertex(origin, Vector3.Zero, 0f, yOffset) : default(Vector3));
float num5 = (float)Math.PI / 2f + minAngle;
Vector3 direction = new Vector3(MathF.Cos(num5), 0f, MathF.Sin(num5));
for (int i = 1; i <= num2; i++)
{
float num6 = (float)Math.PI / 2f + minAngle + (float)i * num4;
Vector3 vector = new Vector3(MathF.Cos(num6), 0f, MathF.Sin(num6));
for (int j = 0; j < num3; j++)
{
float num7 = innerRadius + (outerRadius - innerRadius) * (float)j / (float)num3;
float radius = innerRadius + (outerRadius - innerRadius) * (float)(j + 1) / (float)num3;
float amount = (float)j / (float)num3;
float amount2 = (float)(j + 1) / (float)num3;
Vector4 vector2 = Vector4.Lerp(value, value2, amount);
Vector4 vector3 = Vector4.Lerp(value, value2, amount2);
if (num7 > 0f)
{
Vector3 vector4 = TerrainVertex(origin, direction, num7, yOffset);
Vector3 b = TerrainVertex(origin, direction, radius, yOffset);
Vector3 vector5 = TerrainVertex(origin, vector, radius, yOffset);
Vector3 b2 = TerrainVertex(origin, vector, num7, yOffset);
DrawTriangle(vector4, b, vector5, vector2, vector3, vector3, p);
DrawTriangle(vector5, b2, vector4, vector3, vector2, vector2, p);
}
else
{
Vector3 b3 = TerrainVertex(origin, direction, radius, yOffset);
Vector3 c = TerrainVertex(origin, vector, radius, yOffset);
DrawTriangle(a, b3, c, vector2, vector3, vector3, p);
}
}
direction = vector;
}
}
internal void DrawTerrainFanGradient<T>(Vector3 origin, float innerRadius, float outerRadius, float minAngle, float maxAngle, T gradient, float resolution, float yOffset, uint numSegments = 0u, AxDxParams p = default(AxDxParams)) where T : IPctGradient
{
float num = maxAngle - minAngle;
if (num == 0f)
{
return;
}
uint num2 = ((numSegments != 0) ? numSegments : ((uint)MathF.Ceiling(MathF.Abs(num) * outerRadius / resolution)));
if (num2 == 0)
{
num2 = 1u;
}
int num3 = Math.Max(1, (int)MathF.Ceiling((outerRadius - innerRadius) / resolution));
float num4 = num / (float)num2;
Vector3 vector = ((innerRadius == 0f) ? TerrainVertex(origin, Vector3.Zero, 0f, yOffset) : default(Vector3));
Vector4 colorA = ((innerRadius == 0f) ? gradient.ColorAt(vector).ToVector4() : default(Vector4));
float num5 = (float)Math.PI / 2f + minAngle;
Vector3 direction = new Vector3(MathF.Cos(num5), 0f, MathF.Sin(num5));
for (int i = 1; i <= num2; i++)
{
float num6 = (float)Math.PI / 2f + minAngle + (float)i * num4;
Vector3 vector2 = new Vector3(MathF.Cos(num6), 0f, MathF.Sin(num6));
for (int j = 0; j < num3; j++)
{
float num7 = innerRadius + (outerRadius - innerRadius) * (float)j / (float)num3;
float radius = innerRadius + (outerRadius - innerRadius) * (float)(j + 1) / (float)num3;
if (num7 > 0f)
{
Vector3 vector3 = TerrainVertex(origin, direction, num7, yOffset);
Vector3 vector4 = TerrainVertex(origin, direction, radius, yOffset);
Vector3 vector5 = TerrainVertex(origin, vector2, radius, yOffset);
Vector3 vector6 = TerrainVertex(origin, vector2, num7, yOffset);
DrawTriangle(vector3, vector4, vector5, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector5).ToVector4(), p);
DrawTriangle(vector5, vector6, vector3, gradient.ColorAt(vector5).ToVector4(), gradient.ColorAt(vector6).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
}
else
{
Vector3 vector7 = TerrainVertex(origin, direction, radius, yOffset);
Vector3 vector8 = TerrainVertex(origin, vector2, radius, yOffset);
DrawTriangle(vector, vector7, vector8, colorA, gradient.ColorAt(vector7).ToVector4(), gradient.ColorAt(vector8).ToVector4(), p);
}
}
direction = vector2;
}
}
internal void DrawTerrainQuad(Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint colorA, uint colorB, uint colorC, uint colorD, float resolution, float yOffset, AxDxParams p = default(AxDxParams))
{
float num = MathF.Max(Vector3.Distance(a, b), Vector3.Distance(d, c));
float num2 = MathF.Max(Vector3.Distance(b, c), Vector3.Distance(a, d));
int num3 = Math.Max(1, (int)MathF.Ceiling(num / resolution));
int num4 = Math.Max(1, (int)MathF.Ceiling(num2 / resolution));
Vector4 a2 = colorA.ToVector4();
Vector4 b2 = colorB.ToVector4();
Vector4 c2 = colorC.ToVector4();
Vector4 d2 = colorD.ToVector4();
for (int i = 0; i < num3; i++)
{
float u = (float)i / (float)num3;
float u2 = (float)(i + 1) / (float)num3;
for (int j = 0; j < num4; j++)
{
float v = (float)j / (float)num4;
float v2 = (float)(j + 1) / (float)num4;
Vector3 vector = TerrainVertexBilinear(a, b, c, d, u, v, yOffset);
Vector3 b3 = TerrainVertexBilinear(a, b, c, d, u2, v, yOffset);
Vector3 vector2 = TerrainVertexBilinear(a, b, c, d, u2, v2, yOffset);
Vector3 b4 = TerrainVertexBilinear(a, b, c, d, u, v2, yOffset);
Vector4 vector3 = BilinearColorV4(a2, b2, c2, d2, u, v);
Vector4 colorB2 = BilinearColorV4(a2, b2, c2, d2, u2, v);
Vector4 vector4 = BilinearColorV4(a2, b2, c2, d2, u2, v2);
Vector4 colorB3 = BilinearColorV4(a2, b2, c2, d2, u, v2);
DrawTriangle(vector, b3, vector2, vector3, colorB2, vector4, p);
DrawTriangle(vector2, b4, vector, vector4, colorB3, vector3, p);
}
}
}
internal void DrawTerrainQuadGradient<T>(Vector3 a, Vector3 b, Vector3 c, Vector3 d, T gradient, float resolution, float yOffset, AxDxParams p = default(AxDxParams)) where T : IPctGradient
{
float num = MathF.Max(Vector3.Distance(a, b), Vector3.Distance(d, c));
float num2 = MathF.Max(Vector3.Distance(b, c), Vector3.Distance(a, d));
int num3 = Math.Max(1, (int)MathF.Ceiling(num / resolution));
int num4 = Math.Max(1, (int)MathF.Ceiling(num2 / resolution));
for (int i = 0; i < num3; i++)
{
float u = (float)i / (float)num3;
float u2 = (float)(i + 1) / (float)num3;
for (int j = 0; j < num4; j++)
{
float v = (float)j / (float)num4;
float v2 = (float)(j + 1) / (float)num4;
Vector3 vector = TerrainVertexBilinear(a, b, c, d, u, v, yOffset);
Vector3 vector2 = TerrainVertexBilinear(a, b, c, d, u2, v, yOffset);
Vector3 vector3 = TerrainVertexBilinear(a, b, c, d, u2, v2, yOffset);
Vector3 vector4 = TerrainVertexBilinear(a, b, c, d, u, v2, yOffset);
DrawTriangle(vector, vector2, vector3, gradient.ColorAt(vector).ToVector4(), gradient.ColorAt(vector2).ToVector4(), gradient.ColorAt(vector3).ToVector4(), p);
DrawTriangle(vector3, vector4, vector, gradient.ColorAt(vector3).ToVector4(), gradient.ColorAt(vector4).ToVector4(), gradient.ColorAt(vector).ToVector4(), p);
}
}
}
private static Vector3 TerrainVertex(Vector3 origin, Vector3 direction, float radius, float yOffset)
{
float x = origin.X + direction.X * radius;
float z = origin.Z + direction.Z * radius;
float terrainYRaw = AxTerrainQuery.GetTerrainYRaw(x, z);
float y = (float.IsNaN(terrainYRaw) ? origin.Y : terrainYRaw) + yOffset;
return new Vector3(x, y, z);
}
private static Vector3 TerrainVertexBilinear(Vector3 a, Vector3 b, Vector3 c, Vector3 d, float u, float v, float yOffset)
{
Vector3 result = a * (1f - u) * (1f - v) + b * u * (1f - v) + c * u * v + d * (1f - u) * v;
float terrainYRaw = AxTerrainQuery.GetTerrainYRaw(result.X, result.Z);
float y = result.Y;
result.Y = (float.IsNaN(terrainYRaw) ? y : terrainYRaw) + yOffset;
return result;
}
private static Vector4 BilinearColorV4(Vector4 a, Vector4 b, Vector4 c, Vector4 d, float u, float v)
{
return a * (1f - u) * (1f - v) + b * u * (1f - v) + c * u * v + d * (1f - u) * v;
}
public void DrawFan(Vector3 center, float innerRadius, float outerRadius, float minAngle, float maxAngle, uint innerColor, uint outerColor, uint numSegments = 0u, AxDxParams p = default(AxDxParams))
{
if (!FanDegraded)
{
if (numSegments == 0)
{
numSegments = (uint)MathF.Max(4f, MathF.Ceiling(MathF.Abs(maxAngle - minAngle) * 16f));
}
numSegments = Math.Min(numSegments, 360u);
GetFanFills().Add(center, innerRadius, outerRadius, minAngle, maxAngle, innerColor.ToVector4(), outerColor.ToVector4(), numSegments, p);
}
else
{
DrawTriangleFan(center, innerRadius, outerRadius, minAngle, maxAngle, innerColor, outerColor, numSegments, p);
}
}
private FanFillShader.Data.Builder GetFanFills()
{
return _fanFillDynamicBuilder ?? (_fanFillDynamicBuilder = _fanFillDynamicData.Map(FrameRenderContext));
}
public void DrawStroke(List<Vector3> world, float thickness, uint color, bool closed = false, float dashLength = 0f, float gapLength = 0f, float dashOffset = 0f, uint? colorEnd = null, AxLineCap cap = AxLineCap.Butt, AxLineJoin join = AxLineJoin.None, AxDxParams p = default(AxDxParams))
{
if (!StrokeDegraded)
{
GetStroke().Add(world, thickness, color.ToVector4(), closed, dashLength, gapLength, dashOffset, colorEnd.HasValue ? new Vector4?(colorEnd.Value.ToVector4()) : ((Vector4?)null), (float)cap, (float)join, p);
}
}
public void DrawStroke(List<Vector3> world, ReadOnlySpan<float> thicknesses, uint color, bool closed = false, float dashLength = 0f, float gapLength = 0f, float dashOffset = 0f, uint? colorEnd = null, AxLineCap cap = AxLineCap.Butt, AxLineJoin join = AxLineJoin.None, AxDxParams p = default(AxDxParams))
{
if (!StrokeDegraded)
{
GetStroke().Add(world, thicknesses, color.ToVector4(), closed, dashLength, gapLength, dashOffset, colorEnd.HasValue ? new Vector4?(colorEnd.Value.ToVector4()) : ((Vector4?)null), (float)cap, (float)join, p);
}
}
private StrokeShader.Data.Builder GetStroke()
{
return _strokeDynamicBuilder ?? (_strokeDynamicBuilder = _strokeDynamicData.Map(FrameRenderContext));
}
public void DrawTexturedQuad(IntPtr textureSRV, Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint color)
{
DrawTexturedQuad(textureSRV, a, b, c, d, color, new Vector2(0f, 0f), new Vector2(1f, 1f));
}
public void DrawTexturedQuad(IntPtr textureSRV, Vector3 a, Vector3 b, Vector3 c, Vector3 d, uint color, Vector2 uvMin, Vector2 uvMax)
{
QuadBlitter.Data.Builder texturedQuads = GetTexturedQuads();
texturedQuads.SetTexture(textureSRV);
Vector4 color2 = color.ToVector4();
texturedQuads.Add(a, new Vector2(uvMin.X, uvMin.Y), color2);
texturedQuads.Add(b, new Vector2(uvMax.X, uvMin.Y), color2);
texturedQuads.Add(c, new Vector2(uvMax.X, uvMax.Y), color2);
texturedQuads.Add(a, new Vector2(uvMin.X, uvMin.Y), color2);
texturedQuads.Add(c, new Vector2(uvMax.X, uvMax.Y), color2);
texturedQuads.Add(d, new Vector2(uvMin.X, uvMax.Y), color2);
}
private QuadBlitter.Data.Builder GetTexturedQuads()
{
return _texturedQuadDynamicBuilder ?? (_texturedQuadDynamicBuilder = _texturedQuadDynamicData.Map(FrameRenderContext));
}
}