/*
 * Helper functions for core engine module while rendering.
 */

// TOP

Font*
get_font(Asset_Bank *bank, i32 font_id){
    Font *font = 0;
    if (bank && font_id >= 1 && font_id <= bank->font_max_id){
        font = bank->fonts + font_id - 1;
    }
    return(font);
}

f32*
get_font_advance(Asset_Bank *bank, i32 font_id){
    f32 *advance = 0;
    Font *font = get_font(bank, font_id);
    if (font){
        advance = font->advance;
    }
    return(advance);
}

Image*
get_image(Asset_Bank *bank, i32 image_id){
    Image *result = 0;
    if (bank && image_id >= 1 && image_id <= bank->image_max_id){
        result = bank->images + image_id - 1;
    }
    return(result);
}

enum Tranform_Spec{
    TF_Pixels,
    TF_Units,
};

Transform unit_to_pixel_transform = {
    {v2(pixel_over_unit, 0.f), v2(0.f, pixel_over_unit)}, v2(x_origin_u, y_origin_u)
};

void
target_transform(Render_Target *target, Tranform_Spec t){
    switch (t){
        case TF_Pixels:
        target->transform = invert_transform(target->me_to_pixel_transform);
        break;
        
        case TF_Units:
        target->transform =
            transform_transform(unit_to_pixel_transform, invert_transform(target->me_to_pixel_transform));
        break;
        
        default:
        InvalidCodePath;
    }
}

void
clear_target(Render_Target *target){
    if (target){
        target->push_part.rel_part.pos = 0;
    }
}

void
null_render(Render_Target *target){
    if (target){
        Render_Command_Header *h;
        h = push_type(&target->push_part, Render_Command_Header);
        h->type = render_null;
        h->size = 0;
    }
}

void
do_dbg_rectangle(Render_Target *target, f32_rect rect, vec4 color){
    if (target){
        Render_Command_Header *h;
        Render_Dbg_Rectangle *r;
        
        h = push_type(&target->push_part, Render_Command_Header);
        h->type = render_dbg_rectangle;
        h->size = sizeof(Render_Command_Header) + sizeof(Render_Dbg_Rectangle);
        
        rect.p[0] = do_transform(rect.p[0], target->transform);
        rect.p[1] = do_transform(rect.p[1], target->transform);
        
        r = push_type(&target->push_part, Render_Dbg_Rectangle);
        r->rect = rect;
        r->color = color;
    }
}

void
do_dbg_parallelagram(Render_Target *target, vec2 pos, vec2 x_axis, vec2 y_axis, vec4 color){
    if (target){
        Render_Command_Header *h;
        Render_Dbg_Parallelagram *r;
        
        h = push_type(&target->push_part, Render_Command_Header);
        h->type = render_dbg_parallelagram;
        h->size = sizeof(Render_Command_Header) + sizeof(Render_Dbg_Parallelagram);
        
        r = push_type(&target->push_part, Render_Dbg_Parallelagram);
        r->transform.pos = do_transform(pos, target->transform);
        r->transform.basis.x = x_axis;
        r->transform.basis.y = y_axis;
        r->color = color;
    }
}

void
do_string(Render_Target *target, Asset_Bank *bank,
          i32 font_id, vec2 pos, char *str, int len, vec4 color){
    Render_Command_Header *h;
    Render_Glyph *g;
    i32 i;
    char c;
    f32 *advance;
    
    if (target){
        advance = get_font_advance(bank, font_id);
        if (advance){
            for (i = 0; i < len; ++i){
                h = push_type(&target->push_part, Render_Command_Header);
                h->type = render_glyph;
                h->size = sizeof(Render_Command_Header) + sizeof(Render_Glyph);
                
                c = str[i] & (127);
                g = push_type(&target->push_part, Render_Glyph);
                g->pos = do_transform(pos, target->transform);
                g->font_id = font_id;
                g->c = c;
                g->color = color;
                
                pos.x += advance[c];
            }
        }
    }
}

#define Render_Normal 0x0
#define Render_Exact 0x1

void
do_image_general(Render_Target *target, Asset_Bank *bank,
                 Render_Target *dbg, i32 image_id,
                 u32 flags, vec2 pos, vec2 origin,
                 vec2 x_axis, vec2 y_axis){
    Render_Command_Header *h;
    Render_Image img = {0};
    
    if (target){
        f32 x = 0, y = 0;
        
        Image *image = get_image(bank, image_id);
        
        if (Render_Exact & flags){
            x = 1.f;
            y = 1.f;
        }
        else{
            if (image){
                x = (0.5f*image->width);
                y = (0.5f*image->height);
            }
            else{
                x = 32.f;
                y = 32.f;
            }
        }
        
        img.transform.basis.x = x_axis * x;
        img.transform.basis.y = y_axis * y;
        origin = do_basis(origin, img.transform.basis);
        
        pos.x -= origin.x;
        pos.y -= origin.y;
        
        img.transform.pos = do_transform(pos, target->transform);
        img.image_id = image_id;
        
        if (image){
            h = push_type(&target->push_part, Render_Command_Header);
            h->type = render_image;
            h->size = sizeof(Render_Command_Header) + sizeof(Render_Image);
            
            Render_Image *imgptr = push_type(&target->push_part, Render_Image);
            *imgptr = img;
        }
        
        do_dbg_parallelagram(dbg,
                             img.transform.pos,
                             img.transform.basis.x,
                             img.transform.basis.y,
                             v4(1.f, 0, 0, 0.25f));
    }
}

void
do_image(Render_Target *target, Asset_Bank *bank, Render_Target *dbg, i32 image_id,
         vec2 pos, f32 size = 1.f){
    vec2 x_axis, y_axis;
    
    if (target){
        x_axis = v2(size, 0.0f);
        y_axis = v2(0.0f, size);
        
        do_image_general(target, bank, dbg, image_id,
                         Render_Normal, pos, v2(0,0),
                         x_axis, y_axis);
    }
}

void
do_image(Render_Target *target, Asset_Bank *bank, Render_Target *dbg, i32 image_id,
         vec2 pos, vec2 origin, f32 size = 1.f){
    vec2 x_axis, y_axis;
    
    if (target){
        x_axis = v2(size, 0.0f);
        y_axis = v2(0.0f, size);
        
        do_image_general(target, bank, dbg, image_id,
                         Render_Normal, pos, origin, x_axis, y_axis);
    }
}

void
set_lane(Render_Target *target, Render_Target *dbg,
         i32 lane_index, f32 y){
    Render_Command_Header *h;
    Render_Lane *l;
    
    if (target){
        h = push_type(&target->push_part, Render_Command_Header);
        h->type = render_lane;
        h->size = sizeof(Render_Command_Header) + sizeof(Render_Lane);
        
        l = push_type(&target->push_part, Render_Lane);
        l->lane_index = lane_index;
        l->y_position = y;
        
        do_dbg_parallelagram(dbg,
                             v2(0.f, y),
                             v2(2000.f, 0),
                             v2(0, 5.f),
                             v4(1.f, 0.5f, 0.f, 0.25f));
    }
}

void
do_obstacle(Render_Target *target, Render_Target *dbg,
            u32 type, u32 seed, f32 x, i32 lane){
    Render_Command_Header *h;
    Render_Obstacle *o;
    
    if (target){
        h = push_type(&target->push_part, Render_Command_Header);
        h->type = render_obstacle;
        h->size = sizeof(Render_Command_Header) + sizeof(Render_Obstacle);
        
        o = push_type(&target->push_part, Render_Obstacle);
        o->type = type;
        o->seed = seed;
        o->x = x;
        o->lane = lane;
    }
}

// BOTTOM