using UnityEngine;
using UnityEngine.Rendering;

/// <summary>
/// 相机渲染管理类：单独控制每个相机的渲染
/// </summary>
public partial class CameraRenderer
{
    ScriptableRenderContext context;
    Camera camera;

    const string bufferName = "Render Camera";

    // 创建缓冲区
    CommandBuffer buffer = new CommandBuffer
    {
        name = bufferName
    };

    // 存储相机剔除后的结果
    CullingResults cullingResults;

    // 着色器标记ID
    static ShaderTagId unlitShaderTagId = new ShaderTagId("SRPDefaultUnlit");
    static ShaderTagId litShaderTagId = new ShaderTagId("CustomLit");

    Lighting lighting = new Lighting();

    /// <summary>
    /// 相机渲染
    /// </summary>
    /// <param name="context"></param>
    /// <param name="camera"></param>
    /// <param name="useDynamicBatching"></param>
    /// <param name="useGPUInstancing"></param>
    /// <param name="shadowSettings"></param>
    public void Render(ScriptableRenderContext context, Camera camera, bool useDynamicBatching, bool useGPUInstancing, bool useLightsPerObject, ShadowSettings shadowSettings)
    {
        this.context = context;
        this.camera = camera;
        // 设置buffer缓冲区的名字
        PrepareBuffer();
        // 在Game视图绘制的几何体也绘制到Scene视图中
        PrepareForSceneWindow();
        if (!Cull(shadowSettings.maxDistance))
        {
            return;
        }


        buffer.BeginSample(sampleName);
        ExecuteBuffer();
        lighting.Setup(context, cullingResults, shadowSettings, useLightsPerObject);
        buffer.EndSample(sampleName);
        Setup();

        // 绘制可见几何体
        DrawVisibleGeometry(useDynamicBatching, useGPUInstancing, useLightsPerObject);
        // 绘制SRP不支持的内置shader类型
        DrawUnsupportedShaders();
        // 绘制Gizmos
        DrawGizmos();
        // 释放申请的RT内存空间
        lighting.Cleanup();
        // 提交缓冲区
        Submit();
    }

    /// <summary>
    /// 剔除
    /// </summary>
    /// <returns></returns>
    bool Cull(float maxShadowDistance)
    {
        if (camera.TryGetCullingParameters(out ScriptableCullingParameters p))
        {
            p.shadowDistance = Mathf.Min(maxShadowDistance, camera.farClipPlane);
            cullingResults = context.Cull(ref p);
            return true;
        }
        return false;
    }

    /// <summary>
    /// 设置相机的属性和矩阵，在着色器中被称为unity_matrixvp
    /// </summary>
    void Setup()
    {
        context.SetupCameraProperties(camera);
        // 得到相机的clearflags
        CameraClearFlags flags = camera.clearFlags;
        // 设置相机清除状态
        buffer.ClearRenderTarget(flags <= CameraClearFlags.Depth, flags == CameraClearFlags.Color, flags == CameraClearFlags.Color ? camera.backgroundColor.linear : Color.clear);
        buffer.BeginSample(sampleName);
        ExecuteBuffer();
    }

    /// <summary>
    /// 提交缓冲区命令
    /// </summary>
    void Submit()
    {
        buffer.EndSample(sampleName);
        ExecuteBuffer();
        context.Submit();
    }

    /// <summary>
    /// 执行缓冲区命令
    /// </summary>
    void ExecuteBuffer()
    {
        context.ExecuteCommandBuffer(buffer);
        buffer.Clear();
    }

    /// <summary>
    /// 绘制可见几何体，顺序：不透明物体->天空盒->透明物体
    /// </summary>
    void DrawVisibleGeometry(bool useDynamicBatching, bool useGPUInstancing, bool useLightsPerObject)
    {
        PerObjectData lightsPerObjectFlags = useLightsPerObject ? PerObjectData.LightData | PerObjectData.LightIndices : PerObjectData.None;
        // 设置绘制顺序和指定渲染相机
        var sortingSettings = new SortingSettings(camera)
        {
            criteria = SortingCriteria.CommonOpaque
        };
        // 设置渲染的shader pass和渲染顺序
        var drawingSettings = new DrawingSettings(unlitShaderTagId, sortingSettings)
        {
            enableDynamicBatching = useDynamicBatching,
            enableInstancing = useGPUInstancing,
            perObjectData = PerObjectData.Lightmaps | PerObjectData.ShadowMask | PerObjectData.LightProbe | PerObjectData.OcclusionProbe | PerObjectData.LightProbeProxyVolume | PerObjectData.ReflectionProbes | lightsPerObjectFlags,
        };
        // 渲染CustomLit表示的pass块
        drawingSettings.SetShaderPassName(1, litShaderTagId);

        // 只绘制RenderQueue为opaque不透明物体
        var filteringSettings = new FilteringSettings(RenderQueueRange.opaque);

        // 绘制不透明物体
        context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);
        // 绘制天空盒
        context.DrawSkybox(camera);
        sortingSettings.criteria = SortingCriteria.CommonTransparent;
        drawingSettings.sortingSettings = sortingSettings;
        // 只绘制RenderQueue为transparent透明的物体
        filteringSettings.renderQueueRange = RenderQueueRange.transparent;
        // 绘制透明物体
        context.DrawRenderers(cullingResults, ref drawingSettings, ref filteringSettings);
    }
}
