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; }
/* 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; }
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; }
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(); }
/* 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; }
/* 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 ); }
/* 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; }
/* 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; }
/* 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 ); }
/* 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); }
/* * 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 */ }