
using Godot;
using Godot.Collections;
using System.Collections.Generic;

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

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

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

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

    [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("Distortion Texture", "distortion")]
    [Export]
    public Texture2D distortionTexture;

    [Export]
    public Vector2 distortionTiling = Vector2.One;

    [Export]
    public Vector2 distortionOffset = Vector2.Zero;

    [Export]
    public Vector2 distortionScroll = Vector2.Zero;

    [Export]
    public TimeLine distortionScrollTimeLine;

    [Export]
    public float distortionScrollFPS = 60f;

    
    [Export]
    public RenderingDevice.SamplerFilter distortionFilter = RenderingDevice.SamplerFilter.Linear;

    [Export]
    public RenderingDevice.SamplerRepeatMode distortionRepeatMode = RenderingDevice.SamplerRepeatMode.Repeat;

    [Export]
    public ColorSpaceConversion distortionTextureConversion = ColorSpaceConversion.No_Conversion;
    
    [ExportGroup("Mask Texture", "mask")]
    [Export]
    public Texture2D maskTexture;

    [Export ]
    public Vector2 maskTiling = Vector2.One;

    [Export ]
    public Vector2 maskOffset = Vector2.Zero;

    [Export ]
    public Vector2 maskScroll = Vector2.Zero;

    [Export]
    public TimeLine maskScrollTimeLine;

    [Export]
    public float maskScrollFPS = 60f;

    [Export]
    public RenderingDevice.SamplerFilter maskFilter = RenderingDevice.SamplerFilter.Linear;

    [Export]
    public RenderingDevice.SamplerRepeatMode maskRepeatMode = RenderingDevice.SamplerRepeatMode.Repeat;

    [Export]
    public ColorSpaceConversion maskTextureConversion = ColorSpaceConversion.No_Conversion;

    RG_ScreenColorTexure screenColorTexture;
    RG_BufferTexture bufferTexture;    
    RG_ImageTexture distortionTextureInput;
    RG_ImageTexture maskTextureInput;

    CEG_Copy copy;
    RG_TextureDistortion distortion;    

    void Initialize()
    { 
      screenColorTexture = new RG_ScreenColorTexure( graph );
      bufferTexture = RG_BufferTexture.ScreenSize( graph );
      distortionTextureInput = new RG_ImageTexture( graph );
      maskTextureInput = new RG_ImageTexture( graph );

      copy = new CEG_Copy( graph );
      distortion = new RG_TextureDistortion( graph );

      graph.InitializeNodes();

      copy.SetTextureSlotInputs( screenColorTexture, bufferTexture );

      distortion.SetTextureSlotInputs( copy.output, copy.input );
      distortion.SetDistortionTextureSlotInputs( distortionTextureInput, maskTextureInput );
      
      distortion.distortion.sampler = context.Sampler( distortionFilter, distortionRepeatMode );
      distortion.mask.sampler = context.Sampler( maskFilter, maskRepeatMode );

      distortionTextureInput.SetImageTexture( distortionTexture );
      maskTextureInput.SetImageTexture( maskTexture );

      graph.SetProcessOrder(
        screenColorTexture, 
        bufferTexture, 
        distortionTextureInput,
        maskTextureInput,

        copy,
        distortion 
      );
      
    }

    RenderingDevice.SamplerFilter assignedfilterTop = RenderingDevice.SamplerFilter.Linear;
    RenderingDevice.SamplerRepeatMode assignedRepeatModeTop = RenderingDevice.SamplerRepeatMode.Repeat;

    RenderingDevice.SamplerFilter assignedfilterMask = RenderingDevice.SamplerFilter.Linear;
    RenderingDevice.SamplerRepeatMode assignedRepeatModeMask = RenderingDevice.SamplerRepeatMode.Repeat;


    protected override void ForAllViews()
    {
      // RJLog.Log( "FOR ALL:", distortionTexture, maskTexture );

      if ( assignedfilterTop != distortionFilter || assignedRepeatModeTop != distortionRepeatMode )
      {
        assignedfilterTop = distortionFilter;
        assignedRepeatModeTop = distortionRepeatMode;

        distortion.distortion.sampler = context.Sampler( assignedfilterTop, assignedRepeatModeTop );
      }

      if ( assignedfilterMask != maskFilter || assignedRepeatModeMask != maskRepeatMode )
      {
        assignedfilterMask = maskFilter;
        assignedRepeatModeMask = maskRepeatMode;

        distortion.mask.sampler = context.Sampler( assignedfilterMask, assignedRepeatModeMask );
      }

      distortionTextureInput.SetImageTexture( distortionTexture );
      maskTextureInput.SetImageTexture( maskTexture );

      // RJLog.Log(
      //    distortionTextureInput.GetTexture(), distortionTexture, 
      //    maskTextureInput.GetTexture(), maskTexture  
      // );

      var timeLine = TimeLineManager.Ensure( distortionScrollTimeLine );
      var timelinePosition = timeLine.position;

      if ( distortionScrollFPS > 0f )
      {
        float stepTime = 1.0f / distortionScrollFPS;
        timelinePosition = MathX.SnapFloored( timelinePosition, stepTime );
      }

      var scrollPosition = timelinePosition * distortionScroll;


      

      scrollPosition.X = MathX.Repeat( scrollPosition.X, 1.0f );
      scrollPosition.Y = MathX.Repeat( scrollPosition.Y, 1.0f );

      var timeLineMask = TimeLineManager.Ensure( maskScrollTimeLine );

      var timeLineMaskPosition = timeLineMask.position;

      if ( maskScrollFPS > 0f )
      {
        float stepTime = 1.0f / maskScrollFPS;
        timeLineMaskPosition = MathX.SnapFloored( timeLineMaskPosition, stepTime );
      }

      var scrollPositionMask = timeLineMaskPosition * maskScroll;
      scrollPositionMask.X = MathX.Repeat( scrollPositionMask.X, 1.0f );
      scrollPositionMask.Y = MathX.Repeat( scrollPositionMask.Y, 1.0f );

      distortion.constants.Set(        
        distortionTiling.ToVector4( distortionOffset + scrollPosition ),
        maskTiling.ToVector4( maskOffset + scrollPositionMask ),
        Vector4.Zero,
        Vector4.Zero,

        distortionAmount,
        blendAmount,
        1.0f + redShift,
        1.0f + greenShift,

        1.0f + blueShift,
        (float) smearingSteps,
        smearing,
        (float)(int)distortionTextureConversion,
        (float)(int)maskTextureConversion,
        0f,
        0f,
        0f

      );
    }

   
  }
}