#include <alias/ui.h>

struct alias_ui_dstack_child {
  uint32_t hole;
  float weight;
};

struct alias_ui_named_scope {
  uint64_t hash;
  uint32_t query_capacity;
  float *query_rects;
  uint32_t slot_capacity;
  uint32_t *slot;
};

struct alias_ui_tree_scope {
  uint32_t named_scope_index;
  uint32_t font_index;
  float font_size;
  uint32_t font_color;

  float weight;

  bool handle_alignment;
  float align_x;
  float align_y;

  union {
    struct {
      uint32_t hole;
      uint32_t num_children;
    } stack;
    struct {
      bool vertical;
      uint32_t hole;
      uint32_t child_pmark;
      uint32_t child_mmark;
      float total_weight;
      uint32_t children_capacity;
      uint32_t children_length;
      struct alias_ui_dstack_child *children;
    } dstack;
  };

  void (*begin_child)(struct alias_ui *, struct alias_ui_tree_scope *);
  void (*end_child)(struct alias_ui *, struct alias_ui_tree_scope *);
  void (*end_scope)(struct alias_ui *, struct alias_ui_tree_scope *);
  void *user_data;
};

struct alias_ui {
  alias_MemoryCB *mcb;
  alias_ui_Input input;
  alias_ui_Output *output;

  uint32_t font_capacity;
  uint32_t font_length;
  struct alias_ui_Font *font;

  uint32_t named_scope_capacity;
  uint32_t named_scope_length;
  struct alias_ui_named_scope *named_scope;

  uint32_t tree_scope_capacity;
  uint32_t tree_scope_length;
  struct alias_ui_tree_scope *tree_scope;

  uint32_t program_capacity;
  uint32_t program_length;
  uint32_t *program;

  uint32_t *ip;

  uint32_t memory_capacity;
  uint32_t memory_length;
  uint32_t *memory;

  uint32_t *mp;

  //uint32_t vertexes_capacity;
  //uint32_t vertexes_length;
  //struct alias_ui_vertex *vertexes;

  //uint32_t indexes_capacity;
  //uint32_t indexes_length;
  //uint32_t *indexes;

  uint32_t groups_capacity;
  uint32_t groups_length;
  struct alias_ui_group *groups;

  uint32_t texture_id;

#ifdef UNICAT_UI_ENABLE_FREETYPE
  uint32_t (*freetype_texture_callback)(uint32_t length, void ** ptr);
#endif

  struct {
    uint32_t texture_id;
    uint32_t num_vertexes;
    uint32_t num_indexes;
    uint32_t num_groups;
  } stats;
};

enum {
  P_TERMINATE,
  P_EMPTY_FILL,
  P_COLOR_FILL,
  P_IMAGE,
  P_TEXT,
  P_BACKGROUND_COLOR,
  P_BORDER,
  P_STACK,
  P_HORIZONTAL_STACK,
  P_VERTICAL_STACK,
  P_SIZE,
  P_WIDTH,
  P_HEIGHT,
  P_ALIGN,
  P_ALIGN_X,
  P_ALIGN_Y,
  P_PADDING,
  P_QUERY,
};

// util ---------------------------------------------------------------------------------------------------------------
static inline bool alias_ui__grow(void **ptr, uint32_t element_size, uint32_t length, uint32_t *capacity) {
  uint32_t old_capacity = *capacity;
  if(length > old_capacity) {
    *capacity = length + 1;
    *capacity += *capacity >> 1;
    void * new_ptr = alias_realloc(NULL, *ptr, element_size * old_capacity, element_size * *capacity, 4);
    if(new_ptr == NULL) {
      return false;
    }
    *ptr = new_ptr;
  }
  return true;
}

// tree ---------------------------------------------------------------------------------------------------------------
static inline void alias_ui__tree__space_for(struct alias_ui *ui, uint32_t count) {
  alias_ui__grow((void **)&ui->tree_scope, sizeof(*ui->tree_scope), ui->tree_scope_length + count,
                  &ui->tree_scope_capacity);
}

static inline struct alias_ui_tree_scope *alias_ui__tree__top_scope(struct alias_ui *ui) {
  assert(ui->tree_scope_length > 0);
  return &ui->tree_scope[ui->tree_scope_length - 1];
}

static inline void alias_ui__tree__begin_child(struct alias_ui *ui) {
  if(ui->tree_scope_length > 0) {
    struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
    if(scope->begin_child) {
      scope->begin_child(ui, scope);
    }
  }
}

static inline void alias_ui__tree__end_child(struct alias_ui *ui) {
  if(ui->tree_scope_length > 0) {
    struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
    if(scope->end_child) {
      scope->end_child(ui, scope);
    }
  }
}

static inline void alias_ui__tree__end_scope(struct alias_ui *ui) {
  if(ui->tree_scope_length > 0) {
    struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
    ui->tree_scope_length -= 1;
    if(scope->end_scope) {
      scope->end_scope(ui, scope);
    }
  }
}

static inline void alias_ui__tree__begin_scope(struct alias_ui *ui,
                                                void (*begin_child)(struct alias_ui *, struct alias_ui_tree_scope *),
                                                void (*end_child)(struct alias_ui *, struct alias_ui_tree_scope *),
                                                void (*end_scope)(struct alias_ui *, struct alias_ui_tree_scope *)) {
  alias_ui__tree__space_for(ui, 1);
  struct alias_ui_tree_scope *parent_scope = ui->tree_scope_length > 0 ? alias_ui__tree__top_scope(ui) : NULL;
  ui->tree_scope_length += 1;
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  if(parent_scope != NULL) {
    scope->named_scope_index = parent_scope->named_scope_index;
    scope->font_index = parent_scope->font_index;
    scope->font_size = parent_scope->font_size;
    scope->font_color = parent_scope->font_color;
    if(parent_scope->handle_alignment) {
      scope->handle_alignment = true;
      scope->align_x = parent_scope->align_x;
      scope->align_y = parent_scope->align_y;
    }
  } else {
    scope->named_scope_index = -1;
    scope->font_index = 0;
    scope->font_size = 16;
    scope->font_color = 0xFFFFFFFF;
  }
  scope->begin_child = begin_child;
  scope->end_child = end_child;
  scope->end_scope = end_scope;
}

// program ------------------------------------------------------------------------------------------------------------
static inline void alias_ui__program__space_for(struct alias_ui *ui, uint32_t count) {
  alias_ui__grow((void **)&ui->program, sizeof(*ui->program), ui->program_length + count, &ui->program_capacity);
}

static inline void alias_ui__program__initialize(struct alias_ui *ui) {
  ui->program_length = 0;
}

static inline uint32_t alias_ui__program__mark(struct alias_ui *ui) {
  return ui->program_length;
}

static inline uint32_t alias_ui__program__mark_size(struct alias_ui *ui, uint32_t mark) {
  return ui->program_length - mark;
}

static inline void alias_ui__program__reserve(struct alias_ui *ui, uint32_t space) {
  alias_ui__program__space_for(ui, space);
  ui->program_length += space;
}

static inline uint32_t alias_ui__program__dig(struct alias_ui *ui, uint32_t space) {
  uint32_t result = alias_ui__program__mark(ui);
  alias_ui__program__reserve(ui, space);
  return result;
}

static inline void alias_ui__program__emit_u32(struct alias_ui *ui, uint32_t value) {
  alias_ui__program__space_for(ui, 1);
  ui->program[ui->program_length++] = value;
}

static inline void alias_ui__program__emit_f32(struct alias_ui *ui, float value) {
  union {
    uint32_t u;
    float f;
  } flip = {.f = value};
  alias_ui__program__emit_u32(ui, flip.u);
}

static inline void alias_ui__program__fill_u32(struct alias_ui *ui, uint32_t hole, uint32_t value) {
  ui->program[hole] = value;
}

static inline void alias_ui__program__fill_f32(struct alias_ui *ui, uint32_t hole, float value) {
  union {
    uint32_t u;
    float f;
  } flip = {.f = value};
  alias_ui__program__fill_u32(ui, hole, flip.u);
}

// ip -----------------------------------------------------------------------------------------------------------------
static inline void alias_ui__ip__initialize(struct alias_ui *ui) {
  ui->ip = ui->program;
}

static inline void alias_ui__ip__advance(struct alias_ui *ui, uint32_t count) {
  ui->ip += count;
}

static inline uint32_t alias_ui__ip__read_u32(struct alias_ui *ui) {
  return *ui->ip++;
}

static inline float alias_ui__ip__read_f32(struct alias_ui *ui) {
  union {
    uint32_t u;
    float f;
  } flip = {.u = alias_ui__ip__read_u32(ui)};
  return flip.f;
}

// memory -------------------------------------------------------------------------------------------------------------
static inline void alias_ui__memory__space_for(struct alias_ui *ui, uint32_t count) {
  alias_ui__grow((void **)&ui->memory, sizeof(*ui->memory), ui->memory_length + count, &ui->memory_capacity);
}

static inline void alias_ui__memory__initialize(struct alias_ui *ui) {
  ui->memory_length = 0;
}

static inline uint32_t alias_ui__memory__mark(struct alias_ui *ui) {
  return ui->memory_length;
}

static inline uint32_t alias_ui__memory__mark_size(struct alias_ui *ui, uint32_t mark) {
  return ui->memory_length - mark;
}

static inline void alias_ui__memory__reserve(struct alias_ui *ui, uint32_t space) {
  alias_ui__memory__space_for(ui, space);
  ui->memory_length += space;
}

static inline uint32_t alias_ui__memory__dig(struct alias_ui *ui, uint32_t space) {
  uint32_t result = alias_ui__memory__mark(ui);
  alias_ui__memory__reserve(ui, space);
  return result;
}

static inline void alias_ui__memory__fill_u32(struct alias_ui *ui, uint32_t hole, uint32_t value) {
  assert(hole < ui->memory_length);
  ui->memory[hole] = value;
}

static inline void alias_ui__memory__fill_f32(struct alias_ui *ui, uint32_t hole, float value) {
  union {
    uint32_t u;
    float f;
  } flip = {.f = value};
  alias_ui__memory__fill_u32(ui, hole, flip.u);
}

// float --------------------------------------------------------------------------------------------------------------
static inline float alias_ui__float__min(float a, float b) {
  return a < b ? a : b;
}

static inline float alias_ui__float__max(float a, float b) {
  return a > b ? a : b;
}

static inline float alias_ui__float__clamp(float x, float min, float max) {
  return alias_ui__float__min(alias_ui__float__max(x, min), max);
}

static inline uint8_t alias_ui__float__to_color_channel(float x) {
  return (uint8_t)alias_ui__float__clamp(x * 255.0f, 0.0f, 255.0f);
}

static inline uint32_t alias_ui__color__pack(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
  return ((uint32_t)r << 24) | ((uint32_t)g << 16) | ((uint32_t)b << 8) | a;
}

static inline void alias_ui__color__unpack(uint32_t color, uint8_t *r, uint8_t *g, uint8_t *b, uint8_t *a) {
  *r = (color >> 24) & 0xFF;
  *g = (color >> 16) & 0xFF;
  *b = (color >> 8) & 0xFF;
  *a = (color >> 0) & 0xFF;
}

// mp -----------------------------------------------------------------------------------------------------------------
static inline void alias_ui__mp__initialize(struct alias_ui *ui) {
  ui->mp = ui->memory;
}

static inline void alias_ui__mp__advance(struct alias_ui *ui, uint32_t count) {
  ui->mp += count;
}

static inline uint32_t alias_ui__mp__read_u32(struct alias_ui *ui) {
  return *ui->mp++;
}

static inline float alias_ui__mp__read_f32(struct alias_ui *ui) {
  union {
    uint32_t u;
    float f;
  } flip = {.u = alias_ui__mp__read_u32(ui)};
  return flip.f;
}

// vertex -------------------------------------------------------------------------------------------------------------
static inline void alias_ui__vertex__initialize(struct alias_ui *ui) {
  ui->output->num_vertexes = 0;
}

static inline uint32_t alias_ui__vertex__emit(struct alias_ui *ui, float x, float y, float s, float t, uint8_t r,
                                               uint8_t g, uint8_t b, uint8_t a) {
  float xy[] = {x, y};
  float rgba[] = {r, g, b, a};
  float st[] = {s, t};
  alias_memory_SubBuffer_write(&ui->output->xy_sub_buffer, ui->output->num_vertexes, 1, alias_memory_Format_Float32, 0, xy);
  alias_memory_SubBuffer_write(&ui->output->rgba_sub_buffer, ui->output->num_vertexes, 1, alias_memory_Format_Unorm8, 0, rgba);
  alias_memory_SubBuffer_write(&ui->output->st_sub_buffer, ui->output->num_vertexes, 1, alias_memory_Format_Float32, 0, st);
  return ui->output->num_vertexes++;
}

// index --------------------------------------------------------------------------------------------------------------
static inline void alias_ui__index__initialize(struct alias_ui *ui) {
  ui->output->num_indexes = 0;
}

static inline uint32_t alias_ui__index__emit(struct alias_ui *ui, uint32_t vertex_index) {
  // requires caller to have called alias_ui__index__space_for(ui, N) before
  alias_memory_SubBuffer_write(&ui->output->index_sub_buffer, ui->output->num_indexes, 1, alias_memory_Format_Sint32, 0, &vertex_index);
  return ui->output->num_indexes++;
}

// group --------------------------------------------------------------------------------------------------------------
static inline void alias_ui__group__initialize(struct alias_ui *ui) {
  ui->output->num_groups = 0;
}

static inline struct alias_ui_OutputGroup *alias_ui__group__top(struct alias_ui *ui) {
  return &ui->output->groups[ui->groups_length - 1];
}

static inline void alias_ui__group__prepare(struct alias_ui *ui) {
  struct alias_ui_OutputGroup *group = alias_ui__group__top(ui);
  group->texture_id = ui->texture_id;
  group->index = ui->output->num_indexes;
  group->length = 0;
}

static inline void alias_ui__group__finalize(struct alias_ui *ui) {
  struct alias_ui_OutputGroup *group = alias_ui__group__top(ui);
  group->length = ui->output->num_indexes - group->index;
}

static inline void alias_ui__group__advance(struct alias_ui *ui) {
  if(ui->groups_length > 0) {
    alias_ui__group__finalize(ui);
  }
  ui->groups_length++;
  alias_ui__group__prepare(ui);
}

// render -------------------------------------------------------------------------------------------------------------
void alias_ui_set_texture(struct alias_ui *ui, uint32_t texture_id) {
  if(ui->texture_id != texture_id) {
    ui->texture_id = texture_id;
    alias_ui__group__advance(ui);
  }
}

void alias_ui_draw_rectangle(struct alias_ui *ui, float x, float y, float width, float height,
                                                     float s0, float t0, float s1, float t1, uint8_t r, uint8_t g,
                                                     uint8_t b, uint8_t a) {
  float x0 = x;
  float y0 = y;
  float x1 = x + width;
  float y1 = y + height;
  uint32_t A = alias_ui__vertex__emit(ui, x0, y0, s0, t0, r, g, b, a);
  uint32_t B = alias_ui__vertex__emit(ui, x0, y1, s0, t1, r, g, b, a);
  uint32_t C = alias_ui__vertex__emit(ui, x1, y1, s1, t1, r, g, b, a);
  uint32_t D = alias_ui__vertex__emit(ui, x1, y0, s1, t0, r, g, b, a);
  alias_ui__index__emit(ui, A);
  alias_ui__index__emit(ui, B);
  alias_ui__index__emit(ui, C);
  alias_ui__index__emit(ui, A);
  alias_ui__index__emit(ui, C);
  alias_ui__index__emit(ui, D);
}

static inline void alias_ui__stats__initialize(alias_ui *ui) {
  memset(&ui->stats, 0, sizeof(ui->stats));
  ui->stats.texture_id = -1;
}

static inline void alias_ui__stats__set_texture(alias_ui *ui, uint32_t texture_id) {
  if(ui->stats.texture_id != texture_id) {
    ui->stats.texture_id = texture_id;
    ui->stats.num_groups += 1;
  }
}

static inline void alias_ui__stats__draw_rectangle(struct alias_ui *ui) {
  ui->stats.num_vertexes += 4;
  ui->stats.num_indexes += 6;
}

static inline void alias_ui__layout(struct alias_ui *, float, float, float, float, float *, float *);
static inline void alias_ui__render(struct alias_ui *, float, float, float, float);

// empty fill
// program: r:float, g:float, b:float, a:float
//  memory: unused
static void alias_ui__empty_fill__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                          float max_height, float *out_width, float *out_height) {
  *out_width = max_width;
  *out_height = max_height;
}

static void alias_ui__empty_fill__render(struct alias_ui *ui, float x, float y, float width, float height) {}

void alias_ui_empty_fill(struct alias_ui *ui) {
  alias_ui__tree__begin_child(ui);
  alias_ui__program__emit_u32(ui, P_EMPTY_FILL);
  alias_ui__tree__end_child(ui);
}


// color fill
// program: color:uint32_t
//  memory: unused
static void alias_ui__color_fill__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                          float max_height, float *out_width, float *out_height) {
  alias_ui__ip__advance(ui, 4);
  *out_width = max_width;
  *out_height = max_height;
}

static void alias_ui__color_fill__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t color = alias_ui__ip__read_u32(ui);
  uint8_t r, g, b, a;
  alias_ui__color__unpack(color, &r, &g, &b, &a);
  alias_ui_set_texture(ui, 0);
  alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 1, 1, r, g, b, a);
}

void alias_ui_color_fill(struct alias_ui *ui, float _r, float _g, float _b, float _a) {
  alias_ui__tree__begin_child(ui);
  alias_ui__program__emit_u32(ui, P_COLOR_FILL);
  uint32_t r = alias_ui__float__to_color_channel(_r);
  uint32_t g = alias_ui__float__to_color_channel(_g);
  uint32_t b = alias_ui__float__to_color_channel(_b);
  uint32_t a = alias_ui__float__to_color_channel(_a);
  alias_ui__program__emit_u32(ui, alias_ui__color__pack(r, g, b, a));
  alias_ui__tree__end_child(ui);
  alias_ui__stats__set_texture(ui, 0);
  alias_ui__stats__draw_rectangle(ui);
}

// image
// program: texture_id:uint32_t, width:float, height:float, s0:float, t0:float, s1:float, t1:float
static void alias_ui__image__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                     float max_height, float *out_width, float *out_height) {
  (void)alias_ui__ip__read_u32(ui);
  float width = alias_ui__ip__read_f32(ui);
  float height = alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  *out_width = alias_ui__float__clamp(width, min_width, max_width);
  *out_height = alias_ui__float__clamp(height, min_height, max_height);
}

static void alias_ui__image__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t texture_id = alias_ui__ip__read_u32(ui);
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  float s0 = alias_ui__ip__read_f32(ui);
  float t0 = alias_ui__ip__read_f32(ui);
  float s1 = alias_ui__ip__read_f32(ui);
  float t1 = alias_ui__ip__read_f32(ui);
  alias_ui_set_texture(ui, texture_id);
  alias_ui_draw_rectangle(ui, x, y, width, height, s0, t0, s1, t1, 255, 255, 255, 255);
}

void alias_ui_image(struct alias_ui *ui, float width, float height, float s0, float t0,
                     float s1, float t1, uint32_t texture_id) {
  alias_ui__tree__begin_child(ui);
  alias_ui__program__emit_u32(ui, P_IMAGE);
  alias_ui__program__emit_u32(ui, texture_id);
  alias_ui__program__emit_f32(ui, width);
  alias_ui__program__emit_f32(ui, height);
  alias_ui__program__emit_f32(ui, s0);
  alias_ui__program__emit_f32(ui, t0);
  alias_ui__program__emit_f32(ui, s1);
  alias_ui__program__emit_f32(ui, t1);
  alias_ui__tree__end_child(ui);
  alias_ui__stats__set_texture(ui, texture_id);
  alias_ui__stats__draw_rectangle(ui);
}

// font
void alias_ui_font_index(struct alias_ui *ui, uint32_t index) {
  assert(index < ui->font_length);
  assert(ui->tree_scope_length > 0);
  alias_ui__tree__top_scope(ui)->font_index = index;
}

void alias_ui_font_size(struct alias_ui *ui, float size) {
  assert(ui->tree_scope_length > 0);
  alias_ui__tree__top_scope(ui)->font_size = size;
}

void alias_ui_font_color(struct alias_ui *ui, alias_Color _color) {
  assert(ui->tree_scope_length > 0);
  uint8_t r = alias_ui__float__to_color_channel(_color.r);
  uint8_t g = alias_ui__float__to_color_channel(_color.g);
  uint8_t b = alias_ui__float__to_color_channel(_color.b);
  uint8_t a = alias_ui__float__to_color_channel(_color.a);
  uint32_t color = alias_ui__color__pack(r, g, b, a);
  alias_ui__tree__top_scope(ui)->font_color = color;
}

// text
// program: font_index:uint32_t, size:float, color:uint32_t, len:uint32_t, content:[(len + 3) / 4]uint32_t
static void alias_ui__text__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                    float max_height, float *out_width, float *out_height) {
  uint32_t font_index = alias_ui__ip__read_u32(ui);
  float font_size = alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_u32(ui);
  uint32_t len = alias_ui__ip__read_u32(ui);
  const char *string = (const char *)ui->ip;
  alias_ui__ip__advance(ui, (len + 3) >> 2);
  struct alias_ui_Font *font = &ui->font[font_index];
  uint32_t glyph = 0;
  float x = 0;
  float y = 0;
  float width = 0;
  float height = 0;
  for(; *string; ) {
    uint32_t string_advance;
    struct alias_ui_Font_GlyphInfo glyph_info;
    struct alias_ui_Font *glyph_font = font;
    while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
      glyph_font = glyph_font->fallback;
    }

    string += string_advance;
    float glyph_width = (glyph_info.x + glyph_info.width) * font_size;
    float glyph_height = (glyph_info.y + glyph_info.height) * font_size;
    width = alias_ui__float__max(width, x + glyph_width);
    height = alias_ui__float__max(height, y + glyph_height);
    x += glyph_info.advance_x * font_size;
    if(glyph_info.newline) {
      x = 0;
      y += font_size;
    }
  }
  *out_width = alias_ui__float__clamp(width, min_width, max_width);
  *out_height = alias_ui__float__clamp(height, min_height, max_height);

}

static void alias_ui__text__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t font_index = alias_ui__ip__read_u32(ui);
  float font_size = alias_ui__ip__read_f32(ui);
  uint32_t font_color = alias_ui__ip__read_u32(ui);
  uint32_t len = alias_ui__ip__read_u32(ui);
  const char *string = (const char *)ui->ip;
  alias_ui__ip__advance(ui, (len + 3) >> 2);
  struct alias_ui_Font *font = &ui->font[font_index];
  uint32_t glyph = 0;
  float offset_x = 0;
  float offset_y = 0;
  uint8_t r = (font_color >> 24) & 0xFF;
  uint8_t g = (font_color >> 16) & 0xFF;
  uint8_t b = (font_color >> 8) & 0xFF;
  uint8_t a = (font_color >> 0) & 0xFF;
  for(; *string; ) {
    uint32_t string_advance;
    struct alias_ui_Font_GlyphInfo glyph_info;
    struct alias_ui_Font *glyph_font = font;
    while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
      glyph_font = glyph_font->fallback;
    }
    string += string_advance;
    alias_ui_set_texture(ui, glyph_font->texture_id);
    alias_ui_draw_rectangle(ui, x + offset_x + glyph_info.x, y + offset_y + glyph_info.y, glyph_info.width * font_size,
                                      glyph_info.height * font_size, glyph_info.s0, glyph_info.t0, glyph_info.s1, glyph_info.t1, r,
                                      g, b, a);
    offset_x += glyph_info.advance_x * font_size;
    if(glyph_info.newline) {
      offset_x = 0;
      offset_y += font_size;
    }
  }
}

void alias_ui_textv(struct alias_ui *ui, const char *format, va_list ap) {
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  scope->handle_alignment = true;
  alias_ui__tree__begin_child(ui);
  alias_ui__program__emit_u32(ui, P_TEXT);
  alias_ui__program__emit_u32(ui, scope->font_index);
  alias_ui__program__emit_f32(ui, scope->font_size);
  alias_ui__program__emit_u32(ui, scope->font_color);
  va_list ap1, ap2;
  va_copy(ap1, ap);
  va_copy(ap2, ap);
  int size = vcprintf(format, ap1);
  va_end(ap1);
  alias_ui__program__emit_u32(ui, size);
  alias_ui__program__space_for(ui, (size + 3) >> 2);
  char *mut_string = (char *)(ui->program + ui->program_length);
  vsprintf(mut_string, size + 1, format, ap2);
  va_end(ap2);
  ui->program_length += (size + 3) >> 2;
  alias_ui__tree__end_child(ui);

  // fix this?
  uint32_t string_advance;
  uint32_t font_index = scope->font_index;
  const char * string = mut_string;
  struct alias_ui_Font *font = &ui->font[font_index];
  uint32_t glyph = 0;
  for(; *string; ) {
    struct alias_ui_Font_GlyphInfo glyph_info;
    struct alias_ui_Font *glyph_font = font;
    while(glyph_font != NULL && !glyph_font->decode(glyph_font, string, &glyph, &string_advance, &glyph_info)) {
      glyph_font = glyph_font->fallback;
    }
    string += string_advance;
    alias_ui__stats__set_texture(ui, glyph_font->texture_id);
    alias_ui__stats__draw_rectangle(ui);
  }
}

// background color
// program: color:uint32_t
static inline void alias_ui__background_color__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
}

static inline void alias_ui__background_color__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__background_color__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__background_color__layout(struct alias_ui *ui, float min_width, float max_width,
                                                       float min_height, float max_height, float *out_width,
                                                       float *out_height) {
  (void)alias_ui__ip__read_u32(ui);
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, out_width, out_height);
}

static inline void alias_ui__background_color__render(struct alias_ui *ui, float x, float y, float width,
                                                       float height) {
  uint32_t color = alias_ui__ip__read_u32(ui);
  uint8_t r, g, b, a;
  alias_ui__color__unpack(color, &r, &g, &b, &a);
  alias_ui_set_texture(ui, 0);
  alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 0, 0, r, g, b, a);
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_background_color(struct alias_ui *ui, float r, float g, float b, float a) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__background_color__begin_child, alias_ui__background_color__end_child,
                               alias_ui__background_color__end_scope);
  uint32_t color =
      alias_ui__color__pack(alias_ui__float__to_color_channel(r), alias_ui__float__to_color_channel(g),
                             alias_ui__float__to_color_channel(b), alias_ui__float__to_color_channel(a));
  alias_ui__program__emit_u32(ui, P_BACKGROUND_COLOR);
  alias_ui__program__emit_u32(ui, color);
}

// border
// program: color:uint32_t
static inline void alias_ui__border__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__border__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__border__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__border__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                             float max_height, float *out_width, float *out_height) {
  float size = alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_u32(ui);
  float child_width;
  float child_height;
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
  child_width += size * 2;
  child_height += size * 2;
  *out_width = alias_ui__float__clamp(child_width, min_width, max_width);
  *out_height = alias_ui__float__clamp(child_height, min_height, max_height);
}

static inline void alias_ui__border__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t color = alias_ui__ip__read_u32(ui);
  uint8_t r, g, b, a;
  alias_ui__color__unpack(color, &r, &g, &b, &a);
  alias_ui_set_texture(ui, 0);
  alias_ui_draw_rectangle(ui, x, y, width, height, 0, 0, 0, 0, r, g, b, a);
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_border(struct alias_ui *ui, float size, float r, float g, float b, float a) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__background_color__begin_child, alias_ui__background_color__end_child,
                               alias_ui__background_color__end_scope);
  uint32_t color =
      alias_ui__color__pack(alias_ui__float__to_color_channel(r), alias_ui__float__to_color_channel(g),
                             alias_ui__float__to_color_channel(b), alias_ui__float__to_color_channel(a));
  alias_ui__program__emit_u32(ui, P_BORDER);
  alias_ui__program__emit_f32(ui, size);
  alias_ui__program__emit_u32(ui, color);
}

// stack
// program: len:uint32_t, [len]child
//  memory: [len](width:float, height:float, child)
static inline void alias_ui__stack__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  scope->stack.num_children += 1;
}

static inline void alias_ui__stack__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__stack__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__program__fill_u32(ui, scope->stack.hole, scope->stack.num_children);
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__stack__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                            float max_height, float *out_width, float *out_height) {
  float max_child_width = min_width;
  float max_child_height = min_height;
  uint32_t len = alias_ui__ip__read_u32(ui);
  for(uint32_t i = 0; i < len; i++) {
    uint32_t hole = alias_ui__memory__dig(ui, 2);
    float child_width;
    float child_height;
    alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
    alias_ui__memory__fill_f32(ui, hole + 0, child_width);
    alias_ui__memory__fill_f32(ui, hole + 1, child_height);
    max_child_width = alias_ui__float__max(max_child_width, child_width);
    max_child_height = alias_ui__float__max(max_child_height, child_height);
  }
  *out_width = alias_ui__float__min(max_child_width, max_width);
  *out_height = alias_ui__float__min(max_child_height, max_height);
}

static inline void alias_ui__stack__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t len = alias_ui__ip__read_u32(ui);
  for(uint32_t i = 0; i < len; i++) {
    float child_width = alias_ui__mp__read_f32(ui);
    float child_height = alias_ui__mp__read_f32(ui);
    alias_ui__render(ui, x, y, child_width, child_height);
  }
}

void alias_ui_begin_stack(struct alias_ui *ui) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__stack__begin_child, alias_ui__stack__end_child,
                               alias_ui__stack__end_scope);
  alias_ui__program__emit_u32(ui, P_STACK);
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  scope->stack.hole = alias_ui__program__dig(ui, 1);
}

// directional stack
// program: len:uint32_t, [len](isize:uint32_t, msize:uint32_t, weight:float, align:float, child)
//  memory: [len](width:float, height:float, child)
static inline void alias_ui__dstack__space_for(struct alias_ui *ui, uint32_t count) {
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  alias_ui__grow((void **)&scope->dstack.children, sizeof(*scope->dstack.children),
                  scope->dstack.children_length + count, &scope->dstack.children_capacity);
}

static inline void alias_ui__dstack__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  scope->dstack.child_pmark = alias_ui__program__mark(ui);
  scope->dstack.child_mmark = alias_ui__memory__mark(ui);
  alias_ui__dstack__space_for(ui, 1);
  scope->dstack.children_length += 1;
  struct alias_ui_dstack_child *child = &scope->dstack.children[scope->dstack.children_length - 1];
  child->hole = alias_ui__program__dig(ui, 3);
  child->weight = alias_ui__float__max(scope->weight, 0);
  scope->dstack.total_weight += child->weight;
  alias_ui__program__emit_f32(ui, scope->dstack.vertical ? scope->align_x : scope->align_y);
  alias_ui__memory__reserve(ui, 2);
  scope->weight = 0;
  scope->align_x = 0.5;
  scope->align_y = 0.5;
}

static inline void alias_ui__dstack__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  uint32_t psize = alias_ui__program__mark_size(ui, scope->dstack.child_pmark);
  uint32_t msize = alias_ui__memory__mark_size(ui, scope->dstack.child_mmark);
  struct alias_ui_dstack_child *child = &scope->dstack.children[scope->dstack.children_length - 1];
  alias_ui__program__fill_u32(ui, child->hole + 0, psize);
  alias_ui__program__fill_u32(ui, child->hole + 1, msize);
}

static inline void alias_ui__dstack__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__program__fill_u32(ui, scope->dstack.hole, scope->dstack.children_length);

  for(uint32_t i = 0; i < scope->dstack.children_length; i++) {
    struct alias_ui_dstack_child *child = &scope->dstack.children[i];
    alias_ui__program__fill_f32(ui, child->hole + 2, child->weight / scope->dstack.total_weight);
  }

  alias_free(ui->mcb, scope->dstack.children, sizeof(*scope->dstack.children) * scope->dstack.children_capacity, 4);

  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__dstack__create(struct alias_ui *ui, bool vertical) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__dstack__begin_child, alias_ui__dstack__end_child,
                               alias_ui__dstack__end_scope);
  alias_ui__program__emit_u32(ui, vertical ? P_VERTICAL_STACK : P_HORIZONTAL_STACK);
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  scope->handle_alignment = true;
  scope->align_x = 0.5;
  scope->align_y = 0.5;
  scope->dstack.vertical = vertical;
  scope->dstack.hole = alias_ui__program__dig(ui, 1);
  scope->dstack.total_weight = 0;
  scope->dstack.children_capacity = 0;
  scope->dstack.children_length = 0;
  scope->dstack.children = NULL;
}

static inline void alias_ui__dstack__layout(struct alias_ui *ui, bool vertical, float min_width, float max_width,
                                             float min_height, float max_height, float *out_width, float *out_height) {
  uint32_t len = alias_ui__ip__read_u32(ui);
  uint32_t *prepass_ip = ui->ip;
  float max_child_width = min_width;
  float max_child_height = min_height;
  for(uint32_t pass = 0; pass < 2; pass++) {
    ui->ip = prepass_ip;
    for(uint32_t i = 0; i < len; i++) {
      uint32_t psize = alias_ui__ip__read_u32(ui);
      uint32_t msize = alias_ui__ip__read_u32(ui);
      float weight = alias_ui__ip__read_f32(ui);
      if(pass != (weight > 0 ? 1 : 0)) {
        alias_ui__ip__advance(ui, psize - 3);
        alias_ui__mp__advance(ui, msize);
        continue;
      }
      (void)alias_ui__ip__read_f32(ui);
      float child_width;
      float child_height;
      uint32_t mhole = alias_ui__memory__dig(ui, 2);
      alias_ui__layout(ui, min_width, max_width, min_height, max_height, &child_width, &child_height);
      if(pass == 1) {
        if(!vertical) {
          child_width = weight * max_width;
        } else {
          child_height = weight * max_height;
        }
      }
      alias_ui__memory__fill_f32(ui, mhole + 0, child_width);
      alias_ui__memory__fill_f32(ui, mhole + 1, child_height);
      max_child_width = alias_ui__float__max(max_child_width, child_width);
      max_child_height = alias_ui__float__max(max_child_height, child_height);
      if(pass == 0) {
        if(vertical) {
          min_height = alias_ui__float__max(min_height - child_height, 0);
          max_height = alias_ui__float__max(max_height - child_height, 0);
        } else {
          min_width = alias_ui__float__max(min_width - child_width, 0);
          max_width = alias_ui__float__max(max_width - child_width, 0);
        }
      }
    }
  }
  *out_width = alias_ui__float__min(max_width, max_child_width);
  *out_height = alias_ui__float__min(max_height, max_child_height);
}

static inline void alias_ui__dstack__render(struct alias_ui *ui, bool vertical, float x, float y, float width,
                                             float height) {
  uint32_t len = alias_ui__ip__read_u32(ui);
  for(uint32_t i = 0; i < len; i++) {
    (void)alias_ui__ip__read_u32(ui);
    (void)alias_ui__ip__read_u32(ui);
    (void)alias_ui__ip__read_f32(ui);
    float align = alias_ui__ip__read_f32(ui);
    float child_width = alias_ui__mp__read_f32(ui);
    float child_height = alias_ui__mp__read_f32(ui);
    alias_ui__render(ui, vertical ? x + alias_ui__float__max(width - child_width, 0) * align : x,
                      vertical ? y : y + alias_ui__float__max(height - child_height, 0) * align, child_width,
                      child_height);
    if(!vertical) {
      x += child_width;
    } else {
      y += child_height;
    }
  }
}

void alias_ui_begin_horizontal_stack(struct alias_ui *ui) {
  alias_ui__dstack__create(ui, false);
}

void alias_ui_begin_vertical_stack(struct alias_ui *ui) {
  alias_ui__dstack__create(ui, true);
}

void alias_ui_stack_weight(struct alias_ui *ui, float weight) {
  alias_ui__tree__top_scope(ui)->weight = weight;
}

void alias_ui_end_stack(struct alias_ui *ui) {
  alias_ui__tree__end_scope(ui);
}

// named scope
// program: child
//  memory: child
static inline void alias_ui__named_scope__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__named_scope__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__named_scope__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

void alias_ui_named_scope(struct alias_ui *ui, const char *format, ...) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__named_scope__begin_child, alias_ui__named_scope__end_child,
                               alias_ui__named_scope__end_scope);
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  va_list ap;
  va_start(ap, format);
  int size = vcprintf(format, ap);
  va_end(ap);
  char *buffer = alloca(size + 1);
  va_start(ap, format);
  vsprintf(buffer, size + 1, format, ap);
  va_end(ap);
  uint64_t hash =
      0xCBF29CE484222325ul ^
      (scope->named_scope_index < ui->named_scope_length ? ui->named_scope[scope->named_scope_index].hash : 0);
  while(*buffer) {
    hash ^= *buffer++;
    hash *= 0x00000100000001B3ul;
  }
  for(uint32_t i = 0; i < ui->named_scope_length; i++) {
    if(ui->named_scope[i].hash == hash) {
      scope->named_scope_index = i;
      return;
    }
  }
  alias_ui__grow((void **)&ui->named_scope, sizeof(*ui->named_scope), ui->named_scope_length + 1,
                  &ui->named_scope_capacity);
  ui->named_scope[ui->named_scope_length].hash = hash;
  ui->named_scope[ui->named_scope_length].query_capacity = 0;
  ui->named_scope[ui->named_scope_length].query_rects = NULL;
  ui->named_scope[ui->named_scope_length].slot_capacity = 0;
  ui->named_scope[ui->named_scope_length].slot = NULL;
  scope->named_scope_index = ui->named_scope_length++;
}

void alias_ui_set_uint32(struct alias_ui *ui, uint32_t slot_index, uint32_t value) {
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
  alias_ui__grow((void **)&named_scope->slot, sizeof(*named_scope->slot), slot_index, &named_scope->slot_capacity);
  named_scope->slot[slot_index] = value;
}

void alias_ui_set_float(struct alias_ui *ui, uint32_t slot_index, float value) {
  union {
    uint32_t u;
    float f;
  } flip = {.f = value};
  alias_ui_set_uint32(ui, slot_index, flip.u);
}

uint32_t alias_ui_get_uint32(struct alias_ui *ui, uint32_t slot_index) {
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
  if(slot_index < named_scope->slot_capacity) {
    return named_scope->slot[slot_index];
  } else {
    return 0;
  }
}

float alias_ui_get_float(struct alias_ui *ui, uint32_t slot_index) {
  union {
    uint32_t u;
    float f;
  } flip = {.u = alias_ui_get_uint32(ui, slot_index)};
  return flip.f;
}

// size
// program: width:float, height:float, child
//  memory: child
static inline void alias_ui__size__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__size__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__size__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__size__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                           float max_height, float *out_width, float *out_height) {
  float width = alias_ui__ip__read_f32(ui);
  float height = alias_ui__ip__read_f32(ui);
  float unused_width;
  float unused_height;
  alias_ui__layout(ui, width, width, height, height, &unused_width, &unused_height);
  *out_width = alias_ui__float__clamp(width, min_width, max_width);
  *out_height = alias_ui__float__clamp(height, min_height, max_height);
}

static inline void alias_ui__size__render(struct alias_ui *ui, float x, float y, float width, float height) {
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_size(struct alias_ui *ui, float width, float height) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__size__begin_child, alias_ui__size__end_child,
                               alias_ui__size__end_scope);
  alias_ui__program__emit_u32(ui, P_SIZE);
  alias_ui__program__emit_f32(ui, width);
  alias_ui__program__emit_f32(ui, height);
}

// width
// program: width:float, child
//  memory: child
static inline void alias_ui__width__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__width__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__width__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__width__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                            float max_height, float *out_width, float *out_height) {
  float width = alias_ui__ip__read_f32(ui);
  float unused_width;
  float height;
  alias_ui__layout(ui, width, width, min_height, max_height, &unused_width, &height);
  *out_width = alias_ui__float__clamp(width, min_width, max_width);
  *out_height = alias_ui__float__clamp(height, min_height, max_height);
}

static inline void alias_ui__width__render(struct alias_ui *ui, float x, float y, float width, float height) {
  (void)alias_ui__ip__read_f32(ui);
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_width(struct alias_ui *ui, float width) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__width__begin_child, alias_ui__width__end_child,
                               alias_ui__width__end_scope);
  alias_ui__program__emit_u32(ui, P_WIDTH);
  alias_ui__program__emit_f32(ui, width);
}

// height
// program: height:float, child
//  memory: child
static inline void alias_ui__height__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__height__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__height__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__height__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                             float max_height, float *out_width, float *out_height) {
  float height = alias_ui__ip__read_f32(ui);
  float width;
  float unused_height;
  alias_ui__layout(ui, min_width, max_width, height, height, &width, &unused_height);
  *out_width = alias_ui__float__clamp(width, min_width, max_width);
  *out_height = alias_ui__float__clamp(height, min_height, max_height);
}

static inline void alias_ui__height__render(struct alias_ui *ui, float x, float y, float width, float height) {
  (void)alias_ui__ip__read_f32(ui);
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_height(struct alias_ui *ui, float height) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__height__begin_child, alias_ui__height__end_child,
                               alias_ui__height__end_scope);
  alias_ui__program__emit_u32(ui, P_HEIGHT);
  alias_ui__program__emit_f32(ui, height);
}

// align
// program: x:float, y:float, child
//  memory: width:float, height:float, child
static inline void alias_ui__align__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__memory__reserve(ui, 2);
}

static inline void alias_ui__align__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__align__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__align__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                            float max_height, float *out_width, float *out_height) {
  (void)alias_ui__ip__read_f32(ui);
  (void)alias_ui__ip__read_f32(ui);
  float width;
  float height;
  uint32_t mhole = alias_ui__memory__dig(ui, 2);
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
  alias_ui__memory__fill_f32(ui, mhole + 0, width);
  alias_ui__memory__fill_f32(ui, mhole + 1, height);
  *out_width = max_width;
  *out_height = max_height;
}

static inline void alias_ui__align__render(struct alias_ui *ui, float x, float y, float width, float height) {
  float align_x = alias_ui__ip__read_f32(ui);
  float align_y = alias_ui__ip__read_f32(ui);
  float child_width = alias_ui__mp__read_f32(ui);
  float child_height = alias_ui__mp__read_f32(ui);
  alias_ui__render(ui, x + (width - child_width) * align_x, y + (height - child_height) * align_y, child_width,
                    child_height);
}

void alias_ui_align(struct alias_ui *ui, float x, float y) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__align__begin_child, alias_ui__align__end_child,
                               alias_ui__align__end_scope);
  alias_ui__program__emit_u32(ui, P_ALIGN);
  alias_ui__program__emit_f32(ui, x);
  alias_ui__program__emit_f32(ui, y);
}

// alignx
// program: x:float, child
//  memory: width:float, child
static inline void alias_ui__alignx__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__memory__reserve(ui, 1);
}

static inline void alias_ui__alignx__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__alignx__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__alignx__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                             float max_height, float *out_width, float *out_height) {
  (void)alias_ui__ip__read_f32(ui);
  float width;
  float height;
  uint32_t mhole = alias_ui__memory__dig(ui, 1);
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
  alias_ui__memory__fill_f32(ui, mhole, width);
  *out_width = max_width;
  *out_height = alias_ui__float__clamp(height, min_height, min_height);
}

static inline void alias_ui__alignx__render(struct alias_ui *ui, float x, float y, float width, float height) {
  float align_x = alias_ui__ip__read_f32(ui);
  float child_width = alias_ui__mp__read_f32(ui);
  alias_ui__render(ui, x + (width - child_width) * align_x, y, child_width, height);
}

void alias_ui_align_x(struct alias_ui *ui, float x) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__alignx__begin_child, alias_ui__alignx__end_child,
                               alias_ui__alignx__end_scope);
  alias_ui__program__emit_u32(ui, P_ALIGN_X);
  alias_ui__program__emit_f32(ui, x);
}

// aligny
// program: y:float, child
//  memory: height:float, child
static inline void alias_ui__aligny__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__memory__reserve(ui, 1);
}

static inline void alias_ui__aligny__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__aligny__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__aligny__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                             float max_height, float *out_width, float *out_height) {
  (void)alias_ui__ip__read_f32(ui);
  float width;
  float height;
  uint32_t mhole = alias_ui__memory__dig(ui, 1);
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, &width, &height);
  alias_ui__memory__fill_f32(ui, mhole, height);
  *out_width = alias_ui__float__clamp(width, min_width, min_width);
  *out_height = max_height;
}

static inline void alias_ui__aligny__render(struct alias_ui *ui, float x, float y, float width, float height) {
  float align_y = alias_ui__ip__read_f32(ui);
  float child_height = alias_ui__mp__read_f32(ui);
  alias_ui__render(ui, x, y + (height - child_height) * align_y, width, child_height);
}

void alias_ui_align_y(struct alias_ui *ui, float y) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__aligny__begin_child, alias_ui__aligny__end_child,
                               alias_ui__aligny__end_scope);
  alias_ui__program__emit_u32(ui, P_ALIGN_Y);
  alias_ui__program__emit_f32(ui, y);
}

// padding
// program: left:float, top:float, right:float, bottom:float, child
//  memory: child
static inline void alias_ui__padding__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
}

static inline void alias_ui__padding__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__padding__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__padding__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                              float max_height, float *out_width, float *out_height) {
  float left = alias_ui__ip__read_f32(ui);
  float top = alias_ui__ip__read_f32(ui);
  float right = alias_ui__ip__read_f32(ui);
  float bottom = alias_ui__ip__read_f32(ui);
  float padding_width = left + right;
  float padding_height = top + bottom;
  float child_width;
  float child_height;
  float child_min_width = alias_ui__float__max(min_width - padding_width, 0);
  float child_max_width = alias_ui__float__max(max_width - padding_width, 0);
  float child_min_height = alias_ui__float__max(min_height - padding_height, 0);
  float child_max_height = alias_ui__float__max(max_height - padding_height, 0);
  alias_ui__layout(ui, child_min_width, child_max_width, child_min_height, child_max_height, &child_width, &child_height);
  *out_width = alias_ui__float__clamp(child_width + padding_width, min_width, max_width);
  *out_height = alias_ui__float__clamp(child_height + padding_height, min_height, max_height);
}

static inline void alias_ui__padding__render(struct alias_ui *ui, float x, float y, float width, float height) {
  float left = alias_ui__ip__read_f32(ui);
  float top = alias_ui__ip__read_f32(ui);
  float right = alias_ui__ip__read_f32(ui);
  float bottom = alias_ui__ip__read_f32(ui);
  float padding_width = left + right;
  float padding_height = top + bottom;
  alias_ui__render(ui, x + left, y + top, width - padding_width, height - padding_height);
}

void alias_ui_padding(struct alias_ui *ui, float left, float top, float right, float bottom) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__padding__begin_child, alias_ui__padding__end_child,
                               alias_ui__padding__end_scope);
  alias_ui__program__emit_u32(ui, P_PADDING);
  alias_ui__program__emit_f32(ui, left);
  alias_ui__program__emit_f32(ui, top);
  alias_ui__program__emit_f32(ui, right);
  alias_ui__program__emit_f32(ui, bottom);
}

// query
// program: named_scope:uint32_t, query_index:uint32_t, child
//  memory: child
static inline void alias_ui__query__begin_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {}

static inline void alias_ui__query__end_child(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_scope(ui);
}

static inline void alias_ui__query__end_scope(struct alias_ui *ui, struct alias_ui_tree_scope *scope) {
  alias_ui__tree__end_child(ui);
}

static inline void alias_ui__query__layout(struct alias_ui *ui, float min_width, float max_width, float min_height,
                                            float max_height, float *out_width, float *out_height) {
  (void)alias_ui__ip__read_u32(ui);
  (void)alias_ui__ip__read_u32(ui);
  alias_ui__layout(ui, min_width, max_width, min_height, max_height, out_width, out_height);
}

static inline void alias_ui__query__render(struct alias_ui *ui, float x, float y, float width, float height) {
  uint32_t named_scope_index = alias_ui__ip__read_u32(ui);
  uint32_t query_index = alias_ui__ip__read_u32(ui);
  struct alias_ui_named_scope *named_scope = &ui->named_scope[named_scope_index];
  named_scope->query_rects[query_index * 4 + 0] = x;
  named_scope->query_rects[query_index * 4 + 1] = y;
  named_scope->query_rects[query_index * 4 + 2] = width;
  named_scope->query_rects[query_index * 4 + 3] = height;
  alias_ui__render(ui, x, y, width, height);
}

void alias_ui_query(struct alias_ui *ui, uint32_t query_index, float *out_rect) {
  alias_ui__tree__begin_child(ui);
  alias_ui__tree__begin_scope(ui, alias_ui__query__begin_child, alias_ui__query__end_child,
                               alias_ui__query__end_scope);
  struct alias_ui_tree_scope *scope = alias_ui__tree__top_scope(ui);
  alias_ui__program__emit_u32(ui, P_QUERY);
  alias_ui__program__emit_u32(ui, scope->named_scope_index);
  alias_ui__program__emit_u32(ui, query_index);
  struct alias_ui_named_scope *named_scope = &ui->named_scope[scope->named_scope_index];
  alias_ui__grow((void **)&named_scope->query_rects, sizeof(*named_scope->query_rects) * 4, query_index + 1,
                  &named_scope->query_capacity);
  out_rect[0] = named_scope->query_rects[query_index * 4 + 0];
  out_rect[1] = named_scope->query_rects[query_index * 4 + 1];
  out_rect[2] = named_scope->query_rects[query_index * 4 + 2];
  out_rect[3] = named_scope->query_rects[query_index * 4 + 3];
}

static inline void alias_ui__layout__initialize(struct alias_ui *ui) {
  alias_ui__ip__initialize(ui);
  alias_ui__memory__initialize(ui);
}

static inline void alias_ui__layout(struct alias_ui *ui, float aw, float bw, float ah, float bh, float *oh,
                                     float *ow) {
  uint32_t code = alias_ui__ip__read_u32(ui);
  switch(code) {
  case P_TERMINATE:
    break;
  case P_EMPTY_FILL:
    alias_ui__empty_fill__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_COLOR_FILL:
    alias_ui__color_fill__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_TEXT:
    alias_ui__text__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_IMAGE:
    alias_ui__image__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_BACKGROUND_COLOR:
    alias_ui__background_color__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_BORDER:
    alias_ui__border__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_STACK:
    alias_ui__stack__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_HORIZONTAL_STACK:
    alias_ui__dstack__layout(ui, false, aw, bw, ah, bh, oh, ow);
    break;
  case P_VERTICAL_STACK:
    alias_ui__dstack__layout(ui, true, aw, bw, ah, bh, oh, ow);
    break;
  case P_SIZE:
    alias_ui__size__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_WIDTH:
    alias_ui__width__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_HEIGHT:
    alias_ui__height__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_ALIGN:
    alias_ui__align__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_ALIGN_X:
    alias_ui__alignx__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_ALIGN_Y:
    alias_ui__aligny__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_PADDING:
    alias_ui__padding__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  case P_QUERY:
    alias_ui__query__layout(ui, aw, bw, ah, bh, oh, ow);
    break;
  }
}

static inline void alias_ui__render__initialize(struct alias_ui *ui) {
  alias_ui__ip__initialize(ui);
  alias_ui__mp__initialize(ui);
  alias_ui__vertex__initialize(ui);
  alias_ui__index__initialize(ui);
  alias_ui__group__initialize(ui);
  ui->texture_id = 0;
  alias_ui__group__advance(ui);
}

static inline void alias_ui__render(struct alias_ui *ui, float x, float y, float w, float h) {
  uint32_t code = alias_ui__ip__read_u32(ui);
  switch(code) {
  case P_TERMINATE:
    break;
  case P_EMPTY_FILL:
    alias_ui__empty_fill__render(ui, x, y, w, h);
    break;
  case P_COLOR_FILL:
    alias_ui__color_fill__render(ui, x, y, w, h);
    break;
  case P_TEXT:
    alias_ui__text__render(ui, x, y, w, h);
    break;
  case P_IMAGE:
    alias_ui__image__render(ui, x, y, w, h);
    break;
  case P_BACKGROUND_COLOR:
    alias_ui__background_color__render(ui, x, y, w, h);
    break;
  case P_BORDER:
    alias_ui__border__render(ui, x, y, w, h);
    break;
  case P_STACK:
    alias_ui__stack__render(ui, x, y, w, h);
    break;
  case P_HORIZONTAL_STACK:
    alias_ui__dstack__render(ui, false, x, y, w, h);
    break;
  case P_VERTICAL_STACK:
    alias_ui__dstack__render(ui, true, x, y, w, h);
    break;
  case P_SIZE:
    alias_ui__size__render(ui, x, y, w, h);
    break;
  case P_WIDTH:
    alias_ui__width__render(ui, x, y, w, h);
    break;
  case P_HEIGHT:
    alias_ui__height__render(ui, x, y, w, h);
    break;
  case P_ALIGN:
    alias_ui__align__render(ui, x, y, w, h);
    break;
  case P_ALIGN_X:
    alias_ui__alignx__render(ui, x, y, w, h);
    break;
  case P_ALIGN_Y:
    alias_ui__aligny__render(ui, x, y, w, h);
    break;
  case P_PADDING:
    alias_ui__padding__render(ui, x, y, w, h);
    break;
  case P_QUERY:
    alias_ui__query__render(ui, x, y, w, h);
    break;
  }
}
static inline bool alias_ui__dev_font__decode(struct alias_ui_Font *font, const char *string, uint32_t *inout_glyph,
                                               uint32_t *out_num_bytes, struct alias_ui_Font_GlyphInfo *out_info) {
  uint32_t glyph = *string;
  *inout_glyph = glyph;
  *out_num_bytes = 1;
  uint32_t row = glyph >> 4;
  uint32_t col = glyph & 15;
  out_info->newline = glyph == '\n';
  out_info->advance_x = 0.5f;
  out_info->x = 0.0f;
  out_info->y = 0.0f;
  out_info->width = 1.33f;
  out_info->height = 1.33f;
  if(row < 2 || glyph == ' ') {
    out_info->width = 0;
    out_info->height = 0;
  } else {
    row -= 2;
  }
  out_info->s0 = (float)(col + 0) / 16.0f;
  out_info->t0 = (float)(row + 0) / 16.0f;
  out_info->s1 = (float)(col + 1) / 16.0f;
  out_info->t1 = (float)(row + 1) / 16.0f;
  return true;
}

static struct alias_ui_Font alias_ui__dev_font = {
  .texture_id = 0,
  .decode = alias_ui__dev_font__decode,
};

// --------------------------------------------------------------------------------------------------------------------

#ifdef UNICAT_UI_ENABLE_FREETYPE
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_OUTLINE_H

#define MULTILINE_STRING(...) #__VA_ARGS__

const char * alias_ui_freetype_opengl_fragment_shader(uint32_t major, uint32_t minor) {
  return 
MULTILINE_STRING(
vec2 alias_ui_freetype_snorm16_decode2(uvec2 x) {
  return vec2(x) / 65535.0 - 0.5;
}

float alias_ui_freetype_draw_curve(vec2 p0, vec2 p1, vec2 p2, float inverse_pixel_width) {
  vec2 a = p0 - 2.0*p1 + p2;
  vec2 b = p0 - p1;
  vec2 c = p0;
  vec2 t;
  float si = b.y*b.y - a.y*c.y;
  float s = sqrt(max(si, 0.0));
  t = vec2(b.y - s, b.y + s) / a.y;
  vec2 x = (a.x*t - 2.0*b.x)*t + c.x;
  vec2 weight = clamp(x * inverse_pixel_width + 0.5, 0.0, 1.0) * step(0.0, t) * step(-1.0, -t);
  return dot(weight, vec2(1, -1)) * step(0.0, si);
}

float alias_ui_freetype_draw_layer(vec2 uv, vec2 inverse_pixel_width, uint curve_start, uint curve_length, bool super_sampling) {
  float alpha = 0.0;
  uint row = curve_start;
  uint end = row + curve_length;
  while(row < end) {
    uvec4 contour = alias_ui_freetype_user_font(row++);
    uint count = contour.x;
    vec2 a = alias_ui_freetype_snorm16_decode2(contour.zw) * scale - uv;
    for(uint i = 0u; i < count; i++) {
      uvec4 curve = alias_ui_freetype_user_font(row++);
      vec2 b = alias_ui_freetype_snorm16_decode2(curve.xy) * scale - uv;
      vec2 c = alias_ui_freetype_snorm16_decode2(curve.zw) * scale - uv;
      vec3 x = vec3(a.x, b.x, c.x);
      vec3 y = vec3(a.y, b.y, c.y);
      if(!all(lessThan(y, vec3(0))) && !all(greaterThan(y, vec3(0)))) {
        alpha += alias_ui_freetype_draw_curve(a, b, c, inverse_pixel_width.x);
      }
      if(super_sampling && !all(lessThan(x, vec3(0))) && !all(greaterThan(x, vec3(0)))) {
        alpha += alias_ui_freetype_draw_curve(vec2(a.y, -a.x), vec2(b.y, -b.x), vec2(c.y, -c.x), inverse_pixel_width.y);
      }
      a = c;
    }
  }
  return alpha * (float(!super_sampling)*0.5+0.5);
}

vec4 alias_ui_freetype_draw_glyph(vec4 default_color, vec2 uv, uint glyph_index, bool super_sampling) {
  vec2 inverse_pixel_width = 1.0 / fwidth(uv);
  uvec4 glyph = alias_ui_freetype_user_font(glyph_index);
  if(glyph.y == 1u) {
    float alpha = alias_ui_freetype_draw_layer(uv, inverse_pixel_width, glyph.z, glyph.w, super_sampling);
    return vec4(default_color.rgb, default_color.a * alpha);
  } else {
    vec4 color = vec4(0);
    for(uint i = 0u; i < glyph.y; i++) {
      uvec4 layer = alias_ui_freetype_user_font(glyph.x + i);
      float alpha = alias_ui_freetype_draw_layer(uv, inverse_pixel_width, glyph.z, glyph.w, super_sampling);
      
    }
    return color;
  }
}
  );
}

#undef MULTILINE_STRING

void alias_ui_freetype_texture_callback(struct alias_ui *ui, uint32_t (*f)(uint32_t length, void ** ptr)) {
  ui->freetype_texture_callback = f;
}

struct alias_ui_freetype__Counter {
  uint32_t num_points;
  uint32_t num_contours;
};

static int alias_ui_freetype__counter_move(const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
  c->num_points += 1;
  c->num_contours += 1;
  return 0;
}

static int alias_ui_freetype__counter_line(const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
  c->num_points += 2;
  return 0;
}

static int alias_ui_freetype__counter_conic(const FT_Vector * control, const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
  c->num_points += 2;
  return 0;
}

static int alias_ui_freetype__counter_cubic(const FT_Vector * control1, const FT_Vector * control2, const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Counter *c = (struct alias_ui_freetype__Counter *)user;
  c->num_points += 4;
  return 0;
}

struct alias_ui_freetype__Emitter {
  float scale;
  uint16_t * data;
  uint32_t contour_data_index_start;
  uint32_t data_index;
  float ax;
  float ay;
};

static void alias_ui_freetype__Emitter_flush(struct alias_ui_freetype__Emitter *e) {
  if(e->contour_data_index_start > 0) {
    e->data[e->contour_data_index_start * 4 + 0] = e->data_index - e->data[e->contour_data_index_start * 4 + 0];
  }
  e->contour_data_index_start = 0;
}

static void alias_ui_freetype__Emitter_contour(struct alias_ui_freetype__Emitter *e, float ax, float ay) {
  alias_ui_freetype__Emitter_flush(e);
  e->contour_data_index_start = e->data_index;
  e->data[e->data_index * 4 + 0] = 0;
  e->data[e->data_index * 4 + 1] = 0;
  e->data[e->data_index * 4 + 2] = (uint16_t)((int32_t)e->ax + 32768);
  e->data[e->data_index * 4 + 3] = (uint16_t)((int32_t)e->ay + 32768);
  e->data_index++;
  e->ax = ax;
  e->ay = ay;
}

static void alias_ui_freetype__Emitter_curve(struct alias_ui_freetype__Emitter *e, float bx, float by, float cx, float cy) {
  float x = e->ax - 2.0f*bx + cx;
  float y = e->ay - 2.0f*by + cy;
  if(fabs(x) < 0.00001f || fabs(y) < 0.00001f) {
    bx += (e->ax - cx) * 0.1f;
    by += (e->ay - cy) * 0.1f;
  }
  e->data[e->data_index * 4 + 0] = (uint16_t)((int32_t)bx + 32768);
  e->data[e->data_index * 4 + 1] = (uint16_t)((int32_t)by + 32768);
  e->data[e->data_index * 4 + 2] = (uint16_t)((int32_t)cx + 32768);
  e->data[e->data_index * 4 + 3] = (uint16_t)((int32_t)cy + 32768);
  e->data_index++;
  e->ax = cx;
  e->ay = cy;
}

static int alias_ui_freetype__emitter_move(const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
  alias_ui_freetype__Emitter_contour(e, (float)to->x * e->scale, (float)to->y * e->scale);
  return 0;
}

static int alias_ui_freetype__emitter_line(const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
  float cx = (float)to->x * e->scale;
  float cy = (float)to->y * e->scale;
  float bx = (e->ax + cx) * 0.5f;
  float by = (e->ay + cy) * 0.5f;
  alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
  return 0;
}

static int alias_ui_freetype__emitter_conic(const FT_Vector * control, const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
  float bx = (float)control->x * e->scale;
  float by = (float)control->y * e->scale;
  float cx = (float)to->x * e->scale;
  float cy = (float)to->y * e->scale;
  alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
  return 0;

}

static int alias_ui_freetype__emitter_cubic(const FT_Vector * control1, const FT_Vector * control2, const FT_Vector * to, void * user) {
  struct alias_ui_freetype__Emitter *e = (struct alias_ui_freetype__Emitter *)user;
  // a      b   c  d   e
  // start c1 mid c2 end
  float control1x = (float)control1->x * e->scale;
  float control1y = (float)control1->y * e->scale;
  float control2x = (float)control2->x * e->scale;
  float control2y = (float)control2->y * e->scale;
  float ex = (float)to->x * e->scale;
  float ey = (float)to->y * e->scale;
  float bx = e->ax + (control1x - e->ax) * 0.75;
  float by = e->ax + (control1y - e->ay) * 0.75;
  float dx = ex + (control2x - ex) * 0.75;
  float dy = ey + (control2y - ey) * 0.75;
  float cx = (bx + dx) * 0.5;
  float cy = (by + dy) * 0.5;
  alias_ui_freetype__Emitter_curve(e, bx, by, cx, cy);
  alias_ui_freetype__Emitter_curve(e, dx, dy, ex, ey);
  return 0;
}

struct alias_ui_freetype_font_character {
  uint32_t charcode;
  uint32_t have_bold        : 1;
  uint32_t have_italic      : 1;
  uint32_t have_bold_italic : 1;
  uint32_t glyph_index      : 29;
};

struct alias_ui_freetype_font_glyph {
  float advance_x;
  float x;
  float y;
  float width;
  float height;
};

struct alias_ui_freetype_font {
  struct alias_ui_font root;

  struct alias_ui_freetype_font_character * character_map;
  uint32_t num_characters;

  struct alias_ui_freetype_font_glyph * glyph_map;
  uint32_t num_glyphs;
};

static int alias_ui_freetype_character_map_compare(const void * a, const void * b) {
  uint32_t charcode = *(const uint32_t *)a;
  const struct alias_ui_freetype_font_character * character = (const struct alias_ui_freetype_font_character *)b;
  return (int)((int64_t)character->charcode - (int64_t)a);
}

static bool alias_ui_freetype_font_decode(struct alias_ui_font *_font, const char *string, uint32_t *inout_glyph, uint32_t *out_num_bytes, struct alias_ui_font_glyph_info *out_info) {
  struct alias_ui_freetype_font * font = (struct alias_ui_freetype_font *)_font->user_data;
  
  uint32_t charcode = *string;
  struct alias_ui_freetype_font_character * character = bsearch(&charcode, font->character_map, font->num_characters, sizeof(*font->character_map), alias_ui_freetype_character_map_compare);
  *out_num_bytes = 1;

  if(character != NULL) {
    *inout_glyph = character - font->character_map;
  } else {
    return false;
  }

  out_info->newline == *string == '\n';
  out_info->advance_x = font->glyph_map[*inout_glyph].advance_x;
  out_info->x = font->glyph_map[*inout_glyph].x;
  out_info->y = font->glyph_map[*inout_glyph].y;
  out_info->width = font->glyph_map[*inout_glyph].width;
  out_info->height = font->glyph_map[*inout_glyph].height;
  out_info->s0 = 0.0f + *inout_glyph;
  out_info->t0 = 0.0f;
  out_info->s1 = 1.0f + *inout_glyph;
  out_info->t1 = 1.0f;
  return true;
}

struct alias_ui_font * alias_ui_freetype_create_font(struct alias_ui *ui, const char ** filenames, uint32_t num_filenames) {
  FT_Library library;
  FT_Init_FreeType(&library);

  struct alias_ui_freetype_font * font = malloc(sizeof(*font));

  uint32_t num_faces = num_filenames;
  FT_Face * faces = malloc(sizeof(FT_Face) * num_faces);

  for(uint32_t i = 0; i < num_filenames; i++) {
    FT_New_Face(library, filenames[i], 0, &faces[i]);
  }

  struct {
    struct {
      uint32_t face;
      uint32_t glyph;
    } style[4];
  } *building_character_map = NULL;

  font->num_glyphs = 0;
  for(uint32_t charcode = ' '; charcode < 0x1FFFFF; charcode++) {
    uint32_t face_index = 0;
    FT_UInt glyph_index = 0;
    struct {
      uint32_t face;
      uint32_t glyph;
    } style[4] = {{-1,-1},{-1,-1},{-1,-1},{-1,-1}};
    for(; face_index < num_faces; face_index++) {
      glyph_index = FT_Get_Char_Index(faces[face_index], charcode);
      if(glyph_index != 0) {
        if(style[faces[face_index]->style_flags].face == -1) {
          style[faces[face_index]->style_flags].face = face_index;
          style[faces[face_index]->style_flags].glyph = glyph_index;
        }
      }
    }
    if(style[0].face == -1) {
      continue;
    }
    font->character_map = realloc(font->character_map, sizeof(*font->character_map) * (font->num_characters + 1));
    building_character_map = realloc(building_character_map, sizeof(*building_character_map) * (font->num_characters + 1));

    font->character_map[font->num_characters].charcode = charcode;
    font->character_map[font->num_characters].glyph_index = font->num_glyphs;
    font->character_map[font->num_characters].have_bold = style[1].face != -1;
    font->character_map[font->num_characters].have_italic = style[2].face != -1;
    font->character_map[font->num_characters].have_bold_italic = style[3].face != -1;
    building_character_map[font->num_characters].style[0].face = style[0].face;
    building_character_map[font->num_characters].style[0].glyph = style[0].glyph;
    building_character_map[font->num_characters].style[1].face = style[1].face;
    building_character_map[font->num_characters].style[1].glyph = style[1].glyph;
    building_character_map[font->num_characters].style[2].face = style[2].face;
    building_character_map[font->num_characters].style[2].glyph = style[2].glyph;
    building_character_map[font->num_characters].style[3].face = style[3].face;
    building_character_map[font->num_characters].style[3].glyph = style[3].glyph;

    font->num_glyphs += 1 + 
      font->character_map[font->num_characters].have_bold +
      font->character_map[font->num_characters].have_italic +
      font->character_map[font->num_characters].have_bold_italic;

    font->num_characters++;
  }


  struct alias_ui_freetype__Counter counter;
  memset(&counter, 0, sizeof(counter));

  FT_Outline_Funcs counter_funcs;
  memset(&counter_funcs, 0, sizeof(counter_funcs));
  counter_funcs.move_to = alias_ui_freetype__counter_move;
  counter_funcs.line_to = alias_ui_freetype__counter_line;
  counter_funcs.conic_to = alias_ui_freetype__counter_conic;
  counter_funcs.cubic_to = alias_ui_freetype__counter_cubic;

  for(uint32_t character_index = 0; character_index < font->num_characters; character_index++) {
    for(uint32_t style_index = 0; style_index < 4; style_index) {
      if(building_character_map[character_index].style[style_index].face != -1) {
        FT_Face face = faces[building_character_map[character_index].style[style_index].face];
        FT_Load_Glyph(
          face,
          building_character_map[character_index].style[style_index].glyph,
          FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE | FT_LOAD_LINEAR_DESIGN
        );
        FT_Outline_Decompose(&face->glyph->outline, &counter_funcs, &counter);

      }
    }
  }

  FT_Outline_Funcs emitter_funcs;
  memset(&emitter_funcs, 0, sizeof(emitter_funcs));
  emitter_funcs.move_to = alias_ui_freetype__emitter_move;
  emitter_funcs.line_to = alias_ui_freetype__emitter_line;
  emitter_funcs.conic_to = alias_ui_freetype__emitter_conic;
  emitter_funcs.cubic_to = alias_ui_freetype__emitter_cubic;

  uint32_t length = font->num_glyphs + counter.num_contours + (counter.num_points - counter.num_contours) * 2;

  struct alias_ui_freetype__Emitter emitter;
  memset(&emitter, 0, sizeof(emitter));
  ui->freetype_texture_callback(length, (void **)&emitter.data);
  emitter.data_index = font->num_characters;

  font->glyph_map = malloc(sizeof(*font->glyph_map) * font->num_glyphs);

  uint32_t glyph_index = 0;
  for(uint32_t character_index = 0; character_index < font->num_characters; character_index++) {
    for(uint32_t style_index = 0; style_index < 4; style_index) {
      if(building_character_map[character_index].style[style_index].face != -1) {
        FT_Face face = faces[building_character_map[character_index].style[style_index].face];
        FT_Load_Glyph(
          face,
          building_character_map[character_index].style[style_index].glyph,
          FT_LOAD_NO_HINTING | FT_LOAD_NO_SCALE
        );
        emitter.scale = 65535.0f / (float)face->units_per_EM;
        FT_Outline_Decompose(&face->glyph->outline, &emitter_funcs, &emitter);
        alias_ui_freetype__Emitter_flush(&emitter);
        font->glyph_map[glyph_index].advance_x = (float)face->glyph->metrics.horiAdvance * emitter.scale;
        font->glyph_map[glyph_index].x = (float)face->glyph->metrics.horiBearingX * emitter.scale;
        font->glyph_map[glyph_index].y = (float)face->glyph->metrics.horiBearingY * emitter.scale;
        font->glyph_map[glyph_index].width = (float)face->glyph->metrics.width * emitter.scale;
        font->glyph_map[glyph_index].height = (float)face->glyph->metrics.height * emitter.scale;
      }
    }
  }

  for(uint32_t i = 0; i < num_faces; i++) {
    FT_Done_Face(faces[i]);
  }

  free(faces);
  free(building_character_map);

  font->root.texture_id = ui->freetype_texture_callback(length, (void **)&emitter.data);
  font->root.decode = alias_ui_freetype_font_decode;
  font->root.user_data = font;
  return &font->root;
}

void alias_ui_freetype_free_font(struct alias_ui_font * font) {
}

#endif


alias_ui_Result alias_ui_initialize(alias_MemoryCB *mcb, alias_ui **ui_ptr) {
  struct alias_ui * ui = alias_malloc(mcb, sizeof(struct alias_ui), alignof(struct alias_ui));
  *ui_ptr = ui;
  if(ui == NULL) {
    return alias_ui_ErrorOutOfMemory;
  }
  memset(ui, 0, sizeof(*ui));
  ui->mcb = mcb;
  return alias_ui_add_font(ui, &alias_ui__dev_font, NULL);
}

void alias_ui_free(alias_ui *ui, alias_MemoryCB *mcb) {
}

alias_ui_Result alias_ui_add_font(alias_ui *ui, struct alias_ui_Font *font, uint32_t *out_result) {
  if(!alias_ui__grow((void **)&ui->font, sizeof(*ui->font), ui->font_length + 1, &ui->font_capacity)) {
    return alias_ui_ErrorOutOfMemory;
  }
  uint32_t index = ui->font_length;
  ui->font[index] = *font;
  ui->font_length += 1;
  if(out_result != NULL) {
    *out_result = index;
  }
  return alias_ui_Success;
}

alias_ui_Result alias_ui_begin_frame(alias_ui *ui, alias_MemoryCB *mcb, const alias_ui_Input *input) {
  alias_ui__program__initialize(ui);
  alias_ui__memory__initialize(ui);
  alias_ui__stats__initialize(ui);
  ui->input = *input;
  return alias_ui_Success;
}

void alias_ui_stats(alias_ui *ui, uint32_t *num_vertexes, uint32_t *num_indexes, uint32_t *num_groups) {
  *num_vertexes = ui->stats.num_vertexes;
  *num_indexes = ui->stats.num_indexes;
  *num_groups = ui->stats.num_groups;
}

alias_ui_Result alias_ui_end_frame(alias_ui *ui, alias_MemoryCB *mcb, alias_ui_Output *output) {
  ui->output = output;

  float width = ui->input.screen_size.width;
  float height = ui->input.screen_size.height;
  
  alias_ui__layout__initialize(ui);
  alias_ui__layout(ui, 0, width, 0, height, &width, &height);

  alias_ui__render__initialize(ui);
  alias_ui__render(ui, 0, 0, width, height);

  alias_ui__group__finalize(ui);

  return alias_ui_Success;
}