% Feta (not the Font-En-Tja) music font --  Accidentals
% This file is part of LilyPond, the GNU music typesetter.
%
% Copyright (C) 1997--2023 Han-Wen Nienhuys <hanwen@xs4all.nl>
% Copyright (C) 2013--2023 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/>.

%
% The beams of most sharps have horizontal endings (as if drawn with
% a square pen).  [Wanske] does not mention this, so we'll just ignore
% this fact.
%

save default_width, default_height, onestemmed_height;
save default_interbeam_dist, triples_interbeam_dist;
save default_beam_thickness, stem_thickness;

default_width# := 1.1 staff_space#;
default_height# := 3 staff_space#;
onestemmed_height# := 2.66 staff_space#;
define_pixels (default_width);

default_interbeam_dist := 1.05 staff_space_rounded;
triples_interbeam_dist := 1.2 staff_space_rounded;

default_beam_thickness# := 0.3 staff_space# + stafflinethickness#;
stem_thickness# := stafflinethickness# + .05 staff_space#;
define_whole_blacker_pixels (stem_thickness);


def draw_sharp_beam (expr xcenter, length, y_offset) =
  save ne_beam_dir, nw_dist;
  pair ne_beam_dir, nw_dist;

  clearxy;

  pickup pencircle scaled 2 blot_diameter;

  % use a fractional pixel value to get a uniform slant...
  define_pixels (default_beam_thickness);

  ne_beam_dir = unitvector (length, default_beam_thickness);
  nw_dist = (ne_beam_dir rotated 90) * blot_diameter;

  rt x2 - lft x1 = length;
  z2 = z1 + whatever * ne_beam_dir;
  .5 [z1, z3] = (xcenter, y_offset);
  x3 = x2;

  % ... but use an integer pixel value for actually drawing the beam
  define_whole_vertical_blacker_pixels (default_beam_thickness);

  top y2 - bot y3 = default_beam_thickness;
  x4 = x1;
  top y1 - bot y4 = default_beam_thickness;

  % shift beam vertically to be aligned with the pixel grid
  y1 := good.y (y1);
  y2 := good.y (y2);
  y3 := good.y (y3);
  y4 := good.y (y4);

  fill lft z1{up}
       ... (z1 + nw_dist){ne_beam_dir}
       -- (z2 + nw_dist){ne_beam_dir}
       ... rt z2{down}
       -- rt z3{down}
       ... (z3 - nw_dist){-ne_beam_dir}
       -- (z4 - nw_dist){-ne_beam_dir}
       ... lft z4{up}
       -- cycle;

  labels (1, 2, 3, 4);
enddef;


def draw_sharp (expr arrowup, arrowdown, figured_bass) =
  save depth, height, width;
  save dist_between_stems, offset;
  save outer_space;
  save half_height, interbeam_dist, stem_correction;
  save beam_length, beam_xcenter;

  dist_between_stems# := 7 / 16 * default_width#;
  define_whole_pixels (dist_between_stems);

  outer_space# := .5 (default_width# - dist_between_stems#
                      - stem_thickness#);
  define_whole_pixels (outer_space);
  width# := 2 outer_space# + dist_between_stems# + stem_thickness#;

  if figured_bass:
    % The next two lines are global assignments; we use these values
    % for other figured bass accidentals, too.  (This works because
    % `draw_sharp` is called only once with `figured_bass` set to
    % true.)
    figbass_y# := dist_between_stems# / width#
                  * default_beam_thickness#;
    figbass_width# := width#;

    half_height# := .5 number_design_size + figbass_y#;
    offset# := .5 number_design_size;

    % The stems for the text variant are much shorter; additionally,
    % the top and bottom end parts of the stems are half-circles,
    % contrary to the top and bottom parts of the natural and the flat
    % glyph.  We thus slightly increase the stem lengths to let them
    % stick out of the bounding box.
    stem_correction := .5 stem_thickness;
  else:
    half_height# := .5 default_height#;
    offset# := 0;

    stem_correction := 0;
  fi;
  define_pixels (half_height, offset);

  depth# := half_height# - offset#;
  height# := half_height# + offset#;

  beam_length := 2 outer_space + dist_between_stems + stem_thickness;
  beam_xcenter := .5 beam_length;

  if arrowup:
    % synchronized with point z4 of the arrow
    height# := half_height# - .5 stem_thickness#          % y8
               + .1 staff_space# + .5 stafflinethickness#
                 + .5 stem_thickness#                     % upshift
               + .85 staff_space# + stafflinethickness#;  % htip
  fi;
  if arrowdown:
    % synchronized with point z4 of the arrow
    depth# := half_height# - .5 stem_thickness#          % y5
              + .1 staff_space# + .5 stafflinethickness#
                + .5 stem_thickness#                     % upshift
              + .85 staff_space# + stafflinethickness#;  % htip
  fi;

  set_char_box (0, width#, depth#, height#);
  d := d - feta_space_shift;

  if figured_bass:
    interbeam_dist := .9 default_interbeam_dist;
  else:
    interbeam_dist := default_interbeam_dist;
  fi;

  draw_sharp_beam (beam_xcenter, beam_length,
                   -.5 interbeam_dist + offset);
  draw_sharp_beam (beam_xcenter, beam_length,
                   -.5 interbeam_dist + offset + vround interbeam_dist);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  lft x7 = lft x8 = outer_space + dist_between_stems;
  bot y5 = -(half_height + stem_correction) + offset;
  top y8 = half_height + stem_correction + offset;
  z6 = z8 + whatever * ne_beam_dir;
  bot y7 - offset = -(top y6 - offset) + feta_space_shift;

  fill lft z7{down}
       .. bot z7{right}
       .. rt z7{up}
    if arrowup:
       -- draw_arrow (z8, stem_thickness, up,
                      stafflinethickness / 2 + stem_thickness / 2, false)
    else:
       -- rt z8{up}
       .. top z8{left}
       .. lft z8{down}
    fi
       -- cycle;

  fill rt z6{up}
       .. top z6{left}
       .. lft z6{down}
    if arrowdown:
       -- draw_arrow (z5, stem_thickness, up,
                      stafflinethickness / 2 + stem_thickness / 2, true)
    else:
       -- lft z5{down}
       .. bot z5{right}
       .. rt z5{up}
    fi
       -- cycle;

  labels (5, 6, 7, 8);
  draw_staff_if_debugging (-2, 2);
enddef;


fet_beginchar ("sharp", "sharp");
  draw_sharp (false, false, false);
fet_endchar;


fet_beginchar ("figured bass sharp", "sharp.figbass");
  draw_sharp (false, false, true);
fet_endchar;


fet_beginchar ("arrowed sharp (arrow up)", "sharp.arrowup");
  draw_sharp (true, false, false);
fet_endchar;


fet_beginchar ("arrowed sharp (arrow down)", "sharp.arrowdown");
  draw_sharp (false, true, false);
fet_endchar;


fet_beginchar ("arrowed sharp (arrows up and down)", "sharp.arrowboth");
  draw_sharp (true, true, false);
fet_endchar;


fet_beginchar ("1/2 sharp", "sharp.slashslash.stem");
  save width;
  save outer_space;
  save half_height, interbeam_dist;
  save beam_length, beam_xcenter;

  half_height# := .5 onestemmed_height#;
  define_pixels (half_height);

  outer_space# := .5 (.7 staff_space# - stem_thickness#);
  define_whole_pixels (outer_space);

  width# := 2 outer_space# + stem_thickness#;

  beam_length := 2 outer_space + stem_thickness;
  beam_xcenter := .5 beam_length;

  set_char_box (0, width#, half_height#, half_height#);
  d := d - feta_space_shift;

  interbeam_dist := default_interbeam_dist;
  draw_sharp_beam (beam_xcenter, beam_length, -.5 interbeam_dist);
  draw_sharp_beam (beam_xcenter, beam_length,
                   -.5 interbeam_dist + vround interbeam_dist);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  top y6 = half_height;
  bot y5 = -top y6 + feta_space_shift;

  draw_gridline (z5, z6, stem_thickness);

  labels (5, 6);
  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("sharp (3 beams)", "sharp.slashslashslash.stemstem");
  save width;
  save dist_between_stems;
  save outer_space;
  save half_height, interbeam_dist;
  save default_beam_thickness;
  save beam_length, beam_xcenter;

  half_height# := .5 default_height#;
  define_pixels (half_height);

  dist_between_stems# := 7 / 16 * default_width#;
  define_whole_pixels (dist_between_stems);

  outer_space# := .5 (default_width# - dist_between_stems#
                      - stem_thickness#);
  define_whole_pixels (outer_space);

  width# := 2 outer_space# + dist_between_stems# + stem_thickness#;

  beam_length := 2 outer_space + dist_between_stems + stem_thickness;
  beam_xcenter := .5 beam_length;

  set_char_box (0, width#, half_height#, half_height#);
  d := d - feta_space_shift;

  interbeam_dist := triples_interbeam_dist;
  default_beam_thickness# := .22 staff_space# + stafflinethickness#;
  draw_sharp_beam (beam_xcenter, .88 beam_length, -.5 interbeam_dist);
  draw_sharp_beam (beam_xcenter, .88 beam_length,
                   -.5 interbeam_dist + vround interbeam_dist);
  default_beam_thickness# := 1/.88 default_beam_thickness#;
  draw_sharp_beam (beam_xcenter, beam_length, 0);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  lft x7 = lft x8 = outer_space + dist_between_stems;
  bot y5 = -half_height;
  top y8 = half_height;
  z6 = z8 + whatever * ne_beam_dir;
  bot y7 = -top y6 + feta_space_shift;

  draw_gridline (z5, z6, stem_thickness);
  draw_gridline (z7, z8, stem_thickness);

  labels (5, 6, 7, 8);
  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("1/2 sharp (3 beams)", "sharp.slashslashslash.stem");
  save width;
  save outer_space;
  save half_height, interbeam_dist;
  save default_beam_thickness;
  save beam_length, beam_xcenter;

  half_height# := .5 onestemmed_height#;
  define_pixels (half_height);

  outer_space# := .5 (.95 staff_space# - stem_thickness#);
  define_whole_pixels (outer_space);

  width# := 2 outer_space# + stem_thickness#;

  beam_length := 2 outer_space + stem_thickness;
  beam_xcenter := .5 beam_length;

  set_char_box (0, width#, half_height#, half_height#);
  d := d - feta_space_shift;

  interbeam_dist := triples_interbeam_dist;
  default_beam_thickness# := .22 staff_space# + stafflinethickness#;
  draw_sharp_beam (beam_xcenter, .8 beam_length, -.5 interbeam_dist);
  draw_sharp_beam (beam_xcenter, .8 beam_length,
                   -.5 interbeam_dist + vround interbeam_dist);
  default_beam_thickness# := 1/.8 default_beam_thickness#;
  draw_sharp_beam (beam_xcenter, beam_length, 0);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  top y6 = half_height;
  bot y5 = -top y6 + feta_space_shift;

  draw_gridline (z5, z6, stem_thickness);

  labels (5, 6);
  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("1/2 sharp (1 beam)", "sharp.slash.stem");
  save width;
  save outer_space;
  save half_height, interbeam_dist;
  save beam_length, beam_xcenter;

  half_height# := .5 onestemmed_height#;
  define_pixels (half_height);

  outer_space# := .5 (.95 staff_space# - stem_thickness#);
  define_whole_pixels (outer_space);

  width# := 2 outer_space# + stem_thickness#;

  beam_length := 2 outer_space + stem_thickness;
  beam_xcenter := .5 beam_length;

  set_char_box (0, width#, half_height#, half_height#);
  d := d - feta_space_shift;

  draw_sharp_beam (beam_xcenter, beam_length, 0);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  top y6 = half_height;
  bot y5 = -top y6 + feta_space_shift;

  draw_gridline (z5, z6, stem_thickness);

  labels (5, 6);
  draw_staff_if_debugging (-2, 2);
fet_endchar;


fet_beginchar ("3/4 sharp", "sharp.slashslash.stemstemstem");
  save width;
  save dist_between_stems;
  save outer_space;
  save half_height, interbeam_dist;
  save beam_length, beam_xcenter;

  half_height# := 0.5 default_height#;
  define_pixels (half_height);

  dist_between_stems# := 9 / 32 * 1.6 staff_space#;
  define_whole_pixels (dist_between_stems);

  outer_space# := .5 (1.6 staff_space# - 2 dist_between_stems#
                      - stem_thickness#);
  define_whole_pixels (outer_space);

  width# := 2 outer_space# + 2 dist_between_stems# + stem_thickness#;

  beam_length := 2 outer_space + 2 dist_between_stems + stem_thickness;
  beam_xcenter := .5 beam_length;

  set_char_box (0, width#, half_height#, half_height#);
  d := d - feta_space_shift;

  interbeam_dist := default_interbeam_dist;
  draw_sharp_beam (beam_xcenter, beam_length, -.5 interbeam_dist);
  draw_sharp_beam (beam_xcenter, beam_length,
                   -.5 interbeam_dist + vround interbeam_dist);

  pickup pencircle scaled stem_thickness;

  lft x5 = lft x6 = outer_space;
  lft x9 = lft x10 = outer_space + dist_between_stems;
  lft x7 = lft x8 = outer_space + 2 dist_between_stems;
  bot y5 = -half_height;
  top y8 = half_height;
  z6 = z8 + whatever * ne_beam_dir;
  bot y7 = -top y6 + feta_space_shift;
  y9 = .5 [y5, y7];
  y10 = .5 [y6, y8];

  draw_gridline (z5, z6, stem_thickness);
  draw_gridline (z7, z8, stem_thickness);
  draw_gridline (z9, z10, stem_thickness);

  labels (5, 6, 7, 8, 9, 10);
  draw_staff_if_debugging (-2, 2);
fet_endchar;


def draw_double_sharp (expr figured_bass) =
  save depth, height, width;
  save klaverblad, klaversteel;
  save glyph_height, offset;
  save pat;
  path pat;

  klaversteel = 1/15 staff_space;
  klaverblad = .4 staff_space - .5 stafflinethickness;

  if figured_bass:
    width# := figbass_width#;
    offset# := .5 number_design_size;
  else:
    width# := staff_space#;
    offset# := 0;
  fi;
  define_pixels (offset);

  glyph_height# := .5 width#;
  define_whole_vertical_blacker_pixels (glyph_height);

  depth# := glyph_height# - offset#;
  height# := glyph_height# + offset#;

  set_char_box (0, width#, depth#, height#);

  z1 = (klaversteel, 0);
  z2 = (w / 2 - klaverblad / 10, glyph_height - klaverblad);
  z3 = (w / 2, glyph_height);
  z4 = z2 reflectedabout ((0, 0), (1, 1));
  z5 = z1 reflectedabout ((0, 0), (1, 1));

  pickup pencircle scaled blot_diameter;

  x2 := hfloor (rt x2) - blot_diameter / 2;
  x3 := hfloor (rt x3) - blot_diameter / 2;
  y3 := vfloor (top y3) - blot_diameter / 2;
  y4 := vfloor (top y4) - blot_diameter / 2;

  pat = (rt z1){dir45}
        .. {right}(bot z2)
        .. rt z2
        -- rt z3{z3 - z2}
        .. top z3{z4 - z3}
        -- top z4{z4 - z3}
        .. (lft z4){down}
        .. {dir 225}(top z5);
  pat := pat
         -- reverse pat xscaled -1 shifted (-feta_eps, 0);

  % assure symmetry -- it's more important to center the glyph on the
  % staff line than centering it between staff lines, so we use
  % feta_shift, not feta_space_shift.
  h := h + feta_shift;

  fill pat shifted (0, feta_shift)
       -- reverse pat yscaled -1 shifted (0, -feta_eps)
       -- cycle;

  % ugh
  currentpicture := currentpicture shifted (hround (w / 2),
                                            vround (offset));

  labels (1, 2, 3, 4, 5);
  draw_staff_if_debugging (-2, 2);
enddef;


fet_beginchar ("double sharp", "doublesharp");
  draw_double_sharp (false);
fet_endchar;


fet_beginchar ("figured bass double sharp", "doublesharp.figbass");
  draw_double_sharp (true);
fet_endchar;
