% Feta (not the Font-En-Tja) music font --  Accidentals
% This file is part of LilyPond, the GNU music typesetter.
%
% Copyright (C) 1997--2022 Han-Wen Nienhuys <hanwen@xs4all.nl>
% Copyright (C) 2013--2022 Janek Warchoł <lemniskata.bernoullego@gmail.com>
%
% The LilyPond font is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version, or you can redistribute it under
% the SIL Open Font License.
%
% LilyPond is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with LilyPond.  If not, see <http://www.gnu.org/licenses/>.

%
% Dedicated to my mom.    (3/10/97)
%
% Mamma, ik hou van je; kom je alsjeblieft terug?
%    -- HW
%
%
% TODO: remove crook_fatness
% TODO: document, simplify!
%

def draw_meta_flat (expr xcenter, glyph_width, crook_fatness,
                         arrowup, arrowdown, smaller_hole, figured_bass) =
  save x_offset, y_offset;
  save crook_thinness;
  save bottom_overshoot, bot_crook_dir;
  save top_stem_thick, top_stem_thick_orig;
  save bottom_stem_thick, hair, hole_adjustment;
  save top_crook_thinness;
  save zwiep;
  pair bot_crook_dir;
  save clearing, clearing_orig;

  clearxy;

  % the stem shouldn't reach the top staff line.
  %% TODO: should take from height.

  if smaller_hole:
    hole_adjustment = 0;
  else:
    hole_adjustment = 0.35 stafflinethickness;
  fi;
  crook_thinness = .7 stafflinethickness + .06 staff_space;
  top_crook_thinness = 1 stafflinethickness + .065 staff_space;
  clearing = 1.7 stafflinethickness;
  clearing_orig = clearing;
  if arrowup:
    clearing := 0.5 staff_space;
  fi;
  bottom_overshoot = stafflinethickness;

  bottom_stem_thick# = 0.06 staff_space# + 0.6 stafflinethickness#;
  top_stem_thick# = 0.1 staff_space# + 1.2 stafflinethickness#;
  top_stem_thick_orig# = top_stem_thick#;
  if arrowup:
    % to look nice, arrowed stems should be less brushed
    top_stem_thick# := top_stem_thick# * 0.8;
  fi;
  define_whole_blacker_pixels (bottom_stem_thick, top_stem_thick,
                               top_stem_thick_orig);

  if odd (top_stem_thick - bottom_stem_thick):
    top_stem_thick := top_stem_thick - 1;
  fi;
  if odd (top_stem_thick_orig - bottom_stem_thick):
    top_stem_thick_orig := top_stem_thick_orig - 1;
  fi;

  if figured_bass:
    % left-align
    if xcenter = -1:
      x_offset := hround (.5 top_stem_thick);
    % right-align
    elseif xcenter = 1:
      x_offset := hround (w - glyph_width);
    % center
    else:
      x_offset := hround ((w - glyph_width) / 2 + .25 top_stem_thick);
    fi;
  else:
    x_offset := xcenter;
  fi;

  % z16 and the `*_orig' variables are needed for arrowed accidentals
  % because their inner part should be unchanged from plain ones but
  % the points z3l, z3r, and z10 depend on values that are different
  % for arrowed accidentals
  x1l = hround (x_offset - .5 top_stem_thick);
  x2l = hround (x_offset - .5 bottom_stem_thick);
  x16l = hround (x_offset - .5 top_stem_thick_orig);

  if figured_bass:
    y1 = y16 = h;
    y2 = 0;

    y_offset := .5 (staff_space + stafflinethickness)
               + bottom_overshoot - d;
  else:
    y1 = vround (2 staff_space - clearing);
    y2 = -.5 (staff_space + stafflinethickness);
    y16 = vround (2 staff_space - clearing_orig);

    y_offset := 0;
  fi;

  penpos1 (top_stem_thick, 0);
  penpos16 (top_stem_thick_orig, 0);
  penpos2 (bottom_stem_thick, 0);

  y3l = vfloor (.5 (staff_space - stafflinethickness) + y_offset);
  z3l = whatever [z2r, z1r];
  z3r = .3 [z2r,
            (z16r shifted (0, clearing_orig - 1.7 stafflinethickness))]
        + (hole_adjustment, 0);
  x3r := hceiling x3r;

  % we insert z3l to get better conversion with mf2pt1
  fill simple_serif (z1r, z1l, 30)
       -- z2l
       -- z2r
       -- z3l
       -- cycle;

  z10 = whatever [z2r, z16r] + (hole_adjustment, 0);
  y10 = -1/10 staff_space + y_offset;
  x10 := hceiling x10;

  x11 = x_offset + bottom_overshoot / 3;
  y11 = -vround (.5 (staff_space + stafflinethickness)
                 + bottom_overshoot - y_offset);

  x2a = 0.2[x2r, x7];
  y2a = 1.5[y2, y11];

  penpos4 (whatever, 53);

  y4l - y4r = top_crook_thinness;
  y5r = .15 staff_space + y_offset;
  x5l = hround (glyph_width + x_offset);
  y4 = staff_space / 2 + y_offset;
  x4r = .45 [x5r, x3r];
  y4l := vround y4l;

  penpos5 (crook_fatness, -175);

  bot_crook_dir = unitvector ((x5l, y_offset) - z11);
  z8 = z11 + whatever * bot_crook_dir;
  y8 = -staff_space / 2 + y_offset;

  z7 = z8
       + whatever * bot_crook_dir
       + crook_thinness * (bot_crook_dir rotated 90);
  x7 = .1 [x3r, x8];

  unfill z3r{z3r - z10}
         .. z4r{right}
         .. z5r{down}
         .. z7{-bot_crook_dir}
         & z7
         .. z10{z3r - z10}
         -- cycle;

  if arrowdown:
    fill z2l{down}
         .. z2a{up}
         .. z8{bot_crook_dir}
         .. z5l{up}
         .. z4l{left}
         .. z3l
         -- cycle;
  else:
    fill z2l{down}
         .. z11{right}
         .. z8{bot_crook_dir}
         .. z5l{up}
         .. z4l{left}
         .. z3l
         -- cycle;
  fi;

  if arrowup:
    fill draw_arrow (z1, top_stem_thick, z1l - z2l,
                     0.5 stafflinethickness, false)
         -- cycle;
  fi;
  if arrowdown:
    fill draw_arrow ((0.5 [x2l, x2a], y2), x2a - x2l, up,
                     staff_space / 2, true)
         -- cycle;
  fi;
enddef;


def draw_arrowed_meta_flat (expr arrowup, arrowdown, figured_bass) =
  save width, depth, height, breapth;
  save glyph_width;

  if figured_bass:
    width# := figbass_width#;
    % synchronized with vertical position of point z11 but with less overshoot
    depth# := figbass_y#;
    % synchronized with vertical position of point z1
    height# := number_design_size + figbass_y#;
    breapth# := 0;

    glyph_width# := 0.7 width#;
  else:
    width# := 0.8 staff_space#;
    % synchronized with vertical position of point z11 but with less overshoot
    depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
    % synchronized with vertical position of point z1
    height# := 2 staff_space# - 1.7 stafflinethickness#;
    breapth# := 1.2 stafflinethickness#;

    glyph_width# := width#;
  fi;
  define_whole_pixels (glyph_width);

  if arrowup:
    % synchronized with point z4 of the arrow
    height# := 2 staff_space# - .5 staff_space#           % y1
               + .1 staff_space# + .5 stafflinethickness# % upshift
               + .85 staff_space# + stafflinethickness#;  % htip
    breapth# := .3 staff_space#;
  fi;

  if arrowdown:
    % synchronized with point z4 of the arrow
    depth# := .5 staff_space# + .5 stafflinethickness#  % y2
              + .1 staff_space# + .5 staff_space#       % upshift
              + .85 staff_space# + stafflinethickness#; % htip
    breapth# := .3 staff_space#;
  fi;

  set_char_box (breapth#, width#, depth#, height#);
  draw_meta_flat (0, glyph_width, 0.31 staff_space,
                  arrowup, arrowdown, false, figured_bass);
enddef;

%
% unfortunately, 600dpi is not enough to show the brush of the stem.
%

fet_beginchar ("flat", "flat");
  draw_arrowed_meta_flat (false, false, false);
  penlabels (range 0 thru 16);
  labels (2a);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("figured bass flat", "flat.figbass");
  draw_arrowed_meta_flat (false, false, true);
  penlabels (range 0 thru 16);
  labels (2a);
fet_endchar;


fet_beginchar ("arrowed flat (arrow up)", "flat.arrowup");
  draw_arrowed_meta_flat (true, false, false);
  penlabels (range 0 thru 23);
  labels (2a);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("arrowed flat (arrow down)", "flat.arrowdown");
  draw_arrowed_meta_flat (false, true, false);
  penlabels (range 0 thru 23);
  labels (2a);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("arrowed flat (arrow up and down)", "flat.arrowboth");
  draw_arrowed_meta_flat (true, true, false);
  penlabels (range 0 thru 23);
  labels (2a);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("flat (slashed)", "flat.slash");
  save depth, height;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  % use same value for breapth as for arrowed flats
  set_char_box (.3 staff_space#, .8 staff_space#, depth#, height#);

  draw_meta_flat (0, w, 0.31 staff_space, false, false, false, false);

  clearxy;

  save slope, slash_width;
  slope = 0.5;
  slash_width = w;

  z11 = (0, staff_space_rounded);
  z12 = z11 - (slash_width, slash_width * slope) / 2;
  z13 = z11 + (slash_width, slash_width * slope) / 2;
  penpos12 (1.5 stafflinethickness, angle (z13 - z12) - 90);
  penpos13 (1.5 stafflinethickness, angle (z13 - z12) - 90);

  z14 = z12 - .75 stafflinethickness * unitvector (z13 - z12);
  z15 = z13 + .75 stafflinethickness * unitvector (z13 - z12);

  fill z13r
       .. z15
       .. z13l
       -- z12l
       .. z14
       .. z12r
       -- z13r
       .. cycle;

  penlabels (12, 13);
  labels (11, 14, 15);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("flat (slashed twice)", "flat.slashslash");
  save depth, height;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  % use same value for breapth as for arrowed flats
  set_char_box (.3 staff_space#, .8 staff_space#, depth#, height#);

  draw_meta_flat (0, w, 0.31 staff_space, false, false, false, false);

  clearxy;

  save slope, slash_width, slash_distance;
  slope = 0.5;
  slash_width = w;
  slash_distance = vround (.5 staff_space_rounded);

  z11 = (0, staff_space_rounded - .5 slash_distance);
  z12 = z11 - (slash_width, slash_width * slope) / 2;
  z13 = z11 + (slash_width, slash_width * slope) / 2;
  penpos12 (1.5 stafflinethickness, angle (z13 - z12) - 90);
  penpos13 (1.5 stafflinethickness, angle (z13 - z12) - 90);

  z14 = z12 - .75 stafflinethickness * unitvector (z13 - z12);
  z15 = z13 + .75 stafflinethickness * unitvector (z13 - z12);

  fill z13r
       .. z15
       .. z13l
       -- z12l
       .. z14
       .. z12r
       -- z13r
       .. cycle;

  penlabels (12, 13);
  labels (11, 14, 15);

  z21 = (0, staff_space_rounded + .5 slash_distance);
  z22 = z21 - (slash_width, slash_width * slope) / 2;
  z23 = z21 + (slash_width, slash_width * slope) / 2;
  penpos22 (1.5 stafflinethickness, angle (z23 - z22) - 90);
  penpos23 (1.5 stafflinethickness, angle (z23 - z22) - 90);

  z24 = z22 - .75 stafflinethickness * unitvector (z23 - z22);
  z25 = z23 + .75 stafflinethickness * unitvector (z23 - z22);

  fill z23r
       .. z25
       .. z23l
       -- z22l
       .. z24
       .. z22r
       -- z23r
       .. cycle;

  penlabels (22, 23);
  labels (21, 24, 25);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("flatflat (mirrored)", "mirroredflat.flat");
  save depth, height;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  set_char_box (0, 1.6 staff_space#, depth#, height#);

  % This is a modified version of `draw_meta_flat'.

  save crook_thinness, crook_fatness;
  save bottom_overshoot, bot_crook_dir;
  save top_stem_thick, bottom_stem_thick, hair, hole_adjustment;
  save top_crook_thinness;
  save zwiep;
  pair bot_crook_dir;
  save clearing, wid;
  save mirror_offset;
  save pat;
  path pat;

  clearxy;

  wid = w / 2;

  % the stem shouldn't reach the top staff line.
  %% TODO: should take from height.

  hole_adjustment = 0.35 stafflinethickness;
  clearing = 1.7 stafflinethickness;
  crook_thinness = .7 stafflinethickness + .06 staff_space;
  crook_fatness = 0.31 staff_space;
  top_crook_thinness = 1 stafflinethickness + .065 staff_space;
  bottom_overshoot = stafflinethickness;

  bottom_stem_thick# = 0.06 staff_space# + 0.6 stafflinethickness#;
  top_stem_thick# = 0.1 staff_space# + 1.2 stafflinethickness#;
  define_whole_blacker_pixels (bottom_stem_thick, top_stem_thick);

  if odd (top_stem_thick - bottom_stem_thick):
    top_stem_thick := top_stem_thick - 1;
  fi;
  if odd top_stem_thick:
    mirror_offset := 1;
  else:
    mirror_offset := 0;
  fi;

  x1l = hround (-.5 top_stem_thick);
  y1 = vround (2 staff_space - clearing);
  x2l = hround (-.5 bottom_stem_thick);
  y2 = -.5 staff_space - .5 stafflinethickness;

  penpos1 (top_stem_thick, 0);
  penpos2 (bottom_stem_thick, 0);

  y3l = vfloor ((staff_space - stafflinethickness) / 2);
  z3l = whatever [z2r, z1r];
  z3r = .3 [z2r, z1r] + (hole_adjustment, 0);
  x3r := hceiling x3r;

  z10 = whatever [z2r, z1r] + (hole_adjustment, 0);
  y10 = -1/10 staff_space;
  x10 := hceiling x10;

  x11 = bottom_overshoot / 3;
  y11 = -vround (.5 (staff_space + stafflinethickness)
                 + bottom_overshoot);

  penpos4 (whatever, 53);

  y4l - y4r = top_crook_thinness;
  y5r = .15 staff_space;
  x5l = hround (wid);
  y4 = staff_space / 2;
  x4r = .45 [x5r, x3r];
  y4l := vround y4l;

  penpos5 (crook_fatness, -175);

  bot_crook_dir = unitvector ((x5l, 0) - z11);
  z8 = z11 + whatever * bot_crook_dir;
  y8 = -staff_space / 2;

  z7 = z8
       + whatever * bot_crook_dir
       + crook_thinness * (bot_crook_dir rotated 90);
  x7 = .1 [x3r, x8];

  pat := z3r{z3r - z10}
         .. z4r{right}
         .. z5r{down}
         .. z7{-bot_crook_dir}
         & z7
         .. z10{z3r - z10}
         -- cycle;
  unfill pat;
  unfill pat xscaled -1;

  pat := z11{right}
         .. z8{bot_crook_dir}
         .. z5l{up}
         .. z4l{left}
         .. z3l;
  fill pat
       -- simple_serif (z1r, z1l, 30)
       -- reverse pat xscaled -1 shifted (-feta_eps + mirror_offset, 0)
       -- cycle;

  currentpicture := currentpicture shifted (w/2, 0);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("semi flat", "mirroredflat");
  save depth, height;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  set_char_box (1.2 stafflinethickness#, .8 staff_space#, depth#, height#);

  draw_meta_flat (0, w, 0.31 staff_space, false, false, false, false);
  currentpicture := currentpicture xscaled -1 shifted (w - b, 0);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("semi flat (slashed)", "mirroredflat.backslash");
  save depth, height;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  set_char_box (.4 staff_space#, .8 staff_space#, depth#, height#);

  draw_meta_flat (0, w, 0.31 staff_space, false, false, false, false);

  clearxy;

  save slope, slash_width;
  slope = 0.5;
  slash_width = w;

  z11 = (0, vround (h / 2));
  z12 = z11 - (slash_width, slash_width * slope) / 2;
  z13 = z11 + (slash_width, slash_width * slope) / 2;
  penpos12 (1.5 stafflinethickness, angle (z13 - z12) - 90);
  penpos13 (1.5 stafflinethickness, angle (z13 - z12) - 90);

  z14 = z12 - .75 stafflinethickness * unitvector (z13 - z12);
  z15 = z13 + .75 stafflinethickness * unitvector (z13 - z12);

  fill z13r
       .. z15
       .. z13l
       -- z12l
       .. z14
       .. z12r
       -- z13r
       .. cycle;

  currentpicture := currentpicture xscaled -1 shifted (w - b, 0);

  labels (1, 2, 3);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("double flat", "flatflat");
  save depth, height;
  save left_wid, overlap, right_wid;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  left_wid = .7;
  right_wid = .8;
  overlap = .05;

  set_char_box (1.2 stafflinethickness#,
                (left_wid + right_wid - overlap) * staff_space#,
                depth#, height#);
  draw_meta_flat (0, left_wid * staff_space, 1/3 staff_space,
                  false, false, true, false);
  draw_meta_flat (hround ((left_wid - overlap) * staff_space),
                  right_wid * staff_space, 1/3 staff_space,
                  false, false, false, false);

  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("figured bass double flat", "flatflat.figbass");
  save depth, height;
  save left_wid, right_wid, extra_wid;

  depth# := figbass_y#;
  height# := number_design_size + figbass_y#;

  left_wid := .65;
  right_wid := .75;
  extra_wid := .1;

  define_pixels (figbass_width);

  set_char_box (0, (left_wid + right_wid + extra_wid) * figbass_width#,
                depth#, height#);
  draw_meta_flat (-1, left_wid * figbass_width, 1/3 staff_space,
                  false, false, true, true);
  draw_meta_flat (1, right_wid * figbass_width, 1/3 staff_space,
                  false, false, false, true);
fet_endchar;


fet_beginchar ("3/4 flat", "flatflat.slash");
  save depth, height;
  save left_wid, overlap, right_wid;

  depth# := 0.5 staff_space# + 1.3 stafflinethickness#;
  height# := 2 staff_space# - 1.7 stafflinethickness#;

  left_wid = .7;
  right_wid = .8;
  overlap = .05;

  set_char_box (0.45 staff_space#,
                (left_wid + right_wid - overlap) * staff_space#,
                depth#, height#);
  draw_meta_flat (0, left_wid * staff_space, 1/3 staff_space,
                  false, false, true, false);
  draw_meta_flat (hround ((left_wid - overlap) * staff_space),
                  right_wid * staff_space, 1/3 staff_space,
                  false, false, false, false);

  %% maybe we should clip part of the stems?
  %% or make the 1st flat smaller?
  %% or reverse it?
  pickup pencircle scaled 2 stafflinethickness;

  z12 = round (-.53 staff_space, .55 staff_space) + feta_offset;
  z13 = round (.75 w, 1.45 staff_space) + feta_offset;
  penpos12 (2 stafflinethickness, angle (z13 - z12) - 90);
  penpos13 (2 stafflinethickness, angle (z13 - z12) - 90);

  z14 = z12 - stafflinethickness * unitvector (z13 - z12);
  z15 = z13 + stafflinethickness * unitvector (z13 - z12);

  fill z13r
       .. z15
       .. z13l
       -- z12l
       .. z14
       .. z12r
       -- z13r
       .. cycle;

  penlabels (12, 13);
  labels (14, 15);

  draw_staff_if_debugging (-2, 2);
fet_endchar;
