
using Godot;

namespace Rokojori
{  
  [Tool]
  [GlobalClass]
  public partial class DepthOutlinesEffect:EdgeCompositorEffect
  {
    public DepthOutlinesEffect():base()
    {
      Initialize();
    } 

    [ExportGroup( "Main")]
    [Export( PropertyHint.Range, "0,1") ]
    public float amount = 1f;

    [Export( PropertyHint.Range, "-1,1") ]
    public float outlineWidth = 1f;

    [Export]
    public CurveTexture outlineWidthCurve = new CurveTexture().WithCurve( new Curve().WithValues( 0.5f, 0.5f ) ); 


    [Export]
    public Color edgeColor = Colors.Black;

    [Export( PropertyHint.Range, "0,1") ]
    public float edgeDistanceFade = 0.2f;

    [Export]
    public Color fillColor = new Color( 1.0f, 1.0f, 1.0f, 0.0f );

    [Export]
    public Vector2 rimOffset = Vector2.Zero;

    [Export]
    public float rimContrast = 1.0f;

    [Export( PropertyHint.Range, "0,1") ]
    public float rimStrength = 1.0f;

    [Export( PropertyHint.Range, "0,1") ]
    public float zEdgeAmount = 1f;

    [Export( PropertyHint.Range, "0,1") ]
    public float normalEdgeAmount = 1f;

    [Export( PropertyHint.Range, "0,1") ]
    public float normalEdgeAmountMin = 0.05f;

    [Export( PropertyHint.Range, "0,1") ]
    public float normalEdgeAmountMax = 0.15f;

    [Export]
    public float zTreshold = 0.1f;

    [Export]
    public CurveTexture zTresholdCurve = new CurveTexture().WithCurve( new Curve().WithValues( 1, 1 ) ); 

    [Export]
    public float edgeIntensity = 1f;

    [Export]
    public CurveTexture edgeIntensityCurve = new CurveTexture().WithCurve( new Curve().WithValues( 1, 1 ) ); 

    [Export( PropertyHint.Range, "0,1") ]
    public float adaptiveScaleAmount = 0.5f;

    [Export]
    public float adaptiveScaleNormalizer = 1f;

    [Export ]
    public Vector2 zInput = new Vector2( 0.1f, 4000f );

    [Export ]
    public Vector2 zOutput = new Vector2( 0f, 1f );


    RG_ScreenColorTexure screenColorTexture;
    RG_ScreenDepthTexture screenDepthTexture;
    RG_ScreenNormalRoughnessTexture screenNormalRoughnessTexture;
    RG_BufferTexture bufferTexture;  
    RG_ImageTexture zTresholdTexture;
    RG_ImageTexture edgeIntensityTexture;
    RG_ImageTexture outlineWidthTexture;

    RG_GenerateViewZ generateViewZ;


    RG_ZOutlines zOutlines;  


    void Initialize()
    { 
      screenColorTexture = new RG_ScreenColorTexure( graph );
      screenDepthTexture = new RG_ScreenDepthTexture( graph );
      screenNormalRoughnessTexture = new RG_ScreenNormalRoughnessTexture( graph );

      bufferTexture      = RG_BufferTexture.ScreenSize( graph );
      zTresholdTexture = new RG_ImageTexture( graph );
      edgeIntensityTexture = new RG_ImageTexture( graph );
      outlineWidthTexture = new RG_ImageTexture( graph );

      generateViewZ = new RG_GenerateViewZ( graph );

      zOutlines = new RG_ZOutlines( graph );


      graph.InitializeNodes();

      generateViewZ.SetTextureSlotInputs( screenDepthTexture, bufferTexture );
      generateViewZ.input.UseLinearSamplerEdgeClamped();

      zOutlines.SetTextureSlotInputs( screenColorTexture, screenColorTexture );
      zOutlines.input.UseLinearSampler();
      
      zOutlines.AddTextureSlotInput( bufferTexture ).UseLinearSamplerEdgeClamped();
      zOutlines.AddTextureSlotInput( zTresholdTexture ).UseLinearSamplerEdgeClamped();
      zOutlines.AddTextureSlotInput( edgeIntensityTexture ).UseLinearSamplerEdgeClamped();
      zOutlines.AddTextureSlotInput( screenNormalRoughnessTexture ).UseLinearSamplerEdgeClamped();
      zOutlines.AddTextureSlotInput( outlineWidthTexture ).UseLinearSamplerEdgeClamped();

   
      graph.SetProcessOrder(
        screenColorTexture, 
        screenDepthTexture,
        screenNormalRoughnessTexture,

        bufferTexture,
        zTresholdTexture,
        edgeIntensityTexture,

        generateViewZ,
        zOutlines
      );
      
    }


    protected override void ForAllViews()
    { 
      zTresholdTexture.SetImageTexture( zTresholdCurve );
      edgeIntensityTexture.SetImageTexture( edgeIntensityCurve );
      outlineWidthTexture.SetImageTexture( outlineWidthCurve );

      var projection = context.GetCameraProjection().Inverse();      


      generateViewZ.constants.Set(
        projection.X, 
        projection.Y,
        projection.Z,
        projection.W,

        zInput.X, 
        zInput.Y,
        zOutput.X,
        zOutput.Y
      );

      zOutlines.constants.Set(
        amount * edgeColor.A,
        edgeColor.R,
        edgeColor.G,
        edgeColor.B,

        zInput.X,
        zInput.Y,
        zTreshold,
        edgeIntensity,

        adaptiveScaleAmount,
        adaptiveScaleNormalizer,
        zEdgeAmount,
        normalEdgeAmount,

        normalEdgeAmountMin,
        normalEdgeAmountMax,
        rimOffset.X,
        rimOffset.Y,

        fillColor,

        rimContrast,
        rimStrength,
        Mathf.Pow( 10f, outlineWidth ),
        edgeDistanceFade
      );

      
    }

   
  }
}