
using Godot;
using System.Collections.Generic;

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

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

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

    [Export( PropertyHint.Range, "0,1") ]
    public Vector2 ringSizeScale = Vector2.One;


    [Export( PropertyHint.Range, "4,64") ]
    public int ringResolution;

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

    [Export]
    public Vector2 zRange = new Vector2( 10, 200 );

    [Export]
    public CurveTexture zMapping = new CurveTexture().WithCurve( new Curve().WithValues( 0f, 1f, 0f ) ).
                                                      WithResolution( 64 );

    [ExportGroup( "Smearing")]
    [Export( PropertyHint.Range, "0,0.5") ]
    public float distortionAmount = 0.1f;

    [Export( PropertyHint.Range, "1,32") ]
    public int smearingSteps = 5;

    [Export( PropertyHint.Range, "1,1.5") ]
    public float smearing = 1.1f;

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

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

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

    [ExportGroup( "Luma")]
    [Export]
    public Vector2 lumaInputRange = new Vector2( 0.5f, 1.5f ); 

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

    [Export]
    public Vector2 lumaOutputRange = new Vector2( 0f, 1.5f ); 

    [Export]
    public float desaturation = 1f;
    
    [Export]
    public Color lumaTint = Colors.White;


     int _downSampling = 16;

    public enum DownSampling
    {
      _1x_,
      _2x_,
      _4x_,
      _8x_,
      _16x_,
      _32x_            
    }

    public int downSamplingRate => Mathf.RoundToInt( Mathf.Pow( 2, (int) downSampling ) );

    [Export]
    public DownSampling downSampling = DownSampling._4x_;


    RG_ScreenColorTexure screenColorTexture;
    RG_ScreenDepthTexture screenDepthTexture;
    RG_BufferTexture bufferTexture;  
    RG_ImageTexture zMappingTexture;
    
    RG_ExtractGlowLine extractGlowLine;

    int maxBlooms = 3;


    RG_RingBloom bloom;  


    void Initialize()
    { 
      screenColorTexture = new RG_ScreenColorTexure( graph );
      screenDepthTexture = new RG_ScreenDepthTexture( graph );
      bufferTexture = RG_BufferTexture.ScreenSize( graph, Vector2.One / (float) _downSampling  );
      zMappingTexture = new RG_ImageTexture( graph );

      extractGlowLine = new RG_ExtractGlowLine( graph );

      bloom = new RG_RingBloom( graph );


      graph.InitializeNodes();

      extractGlowLine.SetTextureSlotInputs( screenColorTexture, bufferTexture );
      extractGlowLine.AddSampledTextureSlotInput( screenDepthTexture );
      extractGlowLine.AddSampledTextureSlotInput( zMappingTexture );

      extractGlowLine.input.UseSampler();

     

      bloom.SetTextureSlotInputs( bufferTexture, screenColorTexture );
      bloom.input.UseSampler();


   
      graph.SetProcessOrder(
        screenColorTexture, 
        screenDepthTexture,
        bufferTexture,
        zMappingTexture,
        extractGlowLine,
        bloom
      );
      
    }


    protected override void ForAllViews()
    { 
      if ( downSamplingRate != _downSampling )
      {
        _downSampling = downSamplingRate;
        ( bufferTexture.GetCreator() as CEG_TextureCreator_ScreenSize ).scale = Vector2.One / (float) _downSampling;
      }

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

      extractGlowLine.SetCustomComputeSize( context.internalSize / _downSampling  );
      zMappingTexture.SetImageTexture( zMapping );

      extractGlowLine.constants.Set(

        projection.X, 
        projection.Y,
        projection.Z,
        projection.W,

        lumaInputRange.X, 
        lumaInputRange.Y,
        Mathf.Pow( 10, lumaNormalizationPower ),
        lumaOutputRange.X,

        lumaOutputRange.Y,
        desaturation,
        lumaTint.R,
        lumaTint.G,

        lumaTint.B,
        zRange.X,
        zRange.Y,
        0f
      );

      

      bloom.constants.Set(

        amount,
        1.0f + redShift,
        1.0f + greenShift,
        1.0f + blueShift,

        (float) smearingSteps,
        smearing,
        (float) ringResolution,
        ringSizeXY * ringSizeScale.X,

        ringSizeXY * ringSizeScale.Y,
        distortionAmount,
        blendMode,
        0f
       
        
      );
    

      
    }

   
  }
}