% Copyright 2019 by Till Tantau and others
% CMYK and grayscale shadings adaptation copyright 2019 by David Purton
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Public License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.

\ProvidesFileRCS{pgflibraryshadings.code.tex}


%
% An hsv color wheel. Initial code graciously donated by Ken Starks.
%

\pgfdeclarefunctionalshading[black]{color wheel white center}
{\pgfpoint{-50bp}{-50bp}}
{\pgfpoint{50bp}{50bp}}
{}
{ % x y
  2 copy % ... x y x y
  2 copy abs exch abs add 0.0001 ge
  {atan 360.0 div} % ... x y heading;  heading being in
                   %the interval [0, 1.0]
  { pop } % silently deal with error: return
                  % arbitrary heading of zero for origin
  ifelse  % because we will use it for 'Hue'
  3 1 roll % ... heading x y
  dup mul % ... heading x y*y
  exch dup mul % ... heading y*y x*x
  add sqrt % ... heading ra_pt (distance from origin in points)
  25.0 div % scale it means a ra of 25bp
  dup 1.0 ge % BOOLEAN. ready to clamp to interval [0, 1.0]
  { pop 1.0 }{} ifelse % We shall use the scaled ra as 'Saturation'
  %2.5 mul 0.25 sub % now, Ra in [0.1, 0.5] --> Saturation
                   % in [0.0, 1.0]. Saturation varies between the two radii
  1.0 % ... H S V ( with 'Value' set to literal constant of 1.0 )
  % C version to use as model:
  % H' = H * 6
  % i = floor(H')
  % f = H' - i
  % P = V * (1.0 - S)
  % Q = V * (1.0 - (S*f))
  % T = V * (1.0 - (S * (1.0 - f)))
  3 2 roll 6.0 mul dup 4 1 roll % H' S V H'
  floor cvr  % H' S V i
  dup 5 1 roll % i H' S V i
  3 index sub neg % i H' S V f
  1.0 3 index sub % i H' S V f (1.0 - S )
  2 index mul % i H' S V f P
  6 1 roll % P i H' S V f
  dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S))
  2 index mul % P i H' S V f Q
  7 1 roll % Q P i H' S V f
  neg 1.0 add % Q P i H' S V (1.0 - f)
  2 index mul neg 1.0  add % Q P i H' S V (1.0 - S * (1.0 - f))
  1 index mul % Q P i H' S V T
  7 2 roll % V T Q P i H' S
  pop pop % V T Q P i
  %%%
  % end of BLOCK B. The rest is just stack manipulation
  dup 0.5 le % TEST II [ i == 0 ]
  { % BLOCK C [ take stack to V T P ]
    pop exch pop
  }
  { dup 1.5 le % TEST III [ i == 1 ]
    { % BLOCK D [ take stack to Q V P ]
      pop exch 4 1 roll exch pop
    }
    { dup 2.5 le % TEST IV [ i == 2 ]
      { % BLOCK E [ take stack to P V T ]
        pop 4 1 roll pop
      }
      { dup 3.5 le % TEST V [ i == 3 ]
        { % BLOCK F [ take stack to P Q V ]
          pop exch 4 2 roll pop
        }
        { dup 4.5 le % TEST VI [ i == 4 ]
          { % BLOCK G [ take stack to T P V ]
            pop exch pop 3 -1 roll
          }
          { % BLOCK H [ take stack to V P Q ]
            pop 3 1 roll exch pop
          }
          ifelse
        }
        ifelse % for V
      }
      ifelse % for IV
    }
    ifelse % for III
  }
  ifelse % for II
  \ifpgfshadingmodelcmyk
    \pgffuncshadingrgbtocmyk
  \fi
  \ifpgfshadingmodelgray
    \pgffuncshadingrgbtogray
  \fi
}%

\pgfdeclarefunctionalshading[black]{color wheel black center}
{\pgfpoint{-50bp}{-50bp}}
{\pgfpoint{50bp}{50bp}}
{}
{ % x y
  2 copy % ... x y x y
  2 copy abs exch abs add 0.0001 ge
  {atan 360.0 div} % ... x y heading;  heading being in
                   %the interval [0, 1.0]
  { pop } % silently deal with error: return
                  % arbitrary heading of zero for origin
  ifelse  % because we will use it for 'Hue'
  3 1 roll % ... heading x y
  dup mul % ... heading x y*y
  exch dup mul % ... heading y*y x*x
  add sqrt % ... heading ra_pt (distance from origin in points)
  25.0 div % scale it means a ra of 25bp
  dup 1.0 ge % BOOLEAN. ready to clamp to interval [0, 1.0]
  { pop 1.0 }{} ifelse % We shall use the scaled ra as 'Saturation'
  %2.5 mul 0.25 sub % now, Ra in [0.1, 0.5] --> Saturation
                   % in [0.0, 1.0]. Saturation varies between the two radii
  1.0 exch % ... H S V ( with 'Value' set to literal constant of 1.0 )
  % C version to use as model:
  % H' = H * 6
  % i = floor(H')
  % f = H' - i
  % P = V * (1.0 - S)
  % Q = V * (1.0 - (S*f))
  % T = V * (1.0 - (S * (1.0 - f)))
  3 2 roll 6.0 mul dup 4 1 roll % H' S V H'
  floor cvr  % H' S V i
  dup 5 1 roll % i H' S V i
  3 index sub neg % i H' S V f
  1.0 3 index sub % i H' S V f (1.0 - S )
  2 index mul % i H' S V f P
  6 1 roll % P i H' S V f
  dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S))
  2 index mul % P i H' S V f Q
  7 1 roll % Q P i H' S V f
  neg 1.0 add % Q P i H' S V (1.0 - f)
  2 index mul neg 1.0  add % Q P i H' S V (1.0 - S * (1.0 - f))
  1 index mul % Q P i H' S V T
  7 2 roll % V T Q P i H' S
  pop pop % V T Q P i
  %%%
  % end of BLOCK B. The rest is just stack manipulation
  dup 0.5 le % TEST II [ i == 0 ]
  { % BLOCK C [ take stack to V T P ]
    pop exch pop
  }
  { dup 1.5 le % TEST III [ i == 1 ]
    { % BLOCK D [ take stack to Q V P ]
      pop exch 4 1 roll exch pop
    }
    { dup 2.5 le % TEST IV [ i == 2 ]
      { % BLOCK E [ take stack to P V T ]
        pop 4 1 roll pop
      }
      { dup 3.5 le % TEST V [ i == 3 ]
        { % BLOCK F [ take stack to P Q V ]
          pop exch 4 2 roll pop
        }
        { dup 4.5 le % TEST VI [ i == 4 ]
          { % BLOCK G [ take stack to T P V ]
            pop exch pop 3 -1 roll
          }
          { % BLOCK H [ take stack to V P Q ]
            pop 3 1 roll exch pop
          }
          ifelse
        }
        ifelse % for V
      }
      ifelse % for IV
    }
    ifelse % for III
  }
  ifelse % for II
  \ifpgfshadingmodelcmyk
    \pgffuncshadingrgbtocmyk
  \fi
  \ifpgfshadingmodelgray
    \pgffuncshadingrgbtogray
  \fi
}%

\pgfdeclarefunctionalshading[black]{color wheel}
{\pgfpoint{-50bp}{-50bp}}
{\pgfpoint{50bp}{50bp}}
{}
{ % x y
  2 copy abs exch abs add 0.0001 ge
  {atan 360.0 div} % ... x y heading;  heading being in
                   %the interval [0, 1.0]
  { pop } % silently deal with error: return
                  % arbitrary heading of zero for origin
  ifelse  % because we will use it for 'Hue'
  1.0 1.0 % ... H S V
  % C version to use as model:
  % H' = H * 6
  % i = floor(H')
  % f = H' - i
  % P = V * (1.0 - S)
  % Q = V * (1.0 - (S*f))
  % T = V * (1.0 - (S * (1.0 - f)))
  3 2 roll 6.0 mul dup 4 1 roll % H' S V H'
  floor cvr  % H' S V i
  dup 5 1 roll % i H' S V i
  3 index sub neg % i H' S V f
  1.0 3 index sub % i H' S V f (1.0 - S )
  2 index mul % i H' S V f P
  6 1 roll % P i H' S V f
  dup 3 index mul neg 1.0 add % P i H' S V f ( 1.0 - (f*S))
  2 index mul % P i H' S V f Q
  7 1 roll % Q P i H' S V f
  neg 1.0 add % Q P i H' S V (1.0 - f)
  2 index mul neg 1.0  add % Q P i H' S V (1.0 - S * (1.0 - f))
  1 index mul % Q P i H' S V T
  7 2 roll % V T Q P i H' S
  pop pop % V T Q P i
  %%%
  % end of BLOCK B. The rest is just stack manipulation
  dup 0.5 le % TEST II [ i == 0 ]
  { % BLOCK C [ take stack to V T P ]
    pop exch pop
  }
  { dup 1.5 le % TEST III [ i == 1 ]
    { % BLOCK D [ take stack to Q V P ]
      pop exch 4 1 roll exch pop
    }
    { dup 2.5 le % TEST IV [ i == 2 ]
      { % BLOCK E [ take stack to P V T ]
        pop 4 1 roll pop
      }
      { dup 3.5 le % TEST V [ i == 3 ]
        { % BLOCK F [ take stack to P Q V ]
          pop exch 4 2 roll pop
        }
        { dup 4.5 le % TEST VI [ i == 4 ]
          { % BLOCK G [ take stack to T P V ]
            pop exch pop 3 -1 roll
          }
          { % BLOCK H [ take stack to V P Q ]
            pop 3 1 roll exch pop
          }
          ifelse
        }
        ifelse % for V
      }
      ifelse % for IV
    }
    ifelse % for III
  }
  ifelse % for II
  \ifpgfshadingmodelcmyk
    \pgffuncshadingrgbtocmyk
  \fi
  \ifpgfshadingmodelgray
    \pgffuncshadingrgbtogray
  \fi
}%


%
% A bilinear interpolation.
%

\colorlet{lower left}{white}%
\colorlet{lower right}{white}%
\colorlet{upper left}{white}%
\colorlet{upper right}{white}%

\pgfdeclarefunctionalshading[lower left,lower right,upper left,upper right]{bilinear interpolation}
{\pgfpointorigin}
{\pgfpoint{100bp}{100bp}}
{
  \pgfshadecolortorgb{lower left}{\pgf@lib@shadings@ll}\pgfshadecolortorgb{lower right}{\pgf@lib@shadings@lr}
  \pgfshadecolortorgb{upper right}{\pgf@lib@shadings@ur}\pgfshadecolortorgb{upper left}{\pgf@lib@shadings@ul}
}{
  25 sub 50 div exch 25 sub 50 div 2 copy                   % Calculate y/100 x/100.
%  100 div exch 100 div 2 copy                   % Calculate y/100 x/100.
  neg 1 add exch neg 1 add                      % Calculate 1-y/100 1-x/100.
  3 1 roll 2 copy exch 5 2 roll 6 copy 6 copy   % Set up stack.
  \pgf@lib@shadings@llred mul exch \pgf@lib@shadings@lrred mul add mul     % Process red component.
  4 1 roll
  \pgf@lib@shadings@urred mul exch \pgf@lib@shadings@ulred mul add mul
  add
  13 1 roll
  \pgf@lib@shadings@llgreen mul exch \pgf@lib@shadings@lrgreen mul add mul % Process green component.
  4 1 roll
  \pgf@lib@shadings@urgreen mul exch \pgf@lib@shadings@ulgreen mul add mul
  add
  7 1 roll
  \pgf@lib@shadings@llblue mul exch \pgf@lib@shadings@lrblue mul add mul   % Process blue component.
  4 1 roll
  \pgf@lib@shadings@urblue mul exch \pgf@lib@shadings@ulblue mul add mul
  add
  \ifpgfshadingmodelcmyk
    \pgffuncshadingrgbtocmyk
  \fi
  \ifpgfshadingmodelgray
    \pgffuncshadingrgbtogray
  \fi
}%


%
% A Mandelbrot set shading. Just for fun...
%

\pgfdeclarefunctionalshading[black]{Mandelbrot set}
{\pgfpoint{-50bp}{-50bp}}
{\pgfpoint{50bp}{50bp}}{}
{
  12.5 div exch 12.5 div exch
  1 index 1 index
  % Stack: c_r c_i z_r z_i
  % Formula: z' = z^2 + c = (z_r + i z_i)^2 + c_r + i c_i
  %             = (z_r^2 - z_i^2 + c_r) + i (2 z_r z_i + c_i)
  %
  % First iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Second iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Third iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Fourth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Check for break (to avoid too large numbers)
  1 index dup mul 1 index dup mul add
  4 lt {
  % Fifth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Sixth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Seventh iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Check for break (to avoid too large numbers)
  1 index dup mul 1 index dup mul add
  4 lt {
  % Eighth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Ninth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  % Tenth iteration
  % 1. Compute z_r^2 -z_i^2 + c_r
  1 index dup mul % z_r^2
  1 index dup mul % z_i^2
  sub             % z_r^2 - z_i^2
  4 index add     % z_r^2 -z_i^2 + c_r
  % 2. Compute 2 z_r z_i + c_i
  3 1 roll
  mul 2 mul       % 2 z_r z_i
  2 index add     % 2 z_r z_i + c_i
  } { pop pop 1000.0 1000.0 } ifelse
  } { pop pop 1000.0 1000.0 } ifelse
  % Compute distance
  dup mul exch
  dup mul
  add sqrt
  dup 4 1 roll
  2 gt { pop pop 2.0 exch div 1.0 exch sub dup dup} {pop pop pop 0.0 0.0 0.0} ifelse
  \ifpgfshadingmodelcmyk
    \pgffuncshadingrgbtocmyk
  \fi
  \ifpgfshadingmodelgray
    \pgffuncshadingrgbtogray
  \fi
}%
