#include "holly/isp_tsp.hpp"

#include "texture.hpp"
#include "ta_parameter.hpp"
#include "font.hpp"

#include "math/float_types.hpp"

namespace font {

const font fonts[] = {
  [font::ter_u24n] = {
    .texture_size = tsp_instruction_word::texture_u_size::from_int(256)
                  | tsp_instruction_word::texture_v_size::from_int(128),
    .texture_offset = texture::offset::ter_u24n,
    .texture_width = 256,
    .texture_height = 128,
    .hori_advance = 12,
    .width = 12,
    .height = 24,
    .row_stride = 21,
  },
  [font::ter_u32n] = {
    .texture_size = tsp_instruction_word::texture_u_size::from_int(256)
                  | tsp_instruction_word::texture_v_size::from_int(256),
    .texture_offset = texture::offset::ter_u32n,
    .texture_width = 256,
    .texture_height = 256,
    .hori_advance = 16,
    .width = 16,
    .height = 32,
    .row_stride = 16,
  }
};

void draw_glyph_global(ta_parameter_writer& writer, const font& face)
{
  global_polygon_textured(writer,
                          para_control::list_type::punch_through,
                          face.texture_offset,
                          face.texture_size | tsp_instruction_word::dst_alpha_instr::inverse_src_alpha,
                          texture_control_word::pixel_format::_4bpp_palette);
}

static inline vec2 transform_glyph_texture(const font& face, const vec2& t, int char_code)
{
  int row = char_code / face.row_stride;
  int col = char_code % face.row_stride;

  return {
    (float)(col * face.width  + t.x * face.width) / (float)(face.texture_width),
    (float)(row * face.height + t.y * face.height) / (float)(face.texture_height),
  };
}

static inline vec3 transform_glyph_position(const font& face, const vec2& p, float x, float y, float z)
{
  return {
    p.x * face.width + x,
    p.y * face.height + y,
    z
  };
}

void draw_glyph(ta_parameter_writer& writer,
                const font& face,
                int c,
                float x, float y, float z,
                int base_color)
{
  static const vec2 vtx[] = {
    { 0, 0 },
    { 1, 0 },
    { 1, 1 },
    { 0, 1 },
  };

  vec3 ap = transform_glyph_position(face, vtx[0], x, y, z);
  vec3 bp = transform_glyph_position(face, vtx[1], x, y, z);
  vec3 cp = transform_glyph_position(face, vtx[2], x, y, z);
  vec3 dp = transform_glyph_position(face, vtx[3], x, y, z);

  vec2 at = transform_glyph_texture(face, vtx[0], c);
  vec2 bt = transform_glyph_texture(face, vtx[1], c);
  vec2 ct = transform_glyph_texture(face, vtx[2], c);
  vec2 dt = transform_glyph_texture(face, vtx[3], c);

  quad_type_3(writer,
              ap, at,
              bp, bt,
              cp, ct,
              dp, dt,
              base_color);
}

void draw_string(ta_parameter_writer& writer,
                 const font& face,
                 const char * s,
                 float x, float y, float z,
                 int base_color)
{
  const uint8_t * u8 = (const uint8_t *)s;
  int len = 0;
  while (*u8) {
    len += 1;
    int c = *u8++;
    draw_glyph(writer, face, c - 32, x, y, z, base_color);
    x += face.hori_advance;
  }
}

}
