Shader "ubu/processing/pix_dct8"
{
   Properties
   {
      [NoScaleOffset] _MainTex ("Texture", 2D) = "white" {}
      _Axis ("Axis", Integer) = 0
      _Stage ("Stage",Integer) = 0
      _Quantization( "Quantization Scale", Vector ) = ( 0.25, 1.0, 1.0 )
   }
   SubShader
   {
      // No culling or depth
      Cull Off ZWrite Off ZTest Always

      Pass
      {
         CGPROGRAM
         #pragma vertex vert
         #pragma fragment frag

         #include "UnityCG.cginc"

         struct appdata
         {
            float4 vertex : POSITION;
            float2 uv : TEXCOORD0;
         };

         struct v2f
         {
            float2 uv : TEXCOORD0;
            float4 vertex : SV_POSITION;
         };

         v2f vert (appdata v)
         {
            v2f o;
            o.vertex = UnityObjectToClipPos(v.vertex);
            o.uv = v.uv;
            return o;
         }

         sampler2D _MainTex;
         half4 _MainTex_TexelSize;
         int _Axis;
         int _Stage;
         float4 _Quantization;

static const float mdct[64] = {
0.707106769, 0.707106769, 0.707106769, 0.707106769, 0.707106769, 0.707106769, 0.707106769, 0.707106769, 
0.980785251, 0.831469595, 0.555570245, 0.195090324,-0.195090324,-0.555570245,-0.831469595,-0.980785251, 
0.923879504, 0.382683426,-0.382683426,-0.923879504,-0.923879504,-0.382683426, 0.382683426, 0.923879504, 
0.831469595,-0.195090324,-0.980785251,-0.555570245, 0.555570245, 0.980785251, 0.195090324,-0.831469595, 
0.707106769,-0.707106769,-0.707106769, 0.707106769, 0.707106769,-0.707106769,-0.707106769, 0.707106769, 
0.555570245,-0.980785251, 0.195090324, 0.831469595,-0.831469595,-0.195090324, 0.980785251,-0.555570245, 
0.382683426,-0.923879504, 0.923879504,-0.382683426,-0.382683426, 0.923879504,-0.923879504, 0.382683426, 
0.195090324,-0.555570245, 0.831469595,-0.980785251, 0.980785251,-0.831469595, 0.555570245,-0.195090324
};

static const float Q[64] =
{
16.0,11.0,10.0,16.0,24.0,40.0,51.0,61.0,
12.0,12.0,14.0,19.0,26.0,58.0,60.0,55.0,
14.0,13.0,16.0,24.0,40.0,57.0,69.0,56.0,
14.0,17.0,22.0,29.0,51.0,87.0,80.0,62.0,
18.0,22.0,37.0,56.0,68.0,109.0,103.0,77.0,
24.0,35.0,55.0,64.0,81.0,104.0,113.0,92.0,
49.0,64.0,78.0,87.0,103.0,121.0,120.0,101.0,
72.0,92.0,95.0,98.0,112.0,100.0,103.0,99.0
};
         fixed4 frag (v2f i) : SV_Target
         {
            float2 co = i.uv * _MainTex_TexelSize.zw;
            float2 grid = floor(co/8.0)*8.0;
            float2 uv = frac(co/8.0)*8.0;
            float3 s = float3(0,0,0);
            
            // DCT stage
            if( _Stage == 0 )
            {
               for( int j=0; j<8; j ++ )
               {
                  float2 p0 = grid + 0.5;
                  if( _Axis == 0 ) p0 += float2(j,floor(uv.y));
                  else             p0 += float2(floor(uv.x),j);
                  float3 c = tex2D( _MainTex, p0*_MainTex_TexelSize.xy ).rgb;
                  s += c*mdct[int(uv[_Axis])*8+j];
               }
            }
            // Inverse DCT stage
            else if( _Stage == 1 )
            {
               for( int j=0; j<8; j ++ )
               {
                  float2 p0 = grid + 0.5;
                  if( _Axis == 0 ) p0 += float2( j, uv.y-0.5 );
                  else             p0 += float2( uv.x-0.5, j );
                  float3 c = tex2D( _MainTex, p0*_MainTex_TexelSize.xy ).rgb;
                  s += c*mdct[j*8+int(uv[_Axis])];
               }
            }
            // Quantize stage
            else if( _Stage == 2 )
            {
               float3 c = tex2D( _MainTex, i.uv ).rgb;
               float3 q = Q[int(uv.x) + int(uv.y)*8]*_Quantization.xyz;
               if( _Axis == 0 ) c /= q;
               else             c *= q;
               return float4(c,1.0);
            }

            if( _Axis == 1 )
               s *= 0.25;
            
            return float4( s, 1.0 );
         }
         ENDCG
      }
   }
}
