GLYPH_TEXTURE *gk_create_texture( GLYPH_REND *rend, int rangeStart, int rangeLength )
{
   GLYPH_TEXTURE *texture = 0;
   GLYPH **glyphs = 0;
   GLYPH *returned = 0;
   
   int index;
   
   CARE( rend );
   CARE( rangeStart > 0 && rangeStart + rangeLength <= 255 );
   
   glyphs = (GLYPH **) malloc( sizeof( GLYPH* ) * rangeLength );
   
   for( index = 0; index < rangeLength; index++ ) {
      returned = _gk_rend_render( rend, rangeStart + index );
      
      /* Create a copy of the glyph so that we don't have to care of what happens to the original */
      
      glyphs[index] = returned;//(GLYPH *) malloc( sizeof( GLYPH ));
      //memcpy( glyphs[index], returned, sizeof( GLYPH ));
   }
   
   texture = _gk_glyphs_to_texture( rend, glyphs, rangeLength, rangeStart );
   
   CARE( texture );
   
   _gk_create_display_lists( texture );
   
   return texture;
}
Ejemplo n.º 2
0
/* callers: gk_rend_set_keeper */
static GLYPH_INDEX* _gk_glyph_index_create(GLYPH_KEEP* const keeper,
    GLYPH_REND* const rend)
{
    GLYPH_INDEX* index;
    funcname = "_gk_glyph_index_create()";

    CARE(keeper);
    CARE(rend);

    if (!_gk_keeper_make_space(keeper,sizeof(GLYPH_INDEX))) return 0;

    index = (GLYPH_INDEX*)_gk_malloc(sizeof(GLYPH_INDEX));
    if (!index) return 0;

    index->pages = 0;
    _gk_glyph_index_init(index,rend);

    index->keeper = keeper;
    index->prev = 0;
    index->next = keeper->first_index;
    if (keeper->first_index) keeper->first_index->prev = index;
    if (!keeper->last_index) keeper->last_index = index;
    keeper->first_index = index;

    index->first_renderer = 0;
    index->last_renderer = 0;

    keeper->allocated += sizeof(GLYPH_INDEX);
    return index;
}
Ejemplo n.º 3
0
static void _gk_glyph_index_init(GLYPH_INDEX* const index,
    const GLYPH_REND* const rend)
{
    CARE(index);
    CARE(rend);

    index->face_id = rend->face_id;
    index->load_flags = rend->load_flags;
    index->render_mode = rend->render_mode;
    index->hsize = rend->hsize;
    index->vsize = rend->vsize;
    index->text_angle = rend->text_angle;
    index->italic_angle = rend->italic_angle;
    index->bold_strength = rend->bold_strength;
}
Ejemplo n.º 4
0
static int _gk_glyph_index_ok_for_renderer(const GLYPH_INDEX* const index,
    const GLYPH_REND* const rend)
{
    CARE(index);
    CARE(rend);

    return (index->face_id == rend->face_id &&
            index->load_flags == rend->load_flags &&
            index->render_mode == rend->render_mode &&
            index->hsize == rend->hsize &&
            index->vsize == rend->vsize &&
            index->text_angle == rend->text_angle &&
            index->italic_angle == rend->italic_angle &&
            index->bold_strength == rend->bold_strength);
}
void gk_render_line_gl_utf8( GLYPH_TEXTURE *texture, const char *text, int x, int y )
{
   int textColor;
   
   CARE( texture );
   
   if( texture->textureId == (unsigned)-1 )
      gk_send_texture_to_gpu( texture );
   
   _gk_set_orthographic_projection();
   
   glEnable( GL_TEXTURE_2D );
   glBindTexture( GL_TEXTURE_2D, texture->textureId );
   
   glEnable( GL_BLEND );
   glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
   
   glPushMatrix();
   
   glTranslated( x, y, 0.0 );
   
   textColor = texture->rend->text_alpha_color;
    
   glColor4f( GLYPH_GETR( textColor )/255.0, GLYPH_GETG( textColor )/255.0, GLYPH_GETB( textColor )/255.0, GLYPH_GETA( textColor )/255.0 );
   
   _gk_render_display_list( texture, text );
   
   glPopMatrix();
   
   _gk_reset_projection();
}
Ejemplo n.º 6
0
/* Callers: rend_render. */
static GLYPH* glyph_index_find_glyph(GLYPH_INDEX* const index,const unsigned unicode)
{
    GLYPH *glyph;
    GLYPH_KEEP *keeper;
    GLYPH ***page_b,**page_c;
    int a_index,b_index,c_index;

    CARE(index);
    CARE(unicode<=GK_MAX_UNICODE);

    if (!index->pages) return 0;

    /*a_index = unicode/16384;*/
    a_index = unicode >> 14;

    /*c_index = unicode - a_index*16384;*/
    c_index = unicode - (a_index << 14);

    page_b = index->pages[a_index];
    if (!page_b) return 0;

    /*b_index = c_index/128;*/
    b_index = c_index >> 7;

    page_c = page_b[b_index];
    if (!page_c) return 0;

    /*c_index -= b_index*128;*/
    c_index -= b_index << 7;

    if (!page_c[c_index]) return 0;
    glyph = page_c[c_index];

    keeper = index->keeper;
    if (glyph!=keeper->head)
    {
        if (glyph->prev) glyph->prev->next = glyph->next;
        if (glyph->next) glyph->next->prev = glyph->prev;
        if (keeper->tail==glyph) keeper->tail = glyph->prev;
        if (keeper->head) keeper->head->prev = glyph;
        glyph->next = keeper->head;
        glyph->prev = 0;
        keeper->head = glyph;
    }

    return glyph;
}
void gk_unload_texture_from_gpu( GLYPH_TEXTURE *texture )
{
   CARE( texture );
   
   glDeleteTextures( 1, &texture->textureId );
   
   texture->textureId = 0;
}
Ejemplo n.º 8
0
/* Callers: _gk_glyph_index_create, _gk_glyph_index_add_glyph */
static int _gk_keeper_make_space(GLYPH_KEEP* const keeper,const int bytes)
{
    CARE(keeper);

    /* no need to do anything, the memory is not limited */
    if (!keeper->max_memory) return 1;

    /* trying to release glyphs, until enough memory is free
       older glyphs are released first */
    while ( (keeper->allocated + bytes > keeper->max_memory) && keeper->tail)
        _gk_unload_glyph(keeper->tail);
    if (keeper->allocated + bytes <= keeper->max_memory) return 1;
    return 0;
}
void _gk_render_display_list( const GLYPH_TEXTURE *texture, const char *text )
{
   CARE( texture );
   
   /* Store the user display list settings so that we don't mess them up */
   glPushAttrib( GL_LIST_BIT );
   
   /* Select the base of character rendering */
   glListBase( texture->displayListStart - texture->displayListBase );
   
   /* Send the display lists to gfx card according to our text input */
   glCallLists( strlen( text ), GL_UNSIGNED_BYTE, text );
   
   /* Restore the previous display list settings */
   glPopAttrib();
}
void gk_destroy_texture( GLYPH_TEXTURE *texture )
{
   int i;
   CARE( texture );
   
   if( texture->textureId != 0 )
      gk_unload_texture_from_gpu( texture );
   
   for( i = 0; i < texture->numGlyphs; i++ ) {
      free( texture->glyphs[i] );
   }
   
   free( texture->glyphs );
   free( texture->pixeldata );
   free( texture );
}
Ejemplo n.º 11
0
/* Callers: gk_rend_debug. */
static int _gk_glyph_index_size(const GLYPH_INDEX* const index)
{
    int size,a,b;

    CARE(index);

    size = sizeof(GLYPH_INDEX);
    if (!index->pages) return size;

    size += 69*sizeof(void*);
    if ((long)index->pages[68])
    {
        for (a=0; a<68; a++)
        {
            if (!index->pages[a]) continue;
            size += 129*sizeof(void*);
            if ((long)index->pages[a][128])
            {
                for (b=0; b<128; b++) { if (index->pages[a][b]) size += 129*sizeof(void*); }  
            }
        }
    }
    return size;
}
Ejemplo n.º 12
0
/* Callers: rend_workout. */
static int _gk_glyph_index_add_glyph(GLYPH_INDEX* const index,GLYPH* const glyph)
{
    GLYPH_KEEP *keeper;
    GLYPH ***page_b,**page_c;
    int a_index,b_index,c_index;
    int bytes;
    funcname = "_gk_glyph_index_add_glyph()";

    CARE(index);
    CARE(glyph);

    keeper = index->keeper;

    /* If the keeper has limitation on number of glyphs, */
    /* make sure to not exceed the limit, by removing most long-ago-used glyphs. */
    if (keeper->max_glyphs)
    {
        while ((keeper->num_glyphs >= keeper->max_glyphs) && keeper->tail)
            _gk_unload_glyph(keeper->tail);
        if (keeper->num_glyphs >= keeper->max_glyphs) return 0;
    }

    /* Asking for memory */
    bytes = glyph_size_in_bytes(glyph);
    if (!_gk_keeper_make_space(keeper,bytes+(129+129+69)*sizeof(void*))) return 0;

    /* creating root directory, if not exist */
    if (!index->pages)
    {
        index->pages = (GLYPH****)_gk_malloc(69*sizeof(void*));
        if (!index->pages) return 0;
        memset(index->pages,0,69*sizeof(void*));
        keeper->allocated += 69*sizeof(void*);
    }

    a_index = glyph->unicode/16384;
    c_index = glyph->unicode - a_index*16384;

    if (!index->pages[a_index])
    {
        index->pages[a_index] = (GLYPH***)_gk_malloc(129*sizeof(void*));
        if (!index->pages[a_index]) return 0;
        (*(long*)(index->pages+68))++;
        memset(index->pages[a_index],0,129*sizeof(void*));
        keeper->allocated += 129*sizeof(void*);
    }

    page_b = index->pages[a_index];
    b_index = c_index/128;

    if (!page_b[b_index])
    {
        page_b[b_index] = (GLYPH**)_gk_malloc(129*sizeof(void*));
        if (!page_b[b_index]) return 0;
        (*(long*)(page_b+128))++;
        memset(page_b[b_index],0,129*sizeof(void*));
        keeper->allocated += 129*sizeof(void*);
    }

    page_c = page_b[b_index];
    c_index -= b_index*128;

    /* There should be NO glyph at this place at this moment */
    CARE(page_c[c_index]==0);

    page_c[c_index] = glyph;
    (*(int*)(page_c+128))++;
    glyph->index = index;

    glyph->prev = 0;
    glyph->next = keeper->head;
    if (keeper->head) keeper->head->prev = glyph;
    if (!keeper->tail) keeper->tail = glyph;
    keeper->head = glyph;

    keeper->allocated += bytes;
    keeper->num_glyphs++;
    return 1;
}
Ejemplo n.º 13
0
/* referenced by any GLYPH_REND objects, GLYPH_INDEX object is also deleted. */
static void _gk_unload_glyph(GLYPH* const glyph)
{
    GLYPH_INDEX *index;
    GLYPH_KEEP *keeper;
    GLYPH ***page_b,**page_c;
    int a_index,b_index,c_index;

    if (!glyph) return;

    /* if glyph is not being kept by keeper, just _gk_free() it. */
    if (!glyph->index)
    {
        if (glyph->bmp) _gk_free(glyph->bmp);
        _gk_free(glyph);
        return;
    }

    index = glyph->index;
    keeper = index->keeper;
    CARE(keeper);

    /* if GLYPH_INDEX has no pages, it means it can't keep any glyphs, crash */
    CARE(index->pages);

    a_index = glyph->unicode/16384;
    c_index = glyph->unicode - a_index*16384;

    page_b = index->pages[a_index];
    CARE(page_b);
    b_index = c_index/128;

    page_c = page_b[b_index];
    CARE(page_c);
    c_index -= b_index*128;

    /* check if the index actually keeps the same glyph we are uncaching */
    CARE(page_c[c_index]==glyph);

    /* unlinking the glyph from index */
    page_c[c_index] = 0;
    (*(long*)(page_c+128))--;

    /* uninking the glyph from keeper's list */
    if (glyph == keeper->head) keeper->head = keeper->head->next;
    if (glyph == keeper->tail) keeper->tail = keeper->tail->prev;
    if (glyph->prev) glyph->prev->next = glyph->next;
    if (glyph->next) glyph->next->prev = glyph->prev;

    /* releasing glyph's memory */
    keeper->num_glyphs--;
    keeper->allocated -= glyph_size_in_bytes(glyph);
    if (glyph->bmp) _gk_free(glyph->bmp);
    _gk_free(glyph);

    /* releasing unnecessary index pages, and index itself */
    if (((long)page_c[128])<=0)
    {
        _gk_free(page_c);
        page_b[b_index] = 0;
        keeper->allocated -= 129*sizeof(void*);
        (*(long*)(page_b+128))--;
        if (((long)page_b[128])<=0)
        {
            _gk_free(page_b);
            index->pages[a_index] = 0;
            keeper->allocated -= 129*sizeof(void*);
            (*(long*)(index->pages+68))--;
            if (((long)index->pages[68])<=0)
            {
                _gk_free(index->pages);
                index->pages = 0;
                keeper->allocated -= 69*sizeof(void*);

                /* no any glyphs left, no renderers.. -> kill the index object */
                if (!index->first_renderer) 
                {
                    if (index == keeper->first_index) keeper->first_index = index->next;
                    if (index == keeper->last_index) keeper->last_index = index->prev;
                    if (index->next) index->next->prev = index->prev;
                    if (index->prev) index->prev->next = index->next;
                    _gk_free(index);
                    keeper->allocated -= sizeof(GLYPH_INDEX);
                }
            }
        }
    }
}
void _gk_create_display_lists( GLYPH_TEXTURE *texture )
{
   int index;
   int textureX = 0;
   int textureY = 0;
   double textureCoX;
   double textureCoY;
   double textureW, textureH;
   int line = 0;
   int lineEnd = texture->glyphsPerSplit;
   GLYPH *currentGlyph;
   
   CARE( texture );
   
   texture->displayListStart = glGenLists( texture->numGlyphs );
   
   for( index = 0; index < texture->numGlyphs; index++ ) {
      if( index >= lineEnd ) {
         lineEnd += texture->glyphsPerSplit;
         line++;
         textureX = 0;
         textureY += texture->splitHeight;
      }
      
      currentGlyph = texture->glyphs[index];
      
      textureCoX = (double) textureX/texture->w;
      textureW = (double) currentGlyph->width/texture->w;
      
      textureCoY = (double) textureY/texture->h;
      textureH = (double) currentGlyph->height/texture->h;
      
      
      glNewList( texture->displayListStart + index, GL_COMPILE );
         /* Adjust the quad position according to the anchor */
         
         glTranslated( currentGlyph->left, -currentGlyph->top, 0 );
         
         glBegin( GL_QUADS );
            /* Bottom-left */
            glTexCoord2f( textureCoX, textureCoY + textureH );
            
            glVertex2i( 0, currentGlyph->height );
            
            /* Bottom-right */
            glTexCoord2f( textureCoX + textureW, textureCoY + textureH );
            
            glVertex2i( currentGlyph->width, currentGlyph->height );
            
            /* Top-right */
            glTexCoord2f( textureCoX + textureW, textureCoY );
            
            glVertex2i( currentGlyph->width, 0 );
            
            /* Top-left */
            glTexCoord2f( textureCoX, textureCoY );
            
            glVertex2i( 0, 0 );
            
         glEnd();
         
         /* Revert the anchor displacement and advance the orign such that */
         /* the next glyph drawn at the correct place */
         glTranslated( -currentGlyph->left + (double) (currentGlyph->advance_x)/(double) (1<<6), currentGlyph->top - (double) (currentGlyph->advance_y)/(double) (1<<6), 0 );
         
      glEndList();
      
      textureX += currentGlyph->width;
   }
};
GLYPH_TEXTURE *_gk_glyphs_to_texture( GLYPH_REND *rend, GLYPH **glyphs, int numGlyphs, GLuint displayListBase )
{
   
   GLYPH_TEXTURE *texture = 0;
   int totalWidth = 0;
   int maxHeight = 0;
   
   int glyphx;
   //int x;
   int y;
   unsigned char *srcptr;
   GLYPH_GL_PIXELTYPE *dstptr;
   int index;
   
   int splitCount;
   int chosenSplitcount;
   int minDiff;
   int currentDiff;
   int line;
   int maxiumWidth;
   int currentWidth;
   int currentLineEnd;
   int textureW;
   int textureH;
   int lineBaseIndex;
   
   CARE( first );
   CARE( last );


   texture = (GLYPH_TEXTURE *) malloc( sizeof( GLYPH_TEXTURE ));
   
   texture->displayListBase = displayListBase;
   texture->textureId = -1;
   texture->numGlyphs = numGlyphs;
   texture->glyphs = glyphs;
   texture->rend = rend;
   
   /* Find the width and height of the texture */
   
   for( index = 0; index < numGlyphs; index++ ) {
      totalWidth += glyphs[index]->width;
      
      if( glyphs[index]->height > maxHeight )
         maxHeight = glyphs[index]->height;
   }
   
   
   /* Find the smallest texture size */
   
   texture->w = 1;
   texture->h = 1;
   
   while( texture->w < totalWidth ) texture->w <<= 1;
   while( texture->h < maxHeight ) texture->h <<= 1;
   
   
   splitCount = 0;
   chosenSplitcount = splitCount;
   minDiff = iabs( texture->w - texture->h );
   
   
   do {
      ++splitCount;
      
      if( numGlyphs/splitCount < 10 ) {
         break;
      }
      
      maxiumWidth = 0;
      index = 0;
      
      for( line = 0; line < splitCount; line++ ) {
         currentWidth = 0;
         currentLineEnd = index + _glyphs_per_line( numGlyphs, splitCount );
         for(; index < currentLineEnd && index < numGlyphs; index++ ) {
            currentWidth += glyphs[index]->width;
         }
         
         if( currentWidth > maxiumWidth ) {
            maxiumWidth = currentWidth;
         }
      }
      
      
      if( maxiumWidth < maxHeight * splitCount/2 ) {
         break;
      }
      
      textureW = 1;
      textureH = 1;
      
      while( textureW < maxiumWidth ) textureW <<= 1;
      while( textureH < maxHeight * splitCount ) textureH <<= 1;
      
      currentDiff = iabs( textureW - textureH );
      
      
      if( currentDiff < minDiff ) {
         minDiff = currentDiff;
         chosenSplitcount = splitCount;
         texture->w = textureW;
         texture->h = textureH;
      }
      
   }
   while( 1 );
   
   
   if( chosenSplitcount > 0 ) {
      texture->glyphsPerSplit = _glyphs_per_line( numGlyphs, chosenSplitcount );
   }
   else {
      texture->glyphsPerSplit = numGlyphs;
   }
   
   texture->splits = chosenSplitcount;
   texture->splitHeight = maxHeight;
   
   
   texture->neededMemory = texture->w * texture->h * sizeof( GLYPH_GL_PIXELTYPE )*100;
   
   /* Copy the pixel data */
   
   texture->pixeldata = (GLYPH_GL_PIXELTYPE *) malloc( texture->neededMemory );
   
   memset( texture->pixeldata, 0, texture->neededMemory );
   
   CARE( texture->pixeldata );
   
   index = 0;
   
   /* Copy glyph bitmap data to the texture buffer */
   for( line = 0; line < texture->splits; line++ ) {
      glyphx = 0;
      currentLineEnd = index + _glyphs_per_line( numGlyphs, texture->splits );
      lineBaseIndex = line * texture->splitHeight * texture->w;
      
      for(; index < currentLineEnd && index < numGlyphs; index++ ) {
         srcptr = glyphs[index]->bmp+1;
         for( y = 0; y < glyphs[index]->height; y++ ) {
            /* Copy one line of the glyph to the texture buffer */
            dstptr = lineBaseIndex + texture->pixeldata + y * texture->w + glyphx;
            memcpy( dstptr, srcptr, glyphs[index]->width );
            srcptr += glyphs[index]->width;
         }
         
         glyphx += glyphs[index]->width;
      }
   }
   
   return texture;
}
void gk_send_texture_to_gpu( GLYPH_TEXTURE *texture )
{
   CARE( texture );
   
   texture->textureId = _gk_load_texture( texture->pixeldata, texture->w, texture->h );
}
Ejemplo n.º 17
0
/* callers: gk_done_keeper */
static void _gk_glyph_index_done(GLYPH_INDEX* const index)
{
    GLYPH_KEEP* keeper;
    GLYPH_REND* renderer;
    int a,b,c;

    CARE(index);

    keeper = index->keeper;
    for (renderer = index->first_renderer; renderer; renderer = renderer->next_for_same_index)
        gk_rend_set_keeper(renderer,0);

    if (index->pages)
    {
        for (a=0; a<68; a++)
        {
            if (index->pages[a])
            {
                for (b=0; b<128; b++)
                {
                    if (index->pages[a][b])
                    {
                        for (c=0; c<128; c++)
                        {
                            if (index->pages[a][b][c])
                            {
                                GLYPH *glyph = index->pages[a][b][c];
                                index->pages[a][b][c] = 0;

                                if (glyph == keeper->head) keeper->head = keeper->head->next;
                                if (glyph == keeper->tail) keeper->tail = keeper->tail->prev;
                                if (glyph->prev) glyph->prev->next = glyph->next;
                                if (glyph->next) glyph->next->prev = glyph->prev;
                                keeper->num_glyphs--;
                                keeper->allocated -= glyph_size_in_bytes(glyph);

                                if (glyph->bmp) _gk_free(glyph->bmp);
                                _gk_free(glyph);
                            }
                        }
                        _gk_free(index->pages[a][b]);
                        index->pages[a][b] = 0;
                        keeper->allocated -= 129*sizeof(void*);
                    }
                }
                _gk_free(index->pages[a]);
                index->pages[a] = 0;
                keeper->allocated -= 129*sizeof(void*);
            }
        }
        _gk_free(index->pages);
        index->pages = 0;
        keeper->allocated -= 69*sizeof(void*);
    }

    if (index == keeper->first_index) keeper->first_index = index->next;
    if (index == keeper->last_index) keeper->last_index = index->prev;
    if (index->next) index->next->prev = index->prev;
    if (index->prev) index->prev->next = index->next;

    _gk_free(index);
    keeper->allocated -= sizeof(GLYPH_INDEX);
}
Ejemplo n.º 18
0
/*
 * Renders a glyph immediately, then tries to puts it into cache.
 * rend and rend->face must be not 0
 */
static GLYPH* _gk_rend_workout(GLYPH_REND* const rend,const unsigned unicode)
{
    unsigned glyph_index;
    int bmp_size;
    int error;
    int center_x = 0,center_y = 0;
    FT_Glyph ft_glyph = 0;
    GLYPH* glyph;
    GLYPH_FACE* actual_face;
    unsigned actual_code;

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"_gk_rend_workout(%p,%d) begin\n",(void*)rend,unicode);
#endif

    CARE(rend && rend->face);
    CARE(unicode > 0);
    CARE(unicode <= GK_MAX_UNICODE);

    funcname = "_gk_rend_workout()";

    _gk_find_mapping(rend->face,unicode,&actual_face,&actual_code);
    if (!actual_face || !actual_code) return 0;
    if (!actual_face->face) return 0;

    glyph_index = FT_Get_Char_Index(actual_face->face,actual_code);
    if (!glyph_index)
    {
        if (unicode==rend->undefined_char || unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->undefined_char);
    }

#ifdef GLYPH_LOG
    if (glyph_log) fprintf(glyph_log,"    glyph_index is %u\n",glyph_index);
#endif

    /* Preparing for glyph loading: setting size */
    /*FT_Activate_Size(size);*/
    if (actual_face == rend->face)
    {
        error = (rend->size == 0);
        if (!error) actual_face->face->size = rend->size;
    }
    else
    {
        error = (actual_face->own_size == 0);
        if (!error)
        {
            actual_face->face->size = actual_face->own_size;
            error = FT_Set_Char_Size(actual_face->face,rend->hsize,rend->vsize,72,72);
        }
    }

#ifdef GLYPH_LOG
    if (error)
    {
        if (glyph_log) fprintf(glyph_log,"    Failed to select size\n");
    }
    else
    {
        if (glyph_log) fprintf(glyph_log,"    Size selected successfully\n");
    }
#endif

    /* Loading a glyph with FreeType */
    if (!error)
    {
        error = FT_Load_Glyph(actual_face->face,glyph_index,rend->load_flags);
        if (error)
            _gk_msg("Error: %s: FT_Load_Glyph() bugs on glyph (#%d) for character U+%04X\n",funcname,glyph_index,unicode);
        else
        {
            error = (actual_face->face->glyph == 0);
            if (error) _gk_msg("Error: %s: Empty glyph slot after FT_Load_Glyph()\n",funcname);
        }

/*#ifdef GLYPH_LOG
        if (error)
        {
            if (glyph_log) fprintf(glyph_log,"    Could not load a glyph with FT_Load_Glyph()\n");
        }
        else
        {
            if (glyph_log) fprintf(glyph_log,"    Loaded a glyph with FT_Load_Glyph()\n");
        }
#endif*/
    }


    /* Getting center coordinates (MEGA-HACK) */
    /* This whole idea should be re-made in more optimal way */
    if (!error)
    {
/*#ifdef GLYPH_LOG
        if (glyph_log) fprintf(glyph_log,"    Getting a center point\n");
#endif*/
        FT_Glyph g = 0;
        error = FT_Get_Glyph(actual_face->face->glyph, &g);
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    FT_Get_Glyph() failed\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() succeeded\n");
            if (g)
                fprintf(glyph_log,"    FT_Get_Glyph() returned not 0\n");
            else
                fprintf(glyph_log,"    FT_Get_Glyph() returned 0\n");
        }
#endif*/

        error = error || !g;
        if (!error && g->format==FT_GLYPH_FORMAT_OUTLINE)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Glyph_To_Bitmap()\n");
#endif*/
            error = FT_Glyph_To_Bitmap(&g,rend->render_mode,0,1);
/*#ifdef GLYPH_LOG
            if (glyph_log)
            {
                if (error)
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() failed\n");
                else
                    fprintf(glyph_log,"    FT_Glyph_To_Bitmap() succeeded\n");
            }
#endif*/
            if (!error)
            {
                center_x = 64 * ((FT_BitmapGlyph)g)->left + 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = 64 * ((FT_BitmapGlyph)g)->top - 64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;
                /*center_x = 64 * ((FT_BitmapGlyph)g)->bitmap.width / 2;
                center_y = -64 * ((FT_BitmapGlyph)g)->bitmap.rows / 2;*/
            }
        }
        if (g)
        {
/*#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"    Calling FT_Done_Glyph()\n");
#endif*/
            FT_Done_Glyph(g);
        }
/*#ifdef GLYPH_LOG
        if (glyph_log)
        {
            if (error)
                fprintf(glyph_log,"    Could not find a center point\n");
            else
                fprintf(glyph_log,"    Computed a center point\n");
        }
#endif*/
    }




    /* Emboldening the glyph */
    if (!error)
    {
        if (rend->bold_strength && actual_face->face->glyph->format==FT_GLYPH_FORMAT_OUTLINE)
        {
            int xstr, ystr, xstr2, ystr2;
            int xmin,xmax,ymin,ymax;
            int center_dx, center_dy;
            FT_GlyphSlot slot = actual_face->face->glyph;

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"        Emboldening the glyph by %d\n",rend->bold_strength);
#endif

            xstr = rend->bold_strength * 
                   FT_MulFix( actual_face->face->units_per_EM, actual_face->face->size->metrics.y_scale ) / 2400;
            ystr = xstr;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif
            GK_Outline_Embolden(&slot->outline,xstr,&xmin,&xmax,&ymin,&ymax);
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xmin = %d, xmax = %d\n",xmin,xmax);
            if (glyph_log) fprintf(glyph_log,"            ymin = %d, ymax = %d\n",ymin,ymax);
#endif
            /*xstr = xstr * 2;
            ystr = xstr;*/
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr = %d, ystr = %d\n",xstr,ystr);
#endif

            xstr2 = xmin+xmax;
            ystr2 = ymin+ymax;
#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            xstr2 = %d, ystr2 = %d\n",xstr2,ystr2);
            if (glyph_log) fprintf(glyph_log,"            xscale = %.5f\n",((double)actual_face->face->size->metrics.x_scale)/65536);
            if (glyph_log) fprintf(glyph_log,"            yscale = %.5f\n",((double)actual_face->face->size->metrics.y_scale)/65536);
#endif

            if (slot->advance.x) slot->advance.x += xstr;
            if (slot->advance.y) slot->advance.y += ystr;

            slot->metrics.width        += xstr * 2;
            slot->metrics.height       += ystr * 2;
            /*slot->metrics.horiBearingX -= xmin;*/
            slot->metrics.horiBearingY += ystr * 2;
            slot->metrics.horiAdvance  += xstr * 2;
            slot->metrics.vertBearingX -= xstr;
            slot->metrics.vertBearingY += ystr * 2;
            slot->metrics.vertAdvance  += ystr * 2;

            /*center_dx = (int)( (double)xstr / 2 * (double)actual_face->face->size->metrics.x_scale / (80000) );
            center_dy = (int)( (double)ystr / 2 * (double)actual_face->face->size->metrics.y_scale / (65536) );*/

            center_dx = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.x_ppem / 80);
            center_dy = (int)( (double)rend->bold_strength * (double)actual_face->face->size->metrics.y_ppem / 80);

#ifdef GLYPH_LOG
            if (glyph_log) fprintf(glyph_log,"            center_x += %.1f\n",((double)center_dx)/64);
            if (glyph_log) fprintf(glyph_log,"            center_y += %.1f\n",((double)center_dx)/64);
#endif

            center_x += center_dx;
            center_y += center_dy;

            /*center_x += xstr;*/
            /*center_y += ymin;*/

            /*FT_GlyphSlot_Embolden(slot);*/
        }
    }

    /* Getting a glyph from FreeType */
    if (!error)
    {
        error = FT_Get_Glyph(actual_face->face->glyph, &ft_glyph);
        error = error || !ft_glyph;
        if (error)
            _gk_msg("Error: %s: Can't get a glyph with FT_Get_Glyph() call. Glyph (#%d) for character U+%04X\n",
            funcname,glyph_index,unicode);
    }

    /* Transforming the glyph to apply rotation and italics */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE && rend->do_matrix_transform)
    {
        error = FT_Glyph_Transform(ft_glyph,&rend->matrix,0);
        if (!error)
        {
            FT_Vector c;
            c.x = center_x;
            c.y = center_y;
            FT_Vector_Transform(&c,&rend->matrix);
            center_x = c.x;
            center_y = c.y;
        }
    }

    /* Converting glyph to bitmap */
    if (!error && ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
    {
        error = FT_Glyph_To_Bitmap(&ft_glyph,rend->render_mode,0,1);
        if (error) _gk_msg("Error: %s: FT_Glyph_To_Bitmap() bugs on character U+%04X\n",funcname,unicode);
    }

    /* Checking if we have bitmap now */
    if (!error)
    {
        error = (ft_glyph->format!=FT_GLYPH_FORMAT_BITMAP);
        if (error) _gk_msg("Error: %s: Glyph is not FT_GLYPH_FORMAT_BITMAP after rendering with FT_Glyph_To_Bitmap()\n",funcname);
    }

#ifdef GLYPH_LOG
/*    {
        if (glyph_log)
        {
            fprintf(glyph_log,"    We got a bitmap glyph from FreeType!\n");
            if (ft_glyph->format==FT_GLYPH_FORMAT_BITMAP)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_BITMAP\n");
                fprintf(glyph_log,"        Size: %dx%d, pitch: %d\n",
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.width,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.rows,
                                  ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);
                if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_MONO)
                {
                    int x,y;
                    int pitch = ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_MONO\n");
                    fprintf(glyph_log,"        Buffer:\n");
                    for (y=0; y < ((FT_BitmapGlyph)ft_glyph)->bitmap.rows; y++)
                    {
                        fprintf(glyph_log,"            ");
                        for (x=0; x < ((FT_BitmapGlyph)ft_glyph)->bitmap.width; x++)
                        {
                            unsigned char byte = ((unsigned char*)((FT_BitmapGlyph)ft_glyph)->bitmap.buffer)[y*pitch+x];
                            unsigned char mask = 128 >> (x%8);
                            fprintf(glyph_log,"%s",(byte&mask)?" *":" .");
                        }
                        fprintf(glyph_log,"\n");
                    }
                }
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY2)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY2\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_GRAY4)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_GRAY4\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD\n");
                else if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode==FT_PIXEL_MODE_LCD_V)
                    fprintf(glyph_log,"        Pixel mode: FT_PIXEL_MODE_LCD_V\n");
            }
            else if (ft_glyph->format==FT_GLYPH_FORMAT_OUTLINE)
            {
                fprintf(glyph_log,"        Format: FT_GLYPH_FORMAT_OUTLINE\n");
            }
            fprintf(glyph_log,"        Advance: ( %.1f , %.1f ) pixels\n",
                    ((double)ft_glyph->advance.x)/0x10000,((double)ft_glyph->advance.y)/0x10000);
        }
    }*/
#endif

    if (!error)
    {
        error = ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch < 0 );
        if (error) _gk_msg("Error: rend_workout(): Rendered glyph has negative pitch value, can't handle\n"); /* FIXME */
    }

    if (!error)
    {
        glyph = (GLYPH*)_gk_malloc(sizeof(GLYPH));
        error = (glyph == 0);
    }

    if (error || !ft_glyph)
    {
        if (ft_glyph) FT_Done_Glyph(ft_glyph);

        if (unicode==rend->error_char) return 0;
        else return _gk_rend_render(rend,rend->error_char);
    }

    glyph->unicode = unicode;
    glyph->width = ((FT_BitmapGlyph)ft_glyph)->bitmap.width;
    glyph->height = ((FT_BitmapGlyph)ft_glyph)->bitmap.rows;
    glyph->left = ((FT_BitmapGlyph)ft_glyph)->left;
    glyph->top = ((FT_BitmapGlyph)ft_glyph)->top;
    glyph->advance_x = ft_glyph->advance.x >> 10;
    glyph->advance_y = ft_glyph->advance.y >> 10;
    glyph->center_x = (center_x + 31) / 64;
    glyph->center_y = (center_y + 31) / 64;

    glyph->index = 0;
    glyph->prev = 0;
    glyph->next = 0;
    glyph->bmp = 0;
    glyph->bmpsize = 0;

    _gk_msg("rendering character '%c'\n",unicode);

    bmp_size = glyph->width*glyph->height;
    if (!bmp_size) /* empty glyph, like space (' ') character */
    {
        if (rend->index) _gk_glyph_index_add_glyph(rend->index,glyph);
        FT_Done_Glyph(ft_glyph);
        return glyph;
    }

    if (((FT_BitmapGlyph)ft_glyph)->bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
    {
#ifdef GLYPH_TARGET_KNOWS_MONO_BITPACK
        int pitch1 = (glyph->width+7)>>3;
        int bitpack_size = glyph->height*pitch1;

#ifdef GLYPH_TARGET_KNOWS_MONO_RLE7
        int rle_size = 0;

        if (rend->index)
              rle_size = _gk_make_RLE7( ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer,
                         glyph->width, glyph->height, ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch);

        if (rle_size>0 && rle_size<=bitpack_size)
        {
            glyph->bmp = (unsigned char*)_gk_malloc(rle_size);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            memcpy(glyph->bmp,rle_buffer,rle_size);
            glyph->bmpsize = rle_size;
        }
        else
#endif  /* GLYPH_TARGET_KNOWS_MONO_RLE7 */
        {
            glyph->bmp = (unsigned char*)_gk_malloc(bitpack_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_MONO_BITPACK;
            if ( ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch == pitch1 )
                memcpy( glyph->bmp+1, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer, bitpack_size );
            else
            {
                unsigned char *d = glyph->bmp+1;
                int y = 0;
                for (; y<glyph->height; y++,d+=pitch1)
                    memcpy( d, ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch, pitch1 );
            }
            glyph->bmpsize = bitpack_size+1;
        }
#else  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
        {
            int y = 0;
            unsigned char* b;

            glyph->bmp = (unsigned char*)_gk_malloc(bmp_size+1);
            if (!glyph->bmp) { _gk_free(glyph); return 0; }
            glyph->bmp[0] = GLYPH_UNCOMPRESSED;
            glyph->bmpsize = bmp_size+1;
            b = glyph->bmp + 1;

            for (; y<glyph->height; y++)
            {
                int x = 0;
                unsigned char* a = ((FT_BitmapGlyph)ft_glyph)->bitmap.buffer + y * ((FT_BitmapGlyph)ft_glyph)->bitmap.pitch;
                while (x<glyph->width)
                {
                    if (x < glyph->width) { *b++ = *a&0x80 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x40 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x20 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x10 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x08 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x04 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x02 ? 255 : 0; x++; }
                    if (x < glyph->width) { *b++ = *a&0x01 ? 255 : 0; x++; }
                    a++;
                }
            }
        }
#endif  /* GLYPH_TARGET_KNOWS_MONO_BITPACK */
    }