/**
 * Copyright (c) 2021 Dominic Masters
 * 
 * This software is released under the MIT License.
 * https://opensource.org/licenses/MIT
 */

#include "font.h"

// Due to some compiler bullshit, this is here.
#ifndef  STB_TRUETYPE_IMPLEMENTATION
  #define STB_TRUETYPE_IMPLEMENTATION
  #include <stb_truetype.h>
#endif

void fontInit(font_t *font, char *data) {
  int32_t i, s;
  s = FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT;

  uint8_t *bitmapData = malloc(sizeof(uint8_t) * s);
  pixel_t *pixels = malloc(sizeof(pixel_t) * s);

  // STBTT Loads fonts as single channel values only.
  stbtt_BakeFontBitmap(
    data, 0, FONT_TEXTURE_SIZE, bitmapData,
    FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
    FONT_FIRST_CHAR, FONT_NUM_CHARS,
    font->characterData
  );

  for(i = 0; i < FONT_TEXTURE_WIDTH * FONT_TEXTURE_HEIGHT; i++) {
    pixels[i].r = 0xFF;
    pixels[i].g = 0xFF;
    pixels[i].b = 0xFF;
    pixels[i].a = bitmapData[i];
  }
  textureInit(&font->texture, FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT, pixels);

  free(bitmapData);
  free(pixels);
}

void fontDispose(font_t *font) {
  textureDispose(&font->texture);
}


fonttextinfo_t * fontGetTextInfo(font_t *font, char *text, float scale) {
  int32_t i, j;
  char c;
  float x, y;
  stbtt_aligned_quad *quad;

  // Create info buffer.
  fonttextinfo_t *info = malloc(sizeof(fonttextinfo_t));
  
  info->length = 0;
  info->realLength = 0;

  // Count how many "real characters" are in the string.
  i = 0;
  while(c = text[i++]) {
    info->length++;
    if(c == FONT_SPACE) continue;
    if(c == FONT_NEWLINE) continue;
    info->realLength++;
  }

  // Now setup the size scales
  info->quads = malloc(sizeof(stbtt_aligned_quad) * info->realLength);
  info->scale = scale * FONT_SCALE_ADJUST;
  info->width = 0, info->height = 0;

  // Begin buffering quads.
  x = 0;
  y = FONT_INITIAL_LINE;
  i = 0, j = 0;

  while(c = text[i++]) {
    // Spaces, don't quad just next
    if(c == FONT_SPACE) {
      x += FONT_SPACE_SIZE;
      continue;
    }

    // Newlines reset X
    if(c == FONT_NEWLINE) {
      y += FONT_LINE_HEIGHT;
      x = 0;
      continue;
    }
  
    // Calculate the quad of the character, store into the array.
    quad = info->quads + j;
    stbtt_GetBakedQuad(font->characterData,
      FONT_TEXTURE_WIDTH, FONT_TEXTURE_HEIGHT,
      ((int32_t)c)-FONT_FIRST_CHAR, &x, &y, quad, FONT_FILL_MODE
    );
    quad->x0 *= info->scale, quad->x1 *= info->scale;
    quad->y0 *= info->scale, quad->y1 *= info->scale;
    info->width = mathMax(info->width, quad->x1);
    info->height = mathMax(info->height, quad->y1);
    j++;
  }

  return info;
}

void fontTextInfoDispose(fonttextinfo_t *info) {
  free(info->quads);
  free(info);
}


void fontTextBuffer(font_t *font,primitive_t *primitive,fonttextinfo_t *info) {
  stbtt_aligned_quad *quad;
  int32_t i;
  
  for(i = 0; i < info->realLength; i++) {
    quad = info->quads + i;
    quadBuffer(primitive, 0,
      quad->x0, quad->y0, quad->s0, quad->t0,
      quad->x1, quad->y1, quad->s1, quad->t1,
      i*QUAD_VERTICE_COUNT, i*QUAD_INDICE_COUNT
    );
  }
}

void fontTextInit(font_t *font, primitive_t *primitive, fonttextinfo_t *info) {
  primitiveInit(primitive,
    QUAD_VERTICE_COUNT * info->realLength, QUAD_INDICE_COUNT * info->realLength
  );
  fontTextBuffer(font, primitive, info);
}