///|
/// Bitmap text rendering with a built-in 5x7 font (digits, uppercase
/// letters and basic punctuation). Glyphs are drawn through the clipped
/// drawing primitives, so text can safely overflow the canvas. Lowercase
/// letters render as uppercase; unknown characters render as a box.

///|
/// The 5x7 glyph as 7 rows of 5-bit masks (bit 4 = leftmost column).
fn glyph_rows(code : Int) -> Array[Int] {
  // Map lowercase to uppercase.
  let c = if code >= 97 && code <= 122 { code - 32 } else { code }
  match c {
    32 => [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] // space
    33 => [0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x04] // !
    45 => [0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00] // -
    46 => [0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C] // .
    48 => [0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E] // 0
    49 => [0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E] // 1
    50 => [0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F] // 2
    51 => [0x1F, 0x02, 0x04, 0x02, 0x01, 0x11, 0x0E] // 3
    52 => [0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02] // 4
    53 => [0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E] // 5
    54 => [0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E] // 6
    55 => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08] // 7
    56 => [0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E] // 8
    57 => [0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C] // 9
    58 => [0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x00] // :
    63 => [0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04] // ?
    65 => [0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11] // A
    66 => [0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E] // B
    67 => [0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E] // C
    68 => [0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C] // D
    69 => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F] // E
    70 => [0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10] // F
    71 => [0x0E, 0x11, 0x10, 0x17, 0x11, 0x11, 0x0F] // G
    72 => [0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11] // H
    73 => [0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E] // I
    74 => [0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C] // J
    75 => [0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11] // K
    76 => [0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F] // L
    77 => [0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11] // M
    78 => [0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11] // N
    79 => [0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E] // O
    80 => [0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10] // P
    81 => [0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D] // Q
    82 => [0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11] // R
    83 => [0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E] // S
    84 => [0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04] // T
    85 => [0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E] // U
    86 => [0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04] // V
    87 => [0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A] // W
    88 => [0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11] // X
    89 => [0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04] // Y
    90 => [0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F] // Z
    _ => [0x1F, 0x11, 0x11, 0x11, 0x11, 0x11, 0x1F] // unknown -> box
  }
}

///|
/// Draws one character with its top-left corner at `(x, y)`, each font
/// pixel scaled to a `scale x scale` block (scale is clamped to >= 1).
pub fn Image::draw_char(
  self : Image,
  x : Int,
  y : Int,
  ch : Char,
  scale : Int,
  r : Byte,
  g : Byte,
  b : Byte,
  a : Byte,
) -> Unit {
  let s = if scale < 1 { 1 } else { scale }
  let rows = glyph_rows(ch.to_int())
  for row in 0..<7 {
    for col in 0..<5 {
      if rows[row] / (1 << (4 - col)) % 2 == 1 {
        self.fill_rect(x + col * s, y + row * s, s, s, r, g, b, a)
      }
    }
  }
}

///|
/// Draws a text string starting at `(x, y)`; the pen advances 6 font
/// columns (5 glyph + 1 spacing) per character. Returns nothing; text
/// overflowing the canvas is clipped, not wrapped.
pub fn Image::draw_text(
  self : Image,
  x : Int,
  y : Int,
  text : String,
  scale : Int,
  r : Byte,
  g : Byte,
  b : Byte,
  a : Byte,
) -> Unit {
  let s = if scale < 1 { 1 } else { scale }
  let mut pen = x
  for ch in text {
    self.draw_char(pen, y, ch, s, r, g, b, a)
    pen = pen + 6 * s
  }
}