packages feed

FreeTypeGL-0.0.1: src/glyph-cache.c

#include "glyph-cache.h"
#include <stdlib.h>
#include <assert.h>
#include <wchar.h>

static texture_glyph_t *texture_glyph_new(
    unsigned glyph_index,
    wchar_t charcode,
    ivec2 size,
    ivec2 bearing,
    vec2 advance,

    vec2 texture_pos0,
    vec2 texture_pos1,

    texture_font_t *font)
{
    texture_glyph_t *self = malloc( sizeof *self );
    *self = (texture_glyph_t){
        .glyph_index = glyph_index,
        .charcode = charcode,
        .size = size,
        .bearing = bearing,
        .advance = advance,
        .texture_pos0 = texture_pos0,
        .texture_pos1 = texture_pos1,
        .font = font,
    };
    return self;
}

static void texture_glyph_delete( texture_glyph_t *self )
{
    assert( self );
    free( self );
}

void glyph_cache_init(
    glyph_cache_t *self, const ivec2 *size, int depth)
{
    texture_atlas_init(&self->atlas, size, depth);
    self->glyphs = vector_new( sizeof(texture_glyph_t *) );
    /* -1 is a special glyph */
    glyph_cache_get_glyph(self, NULL, -1);
}

void glyph_cache_fini(glyph_cache_t *self)
{
    size_t i;
    texture_glyph_t *glyph;
    for(i=0; i<vector_size(self->glyphs); ++i) {
        glyph = *(texture_glyph_t **) vector_get( self->glyphs, i );
        texture_glyph_delete(glyph);
    }
    vector_delete(self->glyphs);
}

static texture_glyph_t *glyph_cache_load_glyph(
    glyph_cache_t *self, texture_font_t *font, const wchar_t charcode)
{
    size_t depth = self->atlas.depth;
    texture_font_loaded_glyph_t loaded;
    int rc = texture_font_load_glyph(font, charcode, depth == 3, &loaded);
    if(0 != rc) goto Error;

    size_t w = loaded.bitmap->width/depth;
    size_t h = loaded.bitmap->rows;

    ivec4 region = texture_atlas_make_region(
        &self->atlas, w, h, loaded.bitmap->buffer, loaded.bitmap->pitch);
    if(region.x < 0) goto Unload_Error;

    ivec2 size = self->atlas.size;
    texture_glyph_t *glyph =
        texture_glyph_new(
            loaded.glyph_index, charcode,
            (ivec2){{ region.width, region.height }},
            loaded.bearing,
            loaded.advance,
            (vec2){{ region.x/(float)size.x, region.y/(float)size.y }},
            (vec2){{ (region.x + region.width)/(float)size.x,
                     (region.y + region.height)/(float)size.y }},
            font);

    vector_push_back( self->glyphs, &glyph );
    texture_font_done_glyph(font, &loaded);

    return *(texture_glyph_t **)vector_back( self->glyphs );
Unload_Error:
    texture_font_done_glyph(font, &loaded);
Error:
    return NULL;
}

texture_glyph_t *glyph_cache_get_glyph(glyph_cache_t * self, texture_font_t *font, wchar_t charcode)
{
    size_t i;
    /* Check if charcode has been already loaded */
    for(i=0; i<self->glyphs->size; ++i) {
        texture_glyph_t *glyph =
            *(texture_glyph_t **) vector_get( self->glyphs, i );
        // If charcode is -1, we don't care about outline type or thickness
        if( (glyph->charcode == charcode) &&
            ((charcode == (wchar_t)(-1) ) || (glyph->font == font) ))
        {
            return glyph;
        }
    }

    /* charcode -1 is special : it is used for line drawing (overline,
     * underline, strikethrough) and background.
     */
    if( charcode == (wchar_t)(-1) )
    {
        static unsigned char data[4*4*3] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
                                            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
                                            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
                                            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
        ivec4 region = texture_atlas_make_region(&self->atlas, 4, 4, data, 0);
        if (region.x < 0) return NULL;

        texture_glyph_t *glyph = malloc( sizeof *glyph );
        memset(glyph, 0, sizeof *glyph);
        glyph->glyph_index = -1;
        glyph->charcode = -1;
        ivec2 size  = self->atlas.size;
        glyph->texture_pos0 = (vec2){{ (region.x+2)/(float)size.x, (region.y+2)/(float)size.y }};
        glyph->texture_pos1 = (vec2){{ (region.x+3)/(float)size.x, (region.y+3)/(float)size.y }};
        vector_push_back( self->glyphs, &glyph );
        return glyph; //*(texture_glyph_t **) vector_back( self->glyphs );
    }

    /* Glyph has not been already loaded */
    texture_glyph_t *glyph = glyph_cache_load_glyph( self, font, charcode );
    if(!glyph) return NULL;
    return glyph;
}

float glyph_cache_get_kerning(
    glyph_cache_t *self, texture_glyph_t *glyph, wchar_t prev_char)
{
    return texture_font_get_kerning(glyph->font, glyph->glyph_index, prev_char);
}