/******************************************************************************* * ReadCharMetrics * * Reads metrics for each glyph in a TrueType font. Returns false for memory * allocation or FreeType error; sets *p_metrics to NULL for non-fatal error. * */ static BOOL ReadCharMetrics(FT_Face face, AFM *afm, AFMMETRICS **p_metrics) { FT_ULong charcode, index; AFMMETRICS *metrics; USHORT em_size = afm->WinMetrics.usUnitsPerEm; for (charcode = 0, index = 0; charcode < 65536; ++charcode) if (pFT_Get_Char_Index(face, charcode) != 0) ++index; /* count # of glyphs */ afm->NumofMetrics = index; *p_metrics = metrics = HeapAlloc(PSDRV_Heap, 0, index * sizeof(*metrics)); if (metrics == NULL) return FALSE; for (charcode = 0, index = 0; charcode < 65536; ++charcode) { FT_UInt glyph_index = pFT_Get_Char_Index(face, charcode); FT_Error error; CHAR buffer[128]; /* for glyph names */ if (glyph_index == 0) continue; error = pFT_Load_Glyph(face, glyph_index, GLYPH_LOAD_FLAGS); if (error != FT_Err_Ok) { ERR("%s returned %i\n", "FT_Load_Glyph", error); goto cleanup; } error = pFT_Get_Glyph_Name(face, glyph_index, buffer, sizeof(buffer)); if (error != FT_Err_Ok) { ERR("%s returned %i\n", "FT_Get_Glyph_Name", error); goto cleanup; } metrics[index].N = PSDRV_GlyphName(buffer); if (metrics[index].N == NULL) goto cleanup; metrics[index].C = metrics[index].UV = charcode; metrics[index].WX = PSUnits(face->glyph->metrics.horiAdvance, em_size); ++index; } if (afm->WinMetrics.sAvgCharWidth == 0) afm->WinMetrics.sAvgCharWidth = PSDRV_CalcAvgCharWidth(afm); return TRUE; cleanup: HeapFree(PSDRV_Heap, 0, metrics); return FALSE; }
bool CText::MakeFTChar(FT_Face face, char ch, int list_base, int textures[NUM_CHARS], float charsizes[NUM_CHARS][2], bool mipmaps) { const int ich = ch; if(pFT_Load_Glyph(face,pFT_Get_Char_Index(face,ich),FT_LOAD_DEFAULT)) return false; FT_Glyph glyph; if(pFT_Get_Glyph(face->glyph,&glyph)) return false; bool empty=(pFT_Glyph_To_Bitmap(&glyph,FT_RENDER_MODE_NORMAL,0,1)!=0); FT_BitmapGlyph bitmap_glyph=(FT_BitmapGlyph)glyph; FT_Bitmap& bitmap=bitmap_glyph->bitmap; int width=1, height=1; if (!empty) { width=next_p2(bitmap.width); height=next_p2(bitmap.rows); unsigned char *expanded_data=(unsigned char *)malloc(2*width*height); if (!expanded_data) { pFT_Done_Glyph(glyph); return false; } for(int j=0; j<height; j++) { for(int i=0; i<width; i++) { expanded_data[2*(i+j*width)]=255; expanded_data[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j]; } } glBindTexture(GL_TEXTURE_2D, textures[ich]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST); if (mipmaps) { glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST); if (gluBuild2DMipmaps(GL_TEXTURE_2D,2,width,height,GL_LUMINANCE_ALPHA,GL_UNSIGNED_BYTE,expanded_data)!=0) { free(expanded_data); pFT_Done_Glyph(glyph); return false; } } else { glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data); } free(expanded_data); } glNewList(list_base+ich,GL_COMPILE); { if (!empty) { glBindTexture(GL_TEXTURE_2D,textures[ich]); glPushMatrix(); glTranslatef((float)bitmap_glyph->left, (float)(bitmap_glyph->top-bitmap.rows),0); float x= (float)bitmap.width / (float)width, y= (float)bitmap.rows / (float)height; glBegin(GL_QUADS); { glNormal3f(0,0,1); glTexCoord2f(0,0); glVertex2f(0,(float)bitmap.rows); glTexCoord2f(x,0); glVertex2f((float)bitmap.width, (float)bitmap.rows); glTexCoord2f(x,y); glVertex2f((float)bitmap.width, 0); glTexCoord2f(0,y); glVertex2f(0,0); } glEnd(); glPopMatrix(); } glTranslatef((float)(face->glyph->advance.x>>6), 0, 0); } glEndList(); charsizes[ich][0]=((float)face->glyph->advance.x/64.0f); charsizes[ich][1]=((float)face->size->metrics.height/64.0f); pFT_Done_Glyph(glyph); return true; }