Example #1
0
void Label::makeFont(string f)
{	
	if(fonts.find(f) != fonts.end())
	{
		font = fonts[f];
		return;
	}
	
	string floc = Location + f + ".ttf";
	font = fonts[f] = new Font();
	
	font->point = 200;
	
	// Create And Initilize A FreeType Font Library.
	FT_Init_FreeType( &ft );
	
	// This Is Where We Load In The Font Information From The File.
	// Of All The Places Where The Code Might Die, This Is The Most Likely,
	// As FT_New_Face Will Fail If The Font File Does Not Exist Or Is Somehow Broken.
	if (FT_New_Face( ft, floc.c_str(), 0, &font->face )) 
		return;
	
	// For Some Twisted Reason, FreeType Measures Font Size
	// In Terms Of 1/64ths Of Pixels.  Thus, To Make A Font
	// h Pixels High, We Need To Request A Size Of h*64.
	// (h << 6 Is Just A Prettier Way Of Writing h*64)
	FT_Set_Char_Size( font->face,  font->point * 64,  font->point * 64, 96, 96);
	
	bool use_kerning = FT_HAS_KERNING(  font->face );
	
	for(unsigned char c=0; c<128; c++)
	{
		// The First Thing We Do Is Get FreeType To Render Our Character
		// Into A Bitmap.  This Actually Requires A Couple Of FreeType Commands:
		
		// Load The Glyph For Our Character.
		if(FT_Load_Glyph( font->face, FT_Get_Char_Index( font->face, c ), FT_LOAD_DEFAULT ))
			return;
		
		// Move The Face's Glyph Into A Glyph Object.
		FT_Glyph glyph;
		if(FT_Get_Glyph( font->face->glyph, &glyph ))
			return;
		
		// Convert The Glyph To A Bitmap.
		FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
		FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
		
		// This Reference Will Make Accessing The Bitmap Easier.
		FT_Bitmap& bitmap=bitmap_glyph->bitmap;
		
		// Use Our Helper Function To Get The Widths Of
		// The Bitmap Data That We Will Need In Order To Create
		// Our Texture.
		int downsample = 8;
		int width = next_p2( bitmap.width + 4 * downsample );
		int height = next_p2( bitmap.rows + 4 * downsample );
		
		float xs = (float)bitmap.width / width;
		float ys = (float)bitmap.rows / height;
		
		width /= downsample;
		height /= downsample;
		
		// Allocate Memory For The Texture Data.
		GLubyte* tex = (GLubyte*)malloc(width * height);
		memset(tex, 0, width*height);
		
		for(int i=0; i < width; i++)
		for(int j=0; j < height; j++)
		{
			tex[i + j*width]= edgeDistance(bitmap.buffer, bitmap.width, bitmap.rows, (i)/xs/width, (j)/ys/height, 1.0);
		}
		
		glGenTextures(1, &font->chars[c]);
		glBindTexture(GL_TEXTURE_2D, font->chars[c]);
		
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, tex);
		
		for(int k=0; k<128; k++)
		{
			if(use_kerning)
			{
				FT_Vector kern;
				FT_Get_Kerning( font->face,         
							   FT_Get_Char_Index( font->face, c ),    
							   FT_Get_Char_Index( font->face, k ),        
							   FT_KERNING_DEFAULT, 
							   &kern );   
				
				font->kerning[c][k] = (font->face->glyph->advance.x + kern.x) / (font->point * 64.0f);
			}
			else
			{
				font->kerning[c][k] = font->face->glyph->advance.x / (font->point * 64.0f);
			}
		}
		
		font->wid[c] = bitmap.width / (float)font->point;
		font->hgt[c] = bitmap.rows / (float)font->point;
		font->top[c] = (bitmap_glyph->top-bitmap.rows) / (float)font->point;
		
		font->xpad[c] = xs;
		font->ypad[c] = ys;
		
		free(tex);
	}
	
	FT_Done_Face(font->face);
	FT_Done_FreeType(ft);
}
Example #2
0
void geCreateFontTtf(ge_Font* font){
	FT_GlyphSlot slot = ((FT_Face)font->face)->glyph;
	u16 n;
	u16 chr = 0;
	int x = 0;
	int y = font->size;
	bool first_null_char = true;

	int total_width = 0;

	for(n=0; n<256; n++){
		chr = n;
		FT_UInt glyph_index = FT_Get_Char_Index((FT_Face)font->face, chr);
		int error = FT_Load_Glyph((FT_Face)font->face, glyph_index, FT_LOAD_DEFAULT);
		if (error) continue;
		error = FT_Render_Glyph(((FT_Face)font->face)->glyph, ft_render_mode_normal);
		if (error) continue;
		if(!glyph_index && !first_null_char){
			continue;
		}
		total_width += slot->bitmap.width;
		first_null_char = false;
	}

	if(font->texture)geFreeImage(font->texture);

#ifdef PSP
	ge_Image* dest = geCreateSurface(512, 512, 0x00000000);
#else
//	ge_Image* dest = geCreateSurface(1024, 1024, 0x00000000);
	ge_Image* dest = geCreateSurface(font->size*16*1.5, font->size*16*1.5, 0x00000000);
#endif

	font->texture = dest;
	first_null_char = true;

	for(n=0; n<256; n++){
		chr = n;
		FT_UInt glyph_index = FT_Get_Char_Index((FT_Face)font->face, chr);
		int error = FT_Load_Glyph((FT_Face)font->face, glyph_index, FT_LOAD_DEFAULT);
		if (error) continue;
		error = FT_Render_Glyph(((FT_Face)font->face)->glyph, ft_render_mode_normal);
		if (error) continue;

		if(x+(slot->advance.x>>6) > dest->width){
			x = 0;
			y += font->size * 1.5;
		}

		font->positions[n].x = x;
		if(font->positions[n].x<0)font->positions[n].x=0;
		font->positions[n].y = y - slot->bitmap_top;
		font->positions[n].w = slot->bitmap.width + slot->bitmap_left;
		font->positions[n].h = slot->bitmap.rows;
		font->positions[n].advX = slot->advance.x >> 6;
		font->positions[n].posY = slot->bitmap_top;
		if(!glyph_index && !first_null_char){
			continue;
		}

//		fontPrintTextImage(&slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, 0xffffffff, dest);
		fontPrintTextImpl2(&slot->bitmap, x + slot->bitmap_left, y - slot->bitmap_top, 0xffffffff, dest->data, dest->width, dest->height, dest->textureWidth);

		/*
		int jump = slot->bitmap.width;
		int jump2 = slot->advance.x >> 6;
		if(jump2 > jump){
			jump = jump2;
		}
		jump = slot->bitmap.width + (slot->advance.x >> 6);
		x += jump;
		*/
	//	x += slot->advance.x >> 6;
		x += font->size;

	//	y += slot->advance.y >> 6;
		first_null_char = false;
	}
//	geSwizzle(dest);
	geUpdateImage(dest);
}
Example #3
0
void FontRenderer::rasterize() {
    clear_bitmaps();
    if (!m_ft_face) {
        return;
    }


    qDebug() << " begin rasterize_font ";



    if (m_config->italic()!=0) {
        FT_Matrix matrix;
        const float angle = (-M_PI*m_config->italic()) / 180.0f;
        matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
        matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
        matrix.yx = (FT_Fixed)( 0/*sin( angle )*/ * 0x10000L );
        matrix.yy = (FT_Fixed)( 1/*cos( angle )*/ * 0x10000L );
        FT_Set_Transform(m_ft_face,&matrix,0);
    } else {
        FT_Set_Transform(m_ft_face,0,0);
    }


    /// fill metrics
    if (FT_IS_SCALABLE(m_ft_face)) {
        m_rendered.metrics.ascender = m_ft_face->size->metrics.ascender / 64;
        m_rendered.metrics.descender = m_ft_face->size->metrics.descender/ 64;
        m_rendered.metrics.height = m_ft_face->size->metrics.height/ 64;
    } else {
        m_rendered.metrics.ascender = m_ft_face->ascender;
        m_rendered.metrics.descender = m_ft_face->descender;
        m_rendered.metrics.height = m_ft_face->height;
    }


    bool use_kerning = FT_HAS_KERNING( m_ft_face );

    const ushort* chars = m_config->characters().utf16();
    size_t amount = 0;
    while (chars[amount]!=0) amount++;
    int error = 0;
    for (size_t i=0;i<amount;i++) {
        int glyph_index = FT_Get_Char_Index( m_ft_face, chars[i] );
        if (glyph_index==0 && !m_config->renderMissing())
            continue;

        FT_Int32 flags = FT_LOAD_DEFAULT;
        if (!m_config->antialiased()) {
            flags = flags | FT_LOAD_MONOCHROME | FT_LOAD_TARGET_MONO;
        } else {
            flags = flags | FT_LOAD_TARGET_NORMAL;
        }
        switch (m_config->hinting()) {
        case  FontConfig::HintingDisable:
            flags = flags | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
            break;
        case  FontConfig::HintingForceFreetypeAuto:
            flags = flags | FT_LOAD_FORCE_AUTOHINT;
            break;
        case  FontConfig::HintingDisableFreetypeAuto:
            flags = flags | FT_LOAD_NO_AUTOHINT;
            break;
        default:
            break;
        }

        error = FT_Load_Glyph( m_ft_face, glyph_index, flags );
        if ( error )
           continue;
        if (m_config->bold()!=0) {
            FT_Pos strength = m_config->size()*m_config->bold();
            if ( m_ft_face->glyph->format == FT_GLYPH_FORMAT_OUTLINE )
                FT_Outline_Embolden( &m_ft_face->glyph->outline, strength );
        }
        if (m_ft_face->glyph->format!=FT_GLYPH_FORMAT_BITMAP) {
            error = FT_Render_Glyph( m_ft_face->glyph,
               m_config->antialiased() ? FT_RENDER_MODE_NORMAL:FT_RENDER_MODE_MONO );
        }
        if ( error )
           continue;
        if (append_bitmap(chars[i])) {
            if (use_kerning)
                append_kerning(chars[i],chars,amount);
        }
    }
    imagesChanged(m_chars);
    imagesChanged();
}
// ------------------------------------------------------------- load_glyph ---
texture_glyph_t *
load_glyph( const char *  filename,     const wchar_t charcode,
            const float   highres_size, const float   lowres_size,
            const float   padding )
{
    size_t i, j;
    FT_Library library;
    FT_Face face;

    FT_Init_FreeType( &library );
    FT_New_Face( library, filename, 0, &face );
    FT_Select_Charmap( face, FT_ENCODING_UNICODE );
    FT_UInt glyph_index = FT_Get_Char_Index( face, charcode );

    // Render glyph at high resolution (highres_size points)
    FT_Set_Char_Size( face, highres_size*64, 0, 72, 72 );
    FT_Load_Glyph( face, glyph_index,
                   FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT);
    FT_GlyphSlot slot = face->glyph;
    FT_Bitmap bitmap = slot->bitmap;

    // Allocate high resolution buffer
    size_t highres_width  = bitmap.width + 2*padding*highres_size;
    size_t highres_height = bitmap.rows + 2*padding*highres_size;
    double * highres_data = (double *) malloc( highres_width*highres_height*sizeof(double) );
    memset( highres_data, 0, highres_width*highres_height*sizeof(double) );

    // Copy high resolution bitmap with padding and normalize values
    for( j=0; j < bitmap.rows; ++j )
    {
        for( i=0; i < bitmap.width; ++i )
        {
            int x = i + padding;
            int y = j + padding;
            highres_data[y*highres_width+x] = bitmap.buffer[j*bitmap.width+i]/255.0;
        }
    }

    // Compute distance map
    distance_map( highres_data, highres_width, highres_height );

    // Allocate low resolution buffer
    size_t lowres_width  = round(highres_width * lowres_size/highres_size);
    size_t lowres_height = round(highres_height * lowres_width/(float) highres_width);
    double * lowres_data = (double *) malloc( lowres_width*lowres_height*sizeof(double) );
    memset( lowres_data, 0, lowres_width*lowres_height*sizeof(double) );

    // Scale down highres buffer into lowres buffer
    resize( highres_data, highres_width, highres_height,
            lowres_data,  lowres_width,  lowres_height );

    // Convert the (double *) lowres buffer into a (unsigned char *) buffer and
    // rescale values between 0 and 255.
    unsigned char * data =
        (unsigned char *) malloc( lowres_width*lowres_height*sizeof(unsigned char) );
    for( j=0; j < lowres_height; ++j )
    {
        for( i=0; i < lowres_width; ++i )
        {
            double v = lowres_data[j*lowres_width+i];
            data[j*lowres_width+i] = (int) (255*(1-v));
        }
    }

    // Compute new glyph information from highres value
    float ratio = lowres_size / highres_size;
    size_t pitch  = lowres_width * sizeof( unsigned char );

    // Create glyph
    texture_glyph_t * glyph = texture_glyph_new( );
    glyph->offset_x = (slot->bitmap_left + padding*highres_width) * ratio;
    glyph->offset_y = (slot->bitmap_top + padding*highres_height) * ratio;
    glyph->width    = lowres_width;
    glyph->height   = lowres_height;
    glyph->charcode = charcode;
    /*
    printf( "Glyph width:  %ld\n", glyph->width );
    printf( "Glyph height: %ld\n", glyph->height );
    printf( "Glyph offset x: %d\n", glyph->offset_x );
    printf( "Glyph offset y: %d\n", glyph->offset_y );
    */
    ivec4 region = texture_atlas_get_region( atlas, glyph->width, glyph->height );
    /*
    printf( "Region x : %d\n", region.x );
    printf( "Region y : %d\n", region.y );
    printf( "Region width : %d\n", region.width );
    printf( "Region height : %d\n", region.height );
    */
    texture_atlas_set_region( atlas, region.x, region.y, glyph->width, glyph->height, data, pitch );
    glyph->s0       = region.x/(float)atlas->width;
    glyph->t0       = region.y/(float)atlas->height;
    glyph->s1       = (region.x + glyph->width)/(float)atlas->width;
    glyph->t1       = (region.y + glyph->height)/(float)atlas->height;

    FT_Load_Glyph( face, glyph_index,
                   FT_LOAD_RENDER | FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT);
    glyph->advance_x = ratio * face->glyph->advance.x/64.0;
    glyph->advance_y = ratio * face->glyph->advance.y/64.0;
    /*
    printf( "Advance x : %f\n", glyph->advance_x );
    printf( "Advance y : %f\n", glyph->advance_y );
    */
    free( highres_data );
    free( lowres_data );
    free( data );

    return glyph;
}
Example #5
0
/**
 * \brief Get a glyph
 * \param ch character code
 **/
FT_Glyph ass_font_get_glyph(void* fontconfig_priv, ass_font_t* font, uint32_t ch, ass_hinting_t hinting)
{
	int error;
	int index = 0;
	int i;
	FT_Glyph glyph;
	FT_Face face = 0;
	int flags = 0;

	if (ch < 0x20)
		return 0;
	if (font->n_faces == 0)
		return 0;

	for (i = 0; i < font->n_faces; ++i) {
		face = font->faces[i];
		index = FT_Get_Char_Index(face, ch);
		if (index)
			break;
	}

#ifdef HAVE_FONTCONFIG
	if (index == 0) {
		int face_idx;
		mp_msg(MSGT_ASS, MSGL_INFO, MSGTR_LIBASS_GlyphNotFoundReselectingFont,
		       ch, font->desc.family, font->desc.bold, font->desc.italic);
		face_idx = add_face(fontconfig_priv, font, ch);
		face = font->faces[face_idx];
		index = FT_Get_Char_Index(face, ch);
		if (index == 0) {
			mp_msg(MSGT_ASS, MSGL_ERR, MSGTR_LIBASS_GlyphNotFound,
			       ch, font->desc.family, font->desc.bold, font->desc.italic);
		}
	}
#endif

	switch (hinting) {
	case ASS_HINTING_NONE: flags = FT_LOAD_NO_HINTING; break;
	case ASS_HINTING_LIGHT: flags = FT_LOAD_FORCE_AUTOHINT | FT_LOAD_TARGET_LIGHT; break;
	case ASS_HINTING_NORMAL: flags = FT_LOAD_FORCE_AUTOHINT; break;
	case ASS_HINTING_NATIVE: flags = 0; break;
	}
	
	error = FT_Load_Glyph(face, index, FT_LOAD_NO_BITMAP | flags);
	if (error) {
		mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
		return 0;
	}
	
#if (FREETYPE_MAJOR > 2) || \
    ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR >= 2)) || \
    ((FREETYPE_MAJOR == 2) && (FREETYPE_MINOR == 1) && (FREETYPE_PATCH >= 10))
// FreeType >= 2.1.10 required
	if (!(face->style_flags & FT_STYLE_FLAG_ITALIC) && 
			(font->desc.italic > 55)) {
		FT_GlyphSlot_Oblique(face->glyph);
	}
#endif
	error = FT_Get_Glyph(face->glyph, &glyph);
	if (error) {
		mp_msg(MSGT_ASS, MSGL_WARN, MSGTR_LIBASS_ErrorLoadingGlyph);
		return 0;
	}
	
	return glyph;
}
Example #6
0
	void font_data::createGlyph(CharacterCode charCode) const
	{
		if (FT_Load_Glyph(_face, FT_Get_Char_Index(_face, charCode), FT_LOAD_DEFAULT))
		{
			LogError << "FT_Load_Glyph failed" << std::endl;
			throw std::runtime_error("FT_Load_Glyph failed");
		}

		FT_Glyph glyph;
		if (FT_Get_Glyph(_face->glyph, &glyph))
		{
			LogError << "FT_Get_Glyph failed" << std::endl;
			throw std::runtime_error("FT_Get_Glyph failed");
		}

		FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
		FT_BitmapGlyph bitmap_glyph(reinterpret_cast<FT_BitmapGlyph>(glyph));

		const FT_Bitmap& bitmap = bitmap_glyph->bitmap;

		const int width(next_p2(bitmap.width + 1));
		const int height(next_p2(bitmap.rows + 1));

		const size_t expanded_size(width * height * 2);
		GLubyte* expanded_data = new GLubyte[expanded_size];
		memset(expanded_data, 0, expanded_size);

		for (int j(0); j < height; ++j)
		{
			for (int i(0); i < width; ++i)
			{
				expanded_data[2 * (i + j * width)] = expanded_data[2 * (i + j * width) + 1] =
					(i >= bitmap.width || j >= bitmap.rows) ?
					0 : static_cast<GLubyte>(std::min(static_cast<float>(bitmap.buffer[i + bitmap.width * j]) * 1.5f, 255.0f));
			}
		}

		GlyphData glyphData;
		glyphData._width = _face->glyph->advance.x >> 6;

		glyphData._texture = new OpenGL::Texture();
		glyphData._texture->bind();

		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data);

		delete[] expanded_data;
		expanded_data = NULL;

		glyphData._callList = new OpenGL::CallList();
		glyphData._callList->startRecording();

		glyphData._texture->bind();

		const float xl((const float)bitmap_glyph->left);
		const float xh(xl + width);
		const float yl((const float)h - bitmap_glyph->top);
		const float yh(yl + height);

		glBegin(GL_TRIANGLE_STRIP);
		glTexCoord2f(0.0f, 0.0f);
		glVertex2f(xl, yl);
		glTexCoord2f(0.0f, 1.0f);
		glVertex2f(xl, yh);
		glTexCoord2f(1.0f, 0.0f);
		glVertex2f(xh, yl);
		glTexCoord2f(1.0f, 1.0f);
		glVertex2f(xh, yh);
		glEnd();

		glTranslatef(static_cast<float>(glyphData._width), 0.0f, 0.0f);

		glyphData._callList->endRecording();

		_cachedGlyphs[charCode] = glyphData;
	}
Example #7
0
bool CGLFTFont::MakeSymbol(FT_Face face, uint index, bool blend)
{
GLuint list = m_lists + index;
CGLTexture& texture = m_textures[index];
char Symbol = index + startsymbol;
if ( Symbol == ' ' )
  return MakeSpace( index );

uint CharIndex = FT_Get_Char_Index( face, Symbol );

int error = FT_Load_Glyph( face, CharIndex, FT_LOAD_DEFAULT );
if( error != 0 )
  return false;

FT_Glyph glyph;
error = FT_Get_Glyph( face->glyph, &glyph );
if( error != 0 )
  return false;

//!!******************************
FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;
FT_Bitmap& bitmap = bitmap_glyph->bitmap;
//!!***********************
int& bit_width = bitmap.width;
int& bit_height = bitmap.rows;

m_widths[index] = bit_width;

int tex_width = next_p2( bit_width );
int tex_height = next_p2( bit_height );

// Выделим память для данных текстуры.
size_t size = 2 * tex_width * tex_height;
GLubyte* texture_data = new GLubyte[ size ];
memset( texture_data, 0, size );

for(int y = 0; y < bit_height; ++y)
  for(int x=0; x < bit_width; ++x)
    {
    if (blend == false)
      {
      texture_data[2 * ( x + y*tex_width )] = 0xFF;
      if ( bitmap.buffer[x + bit_width*y] < 0x80)
        texture_data[2 * (x + y*tex_width) + 1] = 0;
      else
        texture_data[2 *( x + y*tex_width) + 1] = 0xFF;
      }
    else
      {
      texture_data[ 2 * (x + y*tex_width) ] = 0xFF;
      texture_data[2 * (x + y*tex_width) + 1] = bitmap.buffer[x + bit_width*y];
      }
    }

texture.Load( tex_width, tex_height, GL_UNSIGNED_BYTE, texture_data, GL_RGBA, 0 ,0, GL_LUMINANCE_ALPHA );
texture.SetParametr( GL_TEXTURE_MAG_FILTER, GL_LINEAR );
texture.SetParametr( GL_TEXTURE_MIN_FILTER, GL_LINEAR );

delete []texture_data;

glNewList( list, GL_COMPILE );
  glEnable( GL_BLEND );
  glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

  texture.Bind();

  double xscale = (double)bit_width / (double)tex_width;
  double yscale = (double)bit_height / (double)tex_height;

  glMatrixMode(GL_MODELVIEW);
  int downshift = 0 - (bitmap_glyph->top - bit_height);
  if ( downshift > 0 )
    {
    if ( m_downshift < downshift )
      m_downshift = downshift;

    glPushMatrix();
    glTranslatef(0,-downshift,0);
    }

  glBegin(GL_QUADS);
    glTexCoord2d(0,0);
    glVertex2f(0,bitmap.rows);

    glTexCoord2d(0,yscale);
    glVertex2f(0,0);

    glTexCoord2d(xscale,yscale);
    glVertex2f(bitmap.width,0);

    glTexCoord2d(xscale,0);
    glVertex2f(bitmap.width,bitmap.rows);
  glEnd();

  if ( downshift > 0 )
    glPopMatrix();

  glTranslatef( bit_width + m_symbolspacer, 0, 0 );

glEndList();
}
Example #8
0
bool Font::insertGlyph(Char character) {
	
	FT_Error error;
	FT_UInt glyphIndex = FT_Get_Char_Index(m_face, character);
	if(!glyphIndex) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	error = FT_Load_Glyph(m_face, glyphIndex, FT_LOAD_FORCE_AUTOHINT);
	if(error) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	error = FT_Render_Glyph(m_face->glyph, FT_RENDER_MODE_NORMAL);
	if(error) {
		insertPlaceholderGlyph(character);
		return false;
	}
	
	// Fill in info for this glyph.
	Glyph & glyph = m_glyphs[character];
	glyph.index = glyphIndex;
	glyph.size.x = m_face->glyph->bitmap.width;
	glyph.size.y = m_face->glyph->bitmap.rows;
	glyph.advance.x = float(m_face->glyph->linearHoriAdvance) / 65536.f;
	glyph.advance.y = float(m_face->glyph->linearVertAdvance) / 65536.f;
	glyph.lsb_delta = m_face->glyph->lsb_delta;
	glyph.rsb_delta = m_face->glyph->rsb_delta;
	glyph.draw_offset.x = m_face->glyph->bitmap_left;
	glyph.draw_offset.y = m_face->glyph->bitmap_top - m_face->glyph->bitmap.rows;
	glyph.uv_start = Vec2f_ZERO;
	glyph.uv_end = Vec2f_ZERO;
	glyph.texture = 0;
	
	// Some glyphs like spaces have a size of 0...
	if(glyph.size.x != 0 && glyph.size.y != 0) {
		
		Image imgGlyph;
		imgGlyph.create(size_t(glyph.size.x), size_t(glyph.size.y), Image::Format_A8);
		
		FT_Bitmap * srcBitmap = &m_face->glyph->bitmap;
		arx_assert(srcBitmap->pitch >= 0);
		arx_assert(unsigned(srcBitmap->pitch) == unsigned(srcBitmap->width));
		
		// Copy pixels
		unsigned char * src = srcBitmap->buffer;
		unsigned char * dst = imgGlyph.getData();
		memcpy(dst, src, glyph.size.x * glyph.size.y);
		
		Vec2i offset;
		if(!m_textures->insertImage(imgGlyph, glyph.texture, offset)) {
			LogWarning << "Could not upload glyph for character U+" << std::hex << character
			           << " (" << util::encode<util::UTF8>(character) << ") in font "
			           << m_info.name;
			insertPlaceholderGlyph(character);
			return false;
		}
		
		// Compute UV mapping for each glyph.
		const float textureSize = float(m_textures->getTextureSize());
		glyph.uv_start = Vec2f(offset) / Vec2f(textureSize);
		glyph.uv_end = Vec2f(offset + glyph.size) / Vec2f(textureSize);
	}
	
	return true;
}
const Sprite *GetGlyph(FontSize size, WChar key)
{
	FT_Face face = GetFontFace(size);
	FT_GlyphSlot slot;
	GlyphEntry new_glyph;
	GlyphEntry *glyph;
	SpriteLoader::Sprite sprite;
	int width;
	int height;
	int x;
	int y;

	assert(IsPrintable(key));

	/* Bail out if no face loaded, or for our special characters */
	if (face == NULL || (key >= SCC_SPRITE_START && key <= SCC_SPRITE_END)) {
		SpriteID sprite = GetUnicodeGlyph(size, key);
		if (sprite == 0) sprite = GetUnicodeGlyph(size, '?');
		return GetSprite(sprite, ST_FONT);
	}

	/* Check for the glyph in our cache */
	glyph = GetGlyphPtr(size, key);
	if (glyph != NULL && glyph->sprite != NULL) return glyph->sprite;

	slot = face->glyph;

	bool aa = GetFontAAState(size);

	FT_UInt glyph_index = FT_Get_Char_Index(face, key);
	if (glyph_index == 0) {
		if (key == '?') {
			/* The font misses the '?' character. Use sprite font. */
			SpriteID sprite = GetUnicodeGlyph(size, key);
			Sprite *spr = (Sprite*)GetRawSprite(sprite, ST_FONT, AllocateFont);
			assert(spr != NULL);
			new_glyph.sprite = spr;
			new_glyph.width  = spr->width + (size != FS_NORMAL);
			SetGlyphPtr(size, key, &new_glyph, false);
			return new_glyph.sprite;
		} else {
			/* Use '?' for missing characters. */
			GetGlyph(size, '?');
			glyph = GetGlyphPtr(size, '?');
			SetGlyphPtr(size, key, glyph, true);
			return glyph->sprite;
		}
	}
	FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT);
	FT_Render_Glyph(face->glyph, aa ? FT_RENDER_MODE_NORMAL : FT_RENDER_MODE_MONO);

	/* Despite requesting a normal glyph, FreeType may have returned a bitmap */
	aa = (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY);

	/* Add 1 pixel for the shadow on the medium font. Our sprite must be at least 1x1 pixel */
	width  = max(1, slot->bitmap.width + (size == FS_NORMAL));
	height = max(1, slot->bitmap.rows  + (size == FS_NORMAL));

	/* Limit glyph size to prevent overflows later on. */
	if (width > 256 || height > 256) usererror("Font glyph is too large");

	/* FreeType has rendered the glyph, now we allocate a sprite and copy the image into it */
	sprite.AllocateData(width * height);
	sprite.width = width;
	sprite.height = height;
	sprite.x_offs = slot->bitmap_left;
	sprite.y_offs = _ascender[size] - slot->bitmap_top;

	/* Draw shadow for medium size */
	if (size == FS_NORMAL) {
		for (y = 0; y < slot->bitmap.rows; y++) {
			for (x = 0; x < slot->bitmap.width; x++) {
				if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
					sprite.data[1 + x + (1 + y) * sprite.width].m = SHADOW_COLOUR;
					sprite.data[1 + x + (1 + y) * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
				}
			}
		}
	}

	for (y = 0; y < slot->bitmap.rows; y++) {
		for (x = 0; x < slot->bitmap.width; x++) {
			if (aa ? (slot->bitmap.buffer[x + y * slot->bitmap.pitch] > 0) : HasBit(slot->bitmap.buffer[(x / 8) + y * slot->bitmap.pitch], 7 - (x % 8))) {
				sprite.data[x + y * sprite.width].m = FACE_COLOUR;
				sprite.data[x + y * sprite.width].a = aa ? slot->bitmap.buffer[x + y * slot->bitmap.pitch] : 0xFF;
			}
		}
	}

	new_glyph.sprite = BlitterFactoryBase::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
	new_glyph.width  = slot->advance.x >> 6;

	SetGlyphPtr(size, key, &new_glyph);

	return new_glyph.sprite;
}
Example #10
0
GlyphBLF *blf_glyph_add(FontBLF *font, unsigned int index, unsigned int c)
{
	FT_GlyphSlot slot;
	GlyphBLF *g;
	FT_Error err;
	FT_Bitmap bitmap, tempbitmap;
	int sharp = (U.text_render & USER_TEXT_DISABLE_AA);
	FT_BBox bbox;
	unsigned int key;

	g = blf_glyph_search(font->glyph_cache, c);
	if (g)
		return g;

	if (sharp)
		err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_MONO);
	else
		err = FT_Load_Glyph(font->face, (FT_UInt)index, FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP);  /* Sure about NO_* flags? */
	if (err)
		return NULL;

	/* get the glyph. */
	slot = font->face->glyph;

	if (sharp) {
		err = FT_Render_Glyph(slot, FT_RENDER_MODE_MONO);

		/* Convert result from 1 bit per pixel to 8 bit per pixel */
		/* Accum errors for later, fine if not interested beyond "ok vs any error" */
		FT_Bitmap_New(&tempbitmap);
		err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1); /* Does Blender use Pitch 1 always? It works so far */
		err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap);
		err += FT_Bitmap_Done(font->ft_lib, &tempbitmap);
	}
	else {
		err = FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
	}

	if (err || slot->format != FT_GLYPH_FORMAT_BITMAP)
		return NULL;

	g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add");
	g->c = c;
	g->idx = (FT_UInt)index;
	g->xoff = -1;
	g->yoff = -1;
	bitmap = slot->bitmap;
	g->width = bitmap.width;
	g->height = bitmap.rows;

	if (g->width && g->height) {
		if (sharp) {
			/* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */
			int i;
			for (i = 0; i < (g->width * g->height); i++) {
				bitmap.buffer[i] = 255 * bitmap.buffer[i];
			}
		}

		g->bitmap = (unsigned char *)MEM_mallocN(g->width * g->height, "glyph bitmap");
		memcpy((void *)g->bitmap, (void *)bitmap.buffer, g->width * g->height);
	}

	g->advance = ((float)slot->advance.x) / 64.0f;
	g->pos_x = slot->bitmap_left;
	g->pos_y = slot->bitmap_top;
	g->pitch = slot->bitmap.pitch;

	FT_Outline_Get_CBox(&(slot->outline), &bbox);
	g->box.xmin = ((float)bbox.xMin) / 64.0f;
	g->box.xmax = ((float)bbox.xMax) / 64.0f;
	g->box.ymin = ((float)bbox.yMin) / 64.0f;
	g->box.ymax = ((float)bbox.yMax) / 64.0f;

	key = blf_hash(g->c);
	BLI_addhead(&(font->glyph_cache->bucket[key]), g);
	return g;
}
CTextRenderer::CGlyph* CTextRenderer::LoadGlyph(CGlyphCache* pCache, CGlyphId GlyphId)
{
	if(m_Fonts.size() == 0)
	{
		dbg_msg("TextRenderer", "No font loaded");
		return 0;
	}
	
	CFont* pFont = m_Fonts[GlyphId.m_FontId];
	if(FT_Set_Pixel_Sizes(pFont->m_FtFace, 0, pCache->m_FontSize) != FT_Err_Ok)
	{
		dbg_msg("TextRenderer", "Can't set pixel size %d", pCache->m_FontSize);
		return 0;
	}
	if(FT_Load_Glyph(pFont->m_FtFace, GlyphId.m_GlyphCode, FT_LOAD_RENDER|FT_LOAD_NO_BITMAP) != FT_Err_Ok)
	{
		dbg_msg("TextRenderer", "Can't load glyph %d", GlyphId.m_GlyphCode);
		return 0;
	}
	
	FT_Bitmap* pBitmap = &pFont->m_FtFace->glyph->bitmap;
	int BitmapWidth = pBitmap->width;
	int BitmapHeight = pBitmap->rows;
	int BBWidth = BitmapWidth+2*s_Margin;
	int BBHeight = BitmapHeight+2*s_Margin;
	
	CTextRenderer::CGlyph* pGlyph = pCache->NewGlyph(GlyphId, BBWidth, BBHeight);
	
	pGlyph->m_GlyphId = GlyphId;
	pGlyph->m_AdvanceX = (pFont->m_FtFace->glyph->advance.x >> 6);
	pGlyph->m_OffsetX = pFont->m_FtFace->glyph->bitmap_left - s_Margin;
	pGlyph->m_OffsetY = pFont->m_FtFace->glyph->bitmap_top + s_Margin;
	
	if(pBitmap->pixel_mode == FT_PIXEL_MODE_GRAY)
	{
		for(int j = 0; j < BitmapHeight; j++)
		{
			for(int i = 0; i < BitmapWidth; i++)
			{
				int CacheDataIndex = (j+s_Margin)*pCache->m_Width + (i+s_Margin);
				pGlyph->m_pData[CacheDataIndex] = pBitmap->buffer[j*pBitmap->pitch+i];
			}
		}
	}
	else if(pBitmap->pixel_mode == FT_PIXEL_MODE_MONO)
	{
		for(int j = 0; j < BitmapHeight; j++)
		{
			for(int i = 0; i < BitmapWidth; i++)
			{
				int CacheDataIndex = (j+s_Margin)*pCache->m_Width + (i+s_Margin);
				if(pBitmap->buffer[j*pBitmap->pitch+i/8]&(1<<(7-(i%8))))
					pGlyph->m_pData[CacheDataIndex] = 255;
				else
					pGlyph->m_pData[CacheDataIndex] = 0;
			}
		}
	}
	
	mem_zero(s_aGlyphBuffer, (pGlyph->m_Granularity.x * pCache->m_PPG) * (pGlyph->m_Granularity.y * pCache->m_PPG));
	
	for(int j = s_Margin; j < pGlyph->m_Height-s_Margin; j++)
	{
		for(int i = s_Margin; i < pGlyph->m_Width-s_Margin; i++)
		{
			s_aGlyphBuffer[j*(pGlyph->m_Granularity.x * pCache->m_PPG) + i] = pGlyph->m_pData[j*pCache->m_Width + i];
		}
	}
	
	pCache->UpdateTexture(pGlyph, s_aGlyphBuffer);
	
	return pGlyph;
}
Example #12
0
void cache_glyphs(struct ft2_source *srcdata, wchar_t *cache_glyphs)
{
	FT_GlyphSlot slot = 0;
	FT_UInt glyph_index = 0;

	if (!srcdata->font_face || !cache_glyphs)
		return;

	//slot = srcdata->font_face->glyph;

	uint32_t dx = srcdata->texbuf_x, dy = srcdata->texbuf_y;
	uint8_t alpha;

	int32_t cached_glyphs = 0;
	size_t len = wcslen(cache_glyphs);

	for (size_t i = 0; i < len; i++) {
		FT_Face curFace;
		glyph_index = FT_Get_Char_Index_Fallback(srcdata, &curFace,
			cache_glyphs[i]);

		if (curFace == 0)
			goto skip_glyph;

		slot = curFace->glyph;

		if (src_glyph != NULL)
			goto skip_glyph;

		FT_Load_Glyph(curFace, glyph_index, FT_LOAD_DEFAULT);

		bool isUseFallback = slot->face == srcdata->fallback_face;
		bool shouldBolden = ((!isUseFallback && srcdata->fake_bold) || (isUseFallback && srcdata->fallback_fake_bold));

		if (slot->format == FT_GLYPH_FORMAT_OUTLINE && shouldBolden)
			FT_Outline_EmboldenXY(&slot->outline, 0x80, 0x40);

		FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);

		uint32_t g_w = slot->bitmap.width;
		uint32_t g_h = slot->bitmap.rows;

		if (srcdata->max_h < g_h) srcdata->max_h = g_h;

		if (dx + g_w >= texbuf_w) {
			dx = 0;
			dy += srcdata->max_h + 1;
		}

		src_glyph = bzalloc(sizeof(struct glyph_info));
		src_glyph->u = (float)dx / (float)texbuf_w;
		src_glyph->u2 = (float)(dx + g_w) / (float)texbuf_w;
		src_glyph->v = (float)dy / (float)texbuf_h;
		src_glyph->v2 = (float)(dy + g_h) / (float)texbuf_h;
		src_glyph->w = g_w;
		src_glyph->h = g_h;
		src_glyph->yoff = slot->bitmap_top;
		src_glyph->xoff = slot->bitmap_left;
		src_glyph->xadv = slot->advance.x >> 6;

		for (uint32_t y = 0; y < g_h; y++) {
			for (uint32_t x = 0; x < g_w; x++) {
				alpha = slot->bitmap.buffer[glyph_pos];
				srcdata->texbuf[buf_pos] =
					0x00FFFFFF ^ ((uint32_t)alpha << 24);
			}
		}

		dx += (g_w + 1);
		if (dx >= texbuf_w) {
			dx = 0;
			dy += srcdata->max_h;
		}

		cached_glyphs++;
	skip_glyph:;
	}

	srcdata->texbuf_x = dx;
	srcdata->texbuf_y = dy;

	if (cached_glyphs > 0) {

		obs_enter_graphics();

		if (srcdata->tex != NULL) {
			gs_texture_t *tmp_texture = NULL;
			tmp_texture = srcdata->tex;
			srcdata->tex = NULL;
			gs_texture_destroy(tmp_texture);
		}

		srcdata->tex = gs_texture_create(texbuf_w, texbuf_h,
			GS_RGBA, 1, (const uint8_t **)&srcdata->texbuf, 0);

		obs_leave_graphics();
	}
}
Example #13
0
void CFreeFont::MakeLetter(wchar_t code)
{
	// Первая вещь, которую нам надо сделать, это вывести наш символ
	// в растр. Это делается набором команд FreeType

	// Загрузить глифы для каждого символа.
	if(FT_Load_Glyph(face, FT_Get_Char_Index(face, code), FT_LOAD_DEFAULT))
		throw NOVA_EXP("CFreeFont::MakeLetter - FT_Load_Glyph failed", BAD_OPERATION);

	// Поместить глиф в объект.
	FT_Glyph glyph;
	if(FT_Get_Glyph(face->glyph, &glyph))
		throw NOVA_EXP("CFreeFont::MakeLetter - FT_Get_Glyph failed", BAD_OPERATION);

	// Конвертировать глиф в растр.
	FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
	FT_BitmapGlyph bitmap_glyph = reinterpret_cast<FT_BitmapGlyph>(glyph);

	// С помощью этой ссылки, получаем легкий доступ до растра.
	FT_Bitmap & bitmap = bitmap_glyph->bitmap;

    // Используем нашу вспомогательную функцию для вычисления ширины и высоты
	// текстуры для нашего растра.
	nInt32 bwidth = NextP2(bitmap.width);
	nInt32 bheight = NextP2(bitmap.rows);

	// Выделим память для данных текстуры.
	//nByte * expanded_data = NULL;
	//expanded_data = getmem<nByte>(expanded_data, 2 * bwidth * bheight);
	CMemoryBuffer mem;
	mem.AllocBuffer(2 * bwidth * bheight);
	nByte * expanded_data = (nova::nByte *)mem.GetBegin();

	// Поместим данные в расширенный растр.
	// Отмечу, что использован двухканальный растр (Один для
	// канала яркости и один для альфа), но мы будем назначать
	// обоим каналам одно и тоже значение, которое мы
	// получим из растра FreeType.
	// Мы используем оператор ?: для того чтобы поместить 0 в зону вне растра FreeType.
	for(nInt32 j = 0; j < bheight; ++j)
		for(nInt32 i = 0; i < bwidth; ++i)
			expanded_data[2*(i + j * bwidth)] = expanded_data[2*(i + j * bwidth)+1] =
				(i >= bitmap.width || j >= bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];

/*	GLuint texture;
	glGenTextures(1, &texture);

	glBindTexture( GL_TEXTURE_2D, texture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	// Здесь мы создаем текстуру
	// Помните, что используем GL_LUMINANCE_ALPHA, чтобы было два альфа канала данных
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, bwidth, bheight, 0,
		GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data);
*/
	//nInt32 tid = CTextureManager::GetSingeltonPtr()->AddTexture(GL_TEXTURE_2D,
	//	expanded_data, bwidth, bheight, CImageFormats::NF_LUMINANCE_ALPHA);
/*	CTexturePtr ptex = CTextureManager::GetSingeltonPtr()->AddTexture(new CTexture(fname.c_str(), GL_TEXTURE_2D));
	ptex->SetEnvType(GL_MODULATE);
	ptex->CreateTexture(expanded_data, bwidth, bheight, CImageFormats::NF_LUMINANCE_ALPHA, GL_CLAMP);

	// После создания текстуры, мы больше не нуждаемся в промежуточных данных.
	freemems(expanded_data);

	CLetter letter(slot->metrics.horiBearingX >> 6, slot->metrics.horiBearingY >> 6,
		slot->metrics.horiAdvance >> 6, bwidth, bheight, bitmap.width, bitmap.rows,
		code, ptex);

*/
	nstring resnamet;
	nstring resnamei("TempFontImage");
	resnamet = mName + "_" + CStringUtils::IntTo16xString(static_cast<nInt32>(code));
// Создаем промежуточное изображение в памяти
	CImagePtr pImage = CImageManager::GetSingelton().CreateNewImage(resnamei, mName, mem,
		bwidth, bheight, 1, CImageFormats::NF_LUMINANCE_ALPHA, CResource::NV_FREE);
// На базе изображения создаем текстуру
	CTexturePtr texp = CTextureManager::GetSingelton().CreateNewTexture(resnamet, mName, pImage);

	// После создания текстуры, мы больше не нуждаемся в промежуточных данных.
	mem.FreeBuffer();

	CLetter letter(slot->metrics.horiBearingX >> 6, slot->metrics.horiBearingY >> 6,
		slot->metrics.horiAdvance >> 6, bwidth, bheight, bitmap.width, bitmap.rows,
		code, texp);
	mSize += texp->GetSize();

/// Создаем дисплейный список на букву ///////////////////////////////////////////////
	letter.GetDispList().CreateList();
	letter.GetDispList().BeginList();
/// //////////////////////////////////////////////////////////////////////////////////
	if(!texp.IsNull())
		texp->ApplyTexture();

// Вычислим какая часть нашей текстуры будет заполнена пустым пространством.
// Мы рисуем только ту часть текстуры, в которой находится символ, и сохраняем
// информацию в переменных x и y, затем, когда мы рисуем четырехугольник,
// мы будем только ссылаться на ту часть текстуры, в которой непосредственно
// содержится символ.
	nReal x = static_cast<nReal>(letter.GetBitmapw()) / static_cast<nReal>(letter.GetWidth()),
		y = static_cast<nReal>(letter.GetBitmapr()) / static_cast<nReal>(letter.GetHeight());

	//glBindTexture(GL_TEXTURE_2D, let.GetTex());

	glBegin(GL_QUADS);
		glTexCoord2f(0,0);
		glVertex2i(0,0);
		glTexCoord2f(0,y);
		glVertex2i(0,letter.GetBitmapr());
		glTexCoord2f(x,y);
		glVertex2i(letter.GetBitmapw(), letter.GetBitmapr());
		glTexCoord2f(x,0);
		glVertex2i(letter.GetBitmapw(), 0);
	glEnd();

/// Завершаем дисплейный список //////////////////////////////////////////////////
	letter.GetDispList().EndList();
/// //////////////////////////////////////////////////////////////////////////////

	letters_map[code] = letter;
}
Example #14
0
value ftIterateGlyphs( value font, value callbacks ) {
    if( !val_is_object(callbacks) ) {
        ft_failure_v("not a callback function object: ", callbacks );
    }
// printf("A\n");
    field endGlyph = val_id("endGlyph");
    field startContour = val_id("startContour");
    field endContour = val_id("endContour");
    field lineTo = val_id("lineTo");
    field curveTo = val_id("curveTo");
// printf("B\n");
    
    if( !val_is_object(font) ) {
        ft_failure_v("not a freetype font face: ", font );
    }
    value __f = val_field( font, val_id("__f") );
    if( __f == NULL || !val_is_abstract( __f ) || !val_is_kind( __f, k_ft_face ) ) {
        ft_failure_v("not a freetype font face: ", font );
    }
    FT_Face *face = val_data( __f );
// printf("C\n");

	FT_UInt glyph_index;
	FT_ULong character;
	FT_Outline *outline;

    field f_character = val_id("character");
    field f_advance = val_id("advance");
    
    character = FT_Get_First_Char( *face, &glyph_index );

// printf("D\n");
    while( character != 0 ) {
        if( FT_Load_Glyph( *face, glyph_index, FT_LOAD_NO_BITMAP ) ) {
            // ignore (TODO report?)
        } else if( (*face)->glyph->format != FT_GLYPH_FORMAT_OUTLINE ) {
            // ignore (TODO)
        } else {
            outline = &((*face)->glyph->outline);
		    int start = 0, end, contour, p;
		    char control, cubic;
		    int n,i;
// printf("  1\n");
		    for( contour = 0; contour < outline->n_contours; contour++ ) {
			    end = outline->contours[contour];
			    n=0;

    
			    for( p = start; p<=end; p++ ) {
				    control = !(outline->tags[p] & 0x01);
				    cubic = outline->tags[p] & 0x02;

				    if( p==start ) {
                        val_ocall2( callbacks, startContour, 
                                    alloc_int( outline->points[p-n].x ),
                                    alloc_int( outline->points[p-n].y ) );
				    }

				    if( !control && n > 0 ) {
					    importGlyphPoints( &(outline->points[(p-n)+1]), n-1, callbacks, lineTo, curveTo, cubic );
					    n=1;
				    } else {
					    n++;
				    }
			    }

			    if( n ) {
				    // special case: repeat first point
				    FT_Vector points[n+1];
				    int s=(end-n)+2;
				    for( i=0; i<n-1; i++ ) {
					    points[i].x = outline->points[s+i].x;
					    points[i].y = outline->points[s+i].y;
				    }
				    points[n-1].x = outline->points[start].x;
				    points[n-1].y = outline->points[start].y;

				    importGlyphPoints( points, n-1, callbacks, lineTo, curveTo, false );
			    }

			    start = end+1;
                val_ocall0( callbacks, endContour );
		    }

// printf("  2\n");
            val_ocall2( callbacks, endGlyph, alloc_int( character ), alloc_int( (*face)->glyph->advance.x ) );
// printf("  3\n");
        }
// printf("  E\n");
        character = FT_Get_Next_Char( *face, character, &glyph_index );
// printf("  F\n");
    }
    
// printf("  Goo\n");
    return val_true;
}
void Java_org_iisc_mile_indictext_android_EditIndicText_drawIndicText(
		JNIEnv* env, jobject thiz, jstring unicodeText, jint xStart,
		jint yBaseLine, jint charHeight, jobject lock) {
	FT_Library ft_library;
	FT_Face ft_face;

	hb_font_t *font;
	hb_buffer_t *buffer;
	int glyph_count;
	hb_glyph_info_t *glyph_info;
	hb_glyph_position_t *glyph_pos;
	hb_bool_t fail;

	FT_UInt glyph_index;
	FT_GlyphSlot slot;
	FT_Error error;

	char* fontFilePath;
	jboolean iscopy;
	const jchar *text;
	int num_chars, i;

	int pen_x;
	int glyphPosX, glyphPosY;

	fontFilePath =
			"/sdcard/Android/data/org.iisc.mile.indictext.android/Lohit-Kannada.ttf";
	text = (*env)->GetStringChars(env, unicodeText, &iscopy);
	num_chars = (*env)->GetStringLength(env, unicodeText);

	error = FT_Init_FreeType(&ft_library); /* initialize library */
	if (error) {
		__android_log_print(6, "drawIndicText",
				"Error initializing FreeType library\n");
		return;
	}
	__android_log_print(2, "drawIndicText",
			"Successfully initialized FreeType library\n");

	error = FT_New_Face(ft_library, fontFilePath, 0, &ft_face); /* create face object */
	if (error == FT_Err_Unknown_File_Format) {
		__android_log_print(6, "drawIndicText",
				"The font file could be opened and read, but it appears that its font format is unsupported");
		return;
	} else if (error) {
		__android_log_print(6, "drawIndicText",
				"The font file could not be opened or read, or it might be broken");
		return;
	}
	__android_log_print(2, "drawIndicText",
			"Successfully created font-face object\n");

	font = hb_ft_font_create(ft_face, NULL);

	error = FT_Set_Pixel_Sizes(ft_face, 0, charHeight); /* set character size */
	/* error handling omitted */
	__android_log_print(2, "drawIndicText",
			"Successfully set character size to %d\n", charHeight);

	__android_log_print(2, "drawIndicText", "Text being rendered = %s\n", text);
	slot = ft_face->glyph;
	pen_x = xStart;

	/* Create a buffer for harfbuzz to use */
	buffer = hb_buffer_create();

	//hb_buffer_set_unicode_funcs(buffer, hb_icu_get_unicode_funcs());
	//alternatively you can use hb_buffer_set_unicode_funcs(buffer, hb_glib_get_unicode_funcs());

	//hb_buffer_set_direction(buffer, HB_DIRECTION_LTR); /* or LTR */
	hb_buffer_set_script(buffer, HB_SCRIPT_KANNADA); /* see hb-unicode.h */
	//hb_buffer_set_language(buffer, hb_language_from_string("ka"));

	/* Layout the text */
	hb_buffer_add_utf16(buffer, text, num_chars, 0, num_chars);
	__android_log_print(2, "drawIndicText", "Before HarfBuzz shape()\n");
	hb_shape(font, buffer, NULL, 0);
	__android_log_print(2, "drawIndicText", "After HarfBuzz shape()\n");

	glyph_count = hb_buffer_get_length(buffer);
	glyph_info = hb_buffer_get_glyph_infos(buffer, 0);
	glyph_pos = hb_buffer_get_glyph_positions(buffer, 0);

	for (i = 0; i < glyph_count; i++) {
		glyph_index = glyph_info[i].codepoint;
		__android_log_print(2, "drawIndicText", "Glyph%d = %x", i, glyph_index);
		error = FT_Load_Glyph(ft_face, glyph_index, FT_LOAD_DEFAULT);
		if (error) {
			continue; /* ignore errors */
		}
		/* convert to an anti-aliased bitmap */
		error = FT_Render_Glyph(ft_face->glyph, FT_RENDER_MODE_NORMAL);
		if (error) {
			continue;
		}

		/* now, draw to our target surface (convert position) */
		draw_bitmap(&slot->bitmap, pen_x + slot->bitmap_left,
				yBaseLine - slot->bitmap_top, env, thiz, lock);
		//glyphPosX = pen_x + glyph_pos[i].x_offset;
		//glyphPosY = yBaseLine - glyph_pos[i].y_offset;
		//draw_bitmap(&slot->bitmap, glyphPosX, glyphPosY, env, thiz, lock);

		/* increment pen position */
		pen_x += slot->advance.x >> 6;
		//pen_x += glyph_pos[i].x_advance / 64;
		__android_log_print(2, "drawIndicText",
				"\tx_offset = %d\ty_offset = %d\tx_advance = %d\ty_advance = %d\n",
				glyph_pos[i].x_offset / 64, glyph_pos[i].y_offset / 64,
				glyph_pos[i].x_advance / 64, glyph_pos[i].y_advance / 64);
		__android_log_print(2, "drawIndicText",
				"\tbitmap_left = %d\tbitmap_top = %d\tadvance.x = %d\tadvance.y = %d\n",
				slot->bitmap_left, slot->bitmap_top, slot->advance.x >> 6,
				slot->advance.y >> 6);
	}

	hb_buffer_destroy(buffer);

	(*env)->ReleaseStringChars(env, unicodeText, text);
	hb_font_destroy(font);
	FT_Done_Face(ft_face);
	FT_Done_FreeType(ft_library);

	return;
}
Example #16
0
bool KG3DFontTexture::InitGlyph(UINT charCode, void* ftGlyph, KG3DTextureGlyph* fontGlyph, BOOL bBorder)
{
	BOOL bRetCode = FALSE;
	FT_GlyphSlot pGlyphSlot = (FT_GlyphSlot)ftGlyph;
	FT_Error nError = 0;
	KG3DTextureGlyph* pGlyphFont = (KG3DTextureGlyph*)fontGlyph;
	FT_UInt nGlyph = 0;
	BOOL bBit = FALSE;
	UINT uX = 0;
	UINT uY = 0;
	int nDivisor = 1;
    FT_F26Dot6 FontSize = 0;

	ASSERT(pGlyphSlot);
	ASSERT(pGlyphFont);

	KGLOG_PROCESS_ERROR(pGlyphSlot);

	nGlyph = FT_Get_Char_Index(m_pFontFace, charCode);
	KG_PROCESS_ERROR(nGlyph != 0);

	// request glyph texture
	pGlyphFont->nTextureID = GetTextureIndex();
	KGLOG_PROCESS_ERROR(pGlyphFont->nTextureID != KG3DFontRenderer::INVALID_TEXTURE_INDEX);

    uX = m_uEmptyTextureX;
    uY = m_uEmptyTextureY;

	for (UINT uMipmapLevel = 0; uMipmapLevel < m_uMipmapLevel; ++uMipmapLevel)
	{
        FontSize = FontFixMul(m_InitParams.fPixel);
        nError = FT_Set_Char_Size(m_pFontFace, FontSize, 0, 0, 0);
		KGLOG_PROCESS_ERROR(nError == 0);

		nError = FT_Load_Glyph(m_pFontFace, nGlyph, m_InitParams.dwLoadFlag);
		KGLOG_PROCESS_ERROR(nError == 0);

        nError = FT_Render_Glyph(m_pFontFace->glyph, (FT_Render_Mode)m_InitParams.dwRenderMode);
		KGLOG_PROCESS_ERROR(nError == 0);
		KGLOG_PROCESS_ERROR(m_pFontFace->glyph->format == FT_GLYPH_FORMAT_BITMAP);

        // empty glyph?
        // 如果轮廓线没有被上载,FreeType 使用的位图渲染模式为 1bit/pixel
        bBit = pGlyphSlot->outline.n_contours == 0 && pGlyphSlot->outline.n_points == 0 || FT_PIXEL_MODE_MONO == m_pFontFace->glyph->bitmap.pixel_mode;
        if (bBit)
        {
            bRetCode = m_pRenderer->UploadMonoTexture(pGlyphFont->nTextureID, uMipmapLevel, uX / nDivisor, uY / nDivisor, 
                m_pFontFace->glyph->bitmap.width, m_pFontFace->glyph->bitmap.rows, 
                m_pFontFace->glyph->bitmap.pitch, m_pFontFace->glyph->bitmap.buffer);
            KGLOG_PROCESS_ERROR(bRetCode);
        }
        else
        {
            bRetCode = m_pRenderer->UploadTexture(pGlyphFont->nTextureID, uMipmapLevel, uX / nDivisor, uY / nDivisor, 
                m_pFontFace->glyph->bitmap.width, m_pFontFace->glyph->bitmap.rows, m_pFontFace->glyph->bitmap.buffer, m_uchAdjustBuffer);
            KGLOG_PROCESS_ERROR(bRetCode);
        }

		nDivisor *= 2;

		if (uMipmapLevel == 0)
		{
            pGlyphFont->xOffset = (FLOAT)m_pFontFace->glyph->bitmap_left;
            pGlyphFont->yOffset = (FLOAT)m_fontAscender - m_pFontFace->glyph->bitmap_top;

            pGlyphFont->cx = (FLOAT)m_pFontFace->glyph->bitmap.width;
            pGlyphFont->cy = (FLOAT)m_pFontFace->glyph->bitmap.rows;

            pGlyphFont->vFontU.x = (float)m_uEmptyTextureX / (float)m_uTextureWidth;
            pGlyphFont->vFontU.y = (float)m_uEmptyTextureY / (float)m_uTextureHeight;

            pGlyphFont->vFontV.x = (float)(m_uEmptyTextureX + m_pFontFace->glyph->bitmap.width) / (float)m_uTextureWidth;
            pGlyphFont->vFontV.y = (float)(m_uEmptyTextureY + m_pFontFace->glyph->bitmap.rows) / (float)m_uTextureHeight;

            m_uEmptyTextureX += static_cast<INT>(pGlyphFont->cx);
            m_uEmptyTextureX += KG3DFONT_DEFAULT_PADDING;
        }
	}

    FontSize = FontFixMul(m_InitParams.fPixel);
    nError = FT_Set_Char_Size(m_pFontFace, FontSize, 0, 0, 0);
    KGLOG_PROCESS_ERROR(nError == 0);

	if (bBorder && m_uMipmapLevel == 1)
	{
		pGlyphFont->nBoderTextureID = GetTextureIndex();
		KGLOG_PROCESS_ERROR(pGlyphFont->nBoderTextureID != KG3DFontRenderer::INVALID_TEXTURE_INDEX);

		pGlyphFont->vBorderU.x = (float)(m_uEmptyTextureX - 1) / (float)m_uTextureWidth;
		pGlyphFont->vBorderU.y = (float)(m_uEmptyTextureY - 1) / (float)m_uTextureHeight;

		pGlyphFont->vBorderV.x = (float)(m_uEmptyTextureX + m_pFontFace->glyph->bitmap.width + 1) / (float)m_uTextureWidth;
		pGlyphFont->vBorderV.y = (float)(m_uEmptyTextureY + m_pFontFace->glyph->bitmap.rows + 1) / (float)m_uTextureHeight;

		if (bBit)
		{
			bRetCode = m_pRenderer->UploadMonoBoderTexture(pGlyphFont->nBoderTextureID, 0, m_uEmptyTextureX, m_uEmptyTextureY, 
				(UINT)pGlyphFont->cx,
				(UINT)pGlyphFont->cy,
				(UINT)m_pFontFace->glyph->bitmap.pitch,
				m_pFontFace->glyph->bitmap.buffer);
			KGLOG_PROCESS_ERROR(bRetCode);
		}
		else
		{
			bRetCode = m_pRenderer->UploadBoderTexture(pGlyphFont->nBoderTextureID, 0, m_uEmptyTextureX, m_uEmptyTextureY, 
				(UINT)pGlyphFont->cx,
				(UINT)pGlyphFont->cy, 
				m_pFontFace->glyph->bitmap.buffer, m_uchAdjustBuffer);
			KGLOG_PROCESS_ERROR(bRetCode);
		}

		m_uEmptyTextureX += static_cast<INT>( pGlyphFont->cx );
		m_uEmptyTextureX += KG3DFONT_DEFAULT_PADDING;
	}

	return true;
Exit0:
	return false;
}
Example #17
0
static FT_Error Load_Glyph( TTF_Font* font, uint16_t ch, 
	c_glyph* cached, int want )
{
	FT_Face face;
	FT_Error error;
	FT_GlyphSlot glyph;
	FT_Glyph_Metrics* metrics;
	FT_Outline* outline;

	if ( !font || !font->face ) {
		return FT_Err_Invalid_Handle;
	}

	face = font->face;

	/* Load the glyph */
	if ( ! cached->index ) {
		cached->index = FT_Get_Char_Index( face, ch );
	}
	error = FT_Load_Glyph( face, cached->index, FT_LOAD_DEFAULT | font->hinting);
	if( error ) {
		return error;
	}

	/* Get our glyph shortcuts */
	glyph = face->glyph;
	metrics = &glyph->metrics;
	outline = &glyph->outline;

	/* Get the glyph metrics if desired */
	if ( (want & CACHED_METRICS) && !(cached->stored & CACHED_METRICS) ) {
		if ( FT_IS_SCALABLE( face ) ) {
			/* Get the bounding box */
			cached->minx = FT_FLOOR(metrics->horiBearingX);
			cached->maxx = cached->minx + FT_CEIL(metrics->width);
			cached->maxy = FT_FLOOR(metrics->horiBearingY);
			cached->miny = cached->maxy - FT_CEIL(metrics->height);
			cached->yoffset = font->ascent - cached->maxy;
			cached->advance = FT_CEIL(metrics->horiAdvance);
		} else {
			/* Get the bounding box for non-scalable format.
			 * Again, freetype2 fills in many of the font metrics
			 * with the value of 0, so some of the values we
			 * need must be calculated differently with certain
			 * assumptions about non-scalable formats.
			 * */
			cached->minx = FT_FLOOR(metrics->horiBearingX);
			cached->maxx = cached->minx + FT_CEIL(metrics->horiAdvance);
			cached->maxy = FT_FLOOR(metrics->horiBearingY);
			cached->miny = cached->maxy - FT_CEIL(
				face->available_sizes[font->font_size_family].height);
			cached->yoffset = 0;
			cached->advance = FT_CEIL(metrics->horiAdvance);
		}
		
		/* Adjust for bold and italic text */
		if( TTF_HANDLE_STYLE_BOLD(font) ) {
			cached->maxx += font->glyph_overhang;
		}
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			cached->maxx += (int)ceil(font->glyph_italics);
		}
		cached->stored |= CACHED_METRICS;
	}

	if ( ((want & CACHED_BITMAP) && !(cached->stored & CACHED_BITMAP)) ||
	     ((want & CACHED_PIXMAP) && !(cached->stored & CACHED_PIXMAP)) ) {
		int mono = (want & CACHED_BITMAP);
		int i;
		FT_Bitmap* src;
		FT_Bitmap* dst;
		FT_Glyph bitmap_glyph = NULL;

		/* Handle the italic style */
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			FT_Matrix shear;

			shear.xx = 1 << 16;
			shear.xy = (int) ( font->glyph_italics * ( 1 << 16 ) ) / font->height;
			shear.yx = 0;
			shear.yy = 1 << 16;

			FT_Outline_Transform( outline, &shear );
		}

		/* Render as outline */
		if( (font->outline > 0) && glyph->format != FT_GLYPH_FORMAT_BITMAP ) {
			FT_Stroker stroker;
			FT_Get_Glyph( glyph, &bitmap_glyph );
			error = FT_Stroker_New( library, &stroker );
			if( error ) {
				return error;
			}
			FT_Stroker_Set( stroker, font->outline * 64, FT_STROKER_LINECAP_ROUND, 
				FT_STROKER_LINEJOIN_ROUND, 0 ); 
			FT_Glyph_Stroke( &bitmap_glyph, stroker, 1 /*delete the original glyph*/);
			FT_Stroker_Done( stroker );
			/* Render the glyph */
			error = FT_Glyph_To_Bitmap( &bitmap_glyph, mono ? 
				ft_render_mode_mono : ft_render_mode_normal, 0, 1 );
			if( error ) {
				FT_Done_Glyph( bitmap_glyph );
				return error;
			}
			src = &((FT_BitmapGlyph)bitmap_glyph)->bitmap;
		} else {
			/* Render the glyph */
			error = FT_Render_Glyph( glyph, mono ?
				ft_render_mode_mono : ft_render_mode_normal );
			if( error ) {
				return error;
			}
			src = &glyph->bitmap;
		}
		/* Copy over information to cache */
		if ( mono ) {
			dst = &cached->bitmap;
		} else {
			dst = &cached->pixmap;
		}
		memcpy( dst, src, sizeof( *dst ) );

		/* FT_Render_Glyph() and .fon fonts always generate a
		 * two-color (black and white) glyphslot surface, even
		 * when rendered in ft_render_mode_normal. */
		/* FT_IS_SCALABLE() means that the font is in outline format,
		 * but does not imply that outline is rendered as 8-bit
		 * grayscale, because embedded bitmap/graymap is preferred
		 * (see FT_LOAD_DEFAULT section of FreeType2 API Reference).
		 * FT_Render_Glyph() canreturn two-color bitmap or 4/16/256-
		 * color graymap according to the format of embedded bitmap/
		 * graymap. */
		if ( src->pixel_mode == FT_PIXEL_MODE_MONO ) {
			dst->pitch *= 8;
		} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
			dst->pitch *= 4;
		} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
			dst->pitch *= 2;
		}

		/* Adjust for bold and italic text */
		if( TTF_HANDLE_STYLE_BOLD(font) ) {
			int bump = font->glyph_overhang;
			dst->pitch += bump;
			dst->width += bump;
		}
		if( TTF_HANDLE_STYLE_ITALIC(font) ) {
			int bump = (int)ceil(font->glyph_italics);
			dst->pitch += bump;
			dst->width += bump;
		}

		if (dst->rows != 0) {
			dst->buffer = (unsigned char *)malloc( dst->pitch * dst->rows );
			if( !dst->buffer ) {
				return FT_Err_Out_Of_Memory;
			}
			memset( dst->buffer, 0, dst->pitch * dst->rows );

			for( i = 0; i < src->rows; i++ ) {
				int soffset = i * src->pitch;
				int doffset = i * dst->pitch;
				if ( mono ) {
					unsigned char *srcp = src->buffer + soffset;
					unsigned char *dstp = dst->buffer + doffset;
					int j;
					if ( src->pixel_mode == FT_PIXEL_MODE_MONO ) {
						for ( j = 0; j < src->width; j += 8 ) {
							unsigned char c = *srcp++;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
							c <<= 1;
							*dstp++ = (c&0x80) >> 7;
						}
					}  else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY2 ) {
						for ( j = 0; j < src->width; j += 4 ) {
							unsigned char c = *srcp++;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
							c <<= 2;
							*dstp++ = (((c&0xA0) >> 6) >= 0x2) ? 1 : 0;
						}
					} else if ( src->pixel_mode == FT_PIXEL_MODE_GRAY4 ) {
						for ( j = 0; j < src->width; j += 2 ) {
							unsigned char c = *srcp++;
							*dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
							c <<= 4;
							*dstp++ = (((c&0xF0) >> 4) >= 0x8) ? 1 : 0;
						}
					} else {
						for ( j = 0; j < src->width; j++ ) {
Example #18
0
bool KG3DFontTexture::InitGlyphBorder(UINT charCode, void* ftGlyph, KG3DTextureGlyph* fontGlyph)
{
	BOOL bRetCode = FALSE;
	FT_GlyphSlot pGlyphSlot = (FT_GlyphSlot)ftGlyph;
	FT_Error nError = 0;
	FT_Bitmap bitmap;
	FT_UInt nGlyph = 0;
    FT_F26Dot6 FontSize = 0;
    KG3DTextureGlyph* pGlyphFont = (KG3DTextureGlyph*)fontGlyph;

	ASSERT(pGlyphSlot);
	ASSERT(pGlyphFont);

	KGLOG_PROCESS_ERROR(pGlyphSlot);

	nGlyph = FT_Get_Char_Index(m_pFontFace, charCode);
	KGLOG_PROCESS_ERROR(nGlyph != 0);

    FontSize = FontFixMul(m_InitParams.fPixel);
    nError = FT_Set_Char_Size(m_pFontFace, FontSize, 0, 0, 0);
	KGLOG_PROCESS_ERROR(nError == 0);

	nError = FT_Load_Glyph(m_pFontFace, nGlyph, m_InitParams.dwLoadFlag);
	KGLOG_PROCESS_ERROR(nError == 0);

	nError = FT_Render_Glyph(pGlyphSlot, (FT_Render_Mode)m_InitParams.dwRenderMode);
	KGLOG_PROCESS_ERROR(nError == 0);
	KGLOG_PROCESS_ERROR(pGlyphSlot->format == FT_GLYPH_FORMAT_BITMAP);

	// request glyph texture
	pGlyphFont->nBoderTextureID = GetTextureIndex();
	KGLOG_PROCESS_ERROR(pGlyphFont->nBoderTextureID != KG3DFontRenderer::INVALID_TEXTURE_INDEX);

	// upload sub texture
	bitmap = pGlyphSlot->bitmap;

	pGlyphFont->vBorderU.x = (float)(m_uEmptyTextureX - 1) / (float)m_uTextureWidth;
	pGlyphFont->vBorderU.y = (float)(m_uEmptyTextureY - 1) / (float)m_uTextureHeight;

	pGlyphFont->vBorderV.x = (float)(m_uEmptyTextureX + bitmap.width + 1) / (float)m_uTextureWidth;
	pGlyphFont->vBorderV.y = (float)(m_uEmptyTextureY + bitmap.rows + 1) / (float)m_uTextureHeight;

	// empty glyph?
	// 如果轮廓线没有被上载,FreeType 使用的位图渲染模式为 1bit/pixel
	if (0 == pGlyphSlot->outline.n_contours && 0 == pGlyphSlot->outline.n_points || FT_PIXEL_MODE_MONO == bitmap.pixel_mode)
	{
		bRetCode = m_pRenderer->UploadMonoBoderTexture(pGlyphFont->nBoderTextureID, 0, m_uEmptyTextureX, m_uEmptyTextureY, 
			(UINT)pGlyphFont->cx,
			(UINT)pGlyphFont->cy,
			(UINT)bitmap.pitch,
			bitmap.buffer);
		KGLOG_PROCESS_ERROR(bRetCode);
	}
	else
	{
		bRetCode = m_pRenderer->UploadBoderTexture(pGlyphFont->nBoderTextureID, 0, m_uEmptyTextureX, m_uEmptyTextureY, 
			(UINT)pGlyphFont->cx,
			(UINT)pGlyphFont->cy, 
			bitmap.buffer, m_uchAdjustBuffer);
		KGLOG_PROCESS_ERROR(bRetCode);
	}

	m_uEmptyTextureX += static_cast<INT>( pGlyphFont->cx );
	m_uEmptyTextureX += KG3DFONT_DEFAULT_PADDING;

	return true;
Exit0:
	return false;
}
//-----------------------------------------------------------
ofTrueTypeFont::glyph ofTrueTypeFont::loadGlyph(uint32_t utf8) const{
	glyph aGlyph;
	auto err = FT_Load_Glyph( face.get(), FT_Get_Char_Index( face.get(), utf8 ), settings.antialiased ?  FT_LOAD_FORCE_AUTOHINT : FT_LOAD_DEFAULT );
	if(err){
		ofLogError("ofTrueTypeFont") << "loadFont(): FT_Load_Glyph failed for utf8 code " << utf8 << ": FT_Error " << err;
		return aGlyph;
	}

	if (settings.antialiased) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
	else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);


	// -------------------------
	// info about the character:
	aGlyph.props.glyph		= utf8;
	aGlyph.props.height 	= face->glyph->metrics.height>>6;
	aGlyph.props.width 		= face->glyph->metrics.width>>6;
	aGlyph.props.bearingX	= face->glyph->metrics.horiBearingX>>6;
	aGlyph.props.bearingY	= face->glyph->metrics.horiBearingY>>6;
	aGlyph.props.xmin		= face->glyph->bitmap_left;
	aGlyph.props.xmax		= aGlyph.props.xmin + aGlyph.props.width;
	aGlyph.props.ymin		= -face->glyph->bitmap_top;
	aGlyph.props.ymax		= aGlyph.props.ymin + aGlyph.props.height;
	aGlyph.props.advance	= face->glyph->metrics.horiAdvance>>6;
	aGlyph.props.tW			= aGlyph.props.width;
	aGlyph.props.tH			= aGlyph.props.height;

	FT_Bitmap& bitmap= face->glyph->bitmap;
	int width  = bitmap.width;
	int height = bitmap.rows;
	if(width==0 || height==0) return aGlyph;

	// Allocate Memory For The Texture Data.
	aGlyph.pixels.allocate(width, height, OF_PIXELS_GRAY_ALPHA);
	//-------------------------------- clear data:
	aGlyph.pixels.set(0,255); // every luminance pixel = 255
	aGlyph.pixels.set(1,0);


	if (settings.antialiased == true){
		ofPixels bitmapPixels;
		bitmapPixels.setFromExternalPixels(bitmap.buffer,bitmap.width,bitmap.rows,OF_PIXELS_GRAY);
		aGlyph.pixels.setChannel(1,bitmapPixels);
	} else {
		//-----------------------------------
		// true type packs monochrome info in a
		// 1-bit format, hella funky
		// here we unpack it:
		unsigned char *src =  bitmap.buffer;
		for(unsigned int j=0; j <bitmap.rows;j++) {
			unsigned char b=0;
			unsigned char *bptr =  src;
			for(unsigned int k=0; k < bitmap.width ; k++){
				aGlyph.pixels[2*(k+j*width)] = 255;

				if (k%8==0){
					b = (*bptr++);
				}

				aGlyph.pixels[2*(k+j*width) + 1] = b&0x80 ? 255 : 0;
				b <<= 1;
			}
			src += bitmap.pitch;
		}
		//-----------------------------------
	}

	return aGlyph;
}
fz_pixmap *
fz_renderftglyph(fz_font *font, int gid, fz_matrix trm)
{
	FT_Face face = font->ftface;
	FT_Matrix m;
	FT_Vector v;
	FT_Error fterr;
	fz_pixmap *glyph;
	int y;

	/* Fudge the font matrix to stretch the glyph if we've substituted the font. */
	if (font->ftsubstitute && gid < font->widthcount)
	{
		int subw;
		int realw;
		float scale;

		/* TODO: use FT_Get_Advance */
		fterr = FT_Set_Char_Size(face, 1000, 1000, 72, 72);
		if (fterr)
			fz_warn("freetype setting character size: %s", ft_errorstring(fterr));

		fterr = FT_Load_Glyph(font->ftface, gid,
			FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP | FT_LOAD_IGNORE_TRANSFORM);
		if (fterr)
			fz_warn("freetype failed to load glyph: %s", ft_errorstring(fterr));

		realw = ((FT_Face)font->ftface)->glyph->metrics.horiAdvance;
		subw = font->widthtable[gid];
		if (realw)
			scale = (float) subw / realw;
		else
			scale = 1;

		trm = fz_concat(fz_scale(scale, 1), trm);
	}

	/*
	Freetype mutilates complex glyphs if they are loaded
	with FT_Set_Char_Size 1.0. it rounds the coordinates
	before applying transformation. to get more precision in
	freetype, we shift part of the scale in the matrix
	into FT_Set_Char_Size instead
	*/

	m.xx = trm.a * 64; /* should be 65536 */
	m.yx = trm.b * 64;
	m.xy = trm.c * 64;
	m.yy = trm.d * 64;
	v.x = trm.e * 64;
	v.y = trm.f * 64;

	fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
	if (fterr)
		fz_warn("freetype setting character size: %s", ft_errorstring(fterr));
	FT_Set_Transform(face, &m, &v);

	if (font->fthint)
	{
		/*
		Enable hinting, but keep the huge char size so that
		it is hinted for a character. This will in effect nullify
		the effect of grid fitting. This form of hinting should
		only be used for DynaLab and similar tricky TrueType fonts,
		so that we get the correct outline shape.
		*/
#ifdef GRIDFIT
		/* If you really want grid fitting, enable this code. */
		float scale = fz_matrixexpansion(trm);
		m.xx = trm.a * 65536 / scale;
		m.xy = trm.b * 65536 / scale;
		m.yx = trm.c * 65536 / scale;
		m.yy = trm.d * 65536 / scale;
		v.x = 0;
		v.y = 0;

		fterr = FT_Set_Char_Size(face, 64 * scale, 64 * scale, 72, 72);
		if (fterr)
			fz_warn("freetype setting character size: %s", ft_errorstring(fterr));
		FT_Set_Transform(face, &m, &v);
#endif
		fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP);
		if (fterr)
			fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr));
	}
	else
	{
		fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
		if (fterr)
		{
			fz_warn("freetype load glyph (gid %d): %s", gid, ft_errorstring(fterr));
			return nil;
		}
	}

	fterr = FT_Render_Glyph(face->glyph, ft_render_mode_normal);
	if (fterr)
	{
		fz_warn("freetype render glyph (gid %d): %s", gid, ft_errorstring(fterr));
		return nil;
	}

	glyph = fz_newpixmap(NULL,
		face->glyph->bitmap_left,
		face->glyph->bitmap_top - face->glyph->bitmap.rows,
		face->glyph->bitmap.width,
		face->glyph->bitmap.rows);

	for (y = 0; y < glyph->h; y++)
	{
		memcpy(glyph->samples + y * glyph->w,
			face->glyph->bitmap.buffer + (glyph->h - y - 1) * face->glyph->bitmap.pitch,
			glyph->w);
	}

	return glyph;
}
Example #21
0
//------------------------------------------------------------------
void urFont::loadFont(string filename, int fontsize, bool _bAntiAliased, bool _bFullCharacterSet, bool makeContours){
	
	
	
	bMakeContours = makeContours;

	//------------------------------------------------
	if (bLoadedOk == true){

		// we've already been loaded, try to clean up :

		if (cps != NULL){
			delete[] cps;
		}
		if (texNames != NULL){
			for (int i = 0; i < nCharacters; i++){
				glDeleteTextures(1, &texNames[i]);
			}
			delete[] texNames;
		}
		bLoadedOk = false;
	}
	//------------------------------------------------


	filename = ofToDataPath(filename);

	bLoadedOk 			= false;
	bAntiAlised 		= _bAntiAliased;
	bFullCharacterSet 	= _bFullCharacterSet;
	fontSize			= fontsize;

	//--------------- load the library and typeface
	FT_Library library;
	if (FT_Init_FreeType( &library )){
		//		ofLog(OF_LOG_ERROR," PROBLEM WITH FT lib");
		return;
	}

	FT_Face face;
	if (FT_New_Face( library, filename.c_str(), 0, &face )) {
		return;
	}

	FT_Set_Char_Size( face, fontsize << 6, fontsize << 6, 96, 96);
	lineHeight = fontsize * 1.43f;

	//------------------------------------------------------
	//kerning would be great to support:
	//ofLog(OF_LOG_NOTICE,"FT_HAS_KERNING ? %i", FT_HAS_KERNING(face));
	//------------------------------------------------------

	nCharacters = bFullCharacterSet ? 256 : 128 - NUM_CHARACTER_TO_START;

	//--------------- initialize character info and textures
	cps       = new charProps[nCharacters];
	texNames  = new GLuint[nCharacters];
	glGenTextures(nCharacters, texNames);

	if(bMakeContours){
		charOutlines.clear();
		charOutlines.assign(nCharacters, ofTTFCharacter());
	}
	//--------------------- load each char -----------------------
	for (int i = 0 ; i < nCharacters; i++){

		//------------------------------------------ anti aliased or not:
		if(FT_Load_Glyph( face, FT_Get_Char_Index( face, (unsigned char)(i+NUM_CHARACTER_TO_START) ), FT_LOAD_DEFAULT )){
			//			ofLog(OF_LOG_ERROR,"error with FT_Load_Glyph %i", i);
		}

		if (bAntiAlised == true) FT_Render_Glyph(face->glyph, FT_RENDER_MODE_NORMAL);
		else FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO);

		//------------------------------------------
		FT_Bitmap& bitmap= face->glyph->bitmap;

		// 3 pixel border around the glyph
		// We show 2 pixels of this, so that blending looks good.
		// 1 pixels is hidden because we don't want to see the real edge of the texture

		border			= 3;
		visibleBorder	= 2;

		if(bMakeContours){
			if( printVectorInfo )printf("\n\ncharacter %c: \n", char( i+NUM_CHARACTER_TO_START ) );

			//int character = i + NUM_CHARACTER_TO_START;
			charOutlines[i] = makeContoursForCharacter( face );
		}

		// prepare the texture:
		int width  = ofNextPow2( bitmap.width + border*2 );
		int height = ofNextPow2( bitmap.rows  + border*2 );


		// ------------------------- this is fixing a bug with small type
		// ------------------------- appearantly, opengl has trouble with
		// ------------------------- width or height textures of 1, so we
		// ------------------------- we just set it to 2...
		if (width == 1) width = 2;
		if (height == 1) height = 2;

		// -------------------------
		// info about the character:
		cps[i].value 			= i;
		cps[i].height 			= face->glyph->bitmap_top;
		cps[i].width 			= face->glyph->bitmap.width;
		cps[i].setWidth 		= face->glyph->advance.x >> 6;
		cps[i].topExtent 		= face->glyph->bitmap.rows;
		cps[i].leftExtent		= face->glyph->bitmap_left;

		// texture internals
		cps[i].tTex             = (float)(bitmap.width + visibleBorder*2)  /  (float)width;
		cps[i].vTex             = (float)(bitmap.rows +  visibleBorder*2)   /  (float)height;

		cps[i].xOff             = (float)(border - visibleBorder) / (float)width;
		cps[i].yOff             = (float)(border - visibleBorder) / (float)height;


		/* sanity check:
		ofLog(OF_LOG_NOTICE,"%i %i %i %i %i %i",
		cps[i].value ,
		cps[i].height ,
		cps[i].width 	,
		cps[i].setWidth 	,
		cps[i].topExtent ,
		cps[i].leftExtent	);
		*/


		// Allocate Memory For The Texture Data.
		unsigned char* expanded_data = new unsigned char[ 2 * width * height];

		//-------------------------------- clear data:
		for(int j=0; j <height;j++) {
			for(int k=0; k < width; k++){
				expanded_data[2*(k+j*width)  ] = 255;   // every luminance pixel = 255
				expanded_data[2*(k+j*width)+1] = 0;
			}
		}


		if (bAntiAlised == true){
			//-----------------------------------
			for(int j=0; j <height; j++) {
				for(int k=0; k < width; k++){
					if ((k<bitmap.width) && (j<bitmap.rows)){
						expanded_data[2*((k+border)+(j+border)*width)+1] = bitmap.buffer[k + bitmap.width*(j)];
					}
				}
			}
			//-----------------------------------
		} else {
			//-----------------------------------
			// true type packs monochrome info in a
			// 1-bit format, hella funky
			// here we unpack it:
			unsigned char *src =  bitmap.buffer;
			for(int j=0; j <bitmap.rows;j++) {
				unsigned char b=0;
				unsigned char *bptr =  src;
				for(int k=0; k < bitmap.width ; k++){
					expanded_data[2*((k+1)+(j+1)*width)] = 255;
					if (k%8==0){ b = (*bptr++);}
					expanded_data[2*((k+1)+(j+1)*width) + 1] =
						b&0x80 ? 255 : 0;
					b <<= 1;
				}
				src += bitmap.pitch;
			}
			//-----------------------------------
		}


		//Now we just setup some texture paramaters.
		glBindTexture( GL_TEXTURE_2D, texNames[i]);
#if (!defined TARGET_OF_IPHONE) && (!defined TARGET_ANDROID)
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
		glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
#endif
		if (bAntiAlised == true){
			glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
			glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
		} else {
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
			glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
		}
		glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

		//Here we actually create the texture itself, notice
		//that we are using GL_LUMINANCE_ALPHA to indicate that
		//we are using 2 channel data.

#if (!defined TARGET_OF_IPHONE) && (!defined TARGET_ANDROID) // gluBuild2DMipmaps doesn't seem to exist in anything i had in the iphone build... so i commented it out
		bool b_use_mipmaps = false;  // FOR now this is fixed to false, could be an option, left in for legacy...
		if (b_use_mipmaps){
			gluBuild2DMipmaps(
				GL_TEXTURE_2D, GL_LUMINANCE_ALPHA, width, height,
				GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data);
		} else
#endif
		{
			glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, width, height,
				0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );
		}


		//With the texture created, we don't need to expanded data anymore

		delete [] expanded_data;

	}

	// ------------- close the library and typeface
	FT_Done_Face(face);
	FT_Done_FreeType(library);
	bLoadedOk = true;
}
fz_pixmap *
fz_renderftstrokedglyph(fz_font *font, int gid, fz_matrix trm, fz_matrix ctm, fz_strokestate *state)
{
	FT_Face face = font->ftface;
	float expansion = fz_matrixexpansion(ctm);
	int linewidth = state->linewidth * expansion * 64 / 2;
	FT_Matrix m;
	FT_Vector v;
	FT_Error fterr;
	FT_Stroker stroker;
	FT_Glyph glyph;
	FT_BitmapGlyph bitmap;
	fz_pixmap *pix;
	int y;

	m.xx = trm.a * 64; /* should be 65536 */
	m.yx = trm.b * 64;
	m.xy = trm.c * 64;
	m.yy = trm.d * 64;
	v.x = trm.e * 64;
	v.y = trm.f * 64;

	fterr = FT_Set_Char_Size(face, 65536, 65536, 72, 72); /* should be 64, 64 */
	if (fterr)
	{
		fz_warn("FT_Set_Char_Size: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Set_Transform(face, &m, &v);

	fterr = FT_Load_Glyph(face, gid, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING);
	if (fterr)
	{
		fz_warn("FT_Load_Glyph(gid %d): %s", gid, ft_errorstring(fterr));
		return nil;
	}

	fterr = FT_Stroker_New(fz_ftlib, &stroker);
	if (fterr)
	{
		fz_warn("FT_Stroker_New: %s", ft_errorstring(fterr));
		return nil;
	}

	FT_Stroker_Set(stroker, linewidth, state->linecap, state->linejoin, state->miterlimit * 65536);

	fterr = FT_Get_Glyph(face->glyph, &glyph);
	if (fterr)
	{
		fz_warn("FT_Get_Glyph: %s", ft_errorstring(fterr));
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_Stroke(&glyph, stroker, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_Stroke: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	fterr = FT_Glyph_To_Bitmap(&glyph, FT_RENDER_MODE_NORMAL, 0, 1);
	if (fterr)
	{
		fz_warn("FT_Glyph_To_Bitmap: %s", ft_errorstring(fterr));
		FT_Done_Glyph(glyph);
		FT_Stroker_Done(stroker);
		return nil;
	}

	bitmap = (FT_BitmapGlyph)glyph;
	pix = fz_newpixmap(NULL,
		bitmap->left,
		bitmap->top - bitmap->bitmap.rows,
		bitmap->bitmap.width,
		bitmap->bitmap.rows);

	for (y = 0; y < pix->h; y++)
	{
		memcpy(pix->samples + y * pix->w,
			bitmap->bitmap.buffer + (pix->h - y - 1) * bitmap->bitmap.pitch,
			pix->w);
	}

	FT_Done_Glyph(glyph);
	FT_Stroker_Done(stroker);

	return pix;
}
Example #23
0
///Create a display list coresponding to the give character.
void make_dlist ( FT_Face face, char ch, GLuint list_base, GLuint * tex_base ) {

	//The first thing we do is get FreeType to render our character
	//into a bitmap.  This actually requires a couple of FreeType commands:

	//Load the Glyph for our character.
	if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_DEFAULT ))
		throw std::runtime_error("FT_Load_Glyph failed");

	//Move the face's glyph into a Glyph object.
    FT_Glyph glyph;
    if(FT_Get_Glyph( face->glyph, &glyph ))
		throw std::runtime_error("FT_Get_Glyph failed");

	//Convert the glyph to a bitmap.
	FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 );
    FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

	//This reference will make accessing the bitmap easier
	FT_Bitmap& bitmap=bitmap_glyph->bitmap;

	//Use our helper function to get the widths of
	//the bitmap data that we will need in order to create
	//our texture.
	int width = next_p2( bitmap.width );
	int height = next_p2( bitmap.rows );

	//Allocate memory for the texture data.
	GLubyte* expanded_data = new GLubyte[ 2 * width * height];

	//Here we fill in the data for the expanded bitmap.
	//Notice that we are using two channel bitmap (one for
	//luminocity and one for alpha), but we assign
	//both luminocity and alpha to the value that we
	//find in the FreeType bitmap. 
	//We use the ?: operator so that value which we use
	//will be 0 if we are in the padding zone, and whatever
	//is the the Freetype bitmap otherwise.
	for(int j=0; j <height;j++) {
		for(int i=0; i < width; i++){
			expanded_data[2*(i+j*width)]= expanded_data[2*(i+j*width)+1] = 
				(i>=bitmap.width || j>=bitmap.rows) ?
				0 : bitmap.buffer[i + bitmap.width*j];
		}
	}


	//Now we just setup some texture paramaters.
    glBindTexture( GL_TEXTURE_2D, tex_base[ch]);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);

	//Here we actually create the texture itself, notice
	//that we are using GL_LUMINANCE_ALPHA to indicate that
	//we are using 2 channel data.
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height,
		  0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data );

	//With the texture created, we don't need to expanded data anymore
    delete [] expanded_data;

	//So now we can create the display list
	glNewList(list_base+ch,GL_COMPILE);

	glBindTexture(GL_TEXTURE_2D,tex_base[ch]);

	//first we need to move over a little so that
	//the character has the right amount of space
	//between it and the one before it.
	glTranslatef(bitmap_glyph->left,0,0);

	//Now we move down a little in the case that the
	//bitmap extends past the bottom of the line 
	//(this is only true for characters like 'g' or 'y'.
	glPushMatrix();
	glTranslatef(0,bitmap_glyph->top-bitmap.rows,0);

	//Now we need to account for the fact that many of
	//our textures are filled with empty padding space.
	//We figure what portion of the texture is used by 
	//the actual character and store that information in 
	//the x and y variables, then when we draw the
	//quad, we will only reference the parts of the texture
	//that we contain the character itself.
	float	x=(float)bitmap.width / (float)width,
			y=(float)bitmap.rows / (float)height;

	//Here we draw the texturemaped quads.
	//The bitmap that we got from FreeType was not 
	//oriented quite like we would like it to be,
	//so we need to link the texture to the quad
	//so that the result will be properly aligned.
	glBegin(GL_QUADS);
	glTexCoord2d(0,0); glVertex2f(0,bitmap.rows);
	glTexCoord2d(0,y); glVertex2f(0,0);
	glTexCoord2d(x,y); glVertex2f(bitmap.width,0);
	glTexCoord2d(x,0); glVertex2f(bitmap.width,bitmap.rows);
	glEnd();
	glPopMatrix();
	glTranslatef(face->glyph->advance.x >> 6 ,0,0);


	//increment the raster position as if we were a bitmap font.
	//(only needed if you want to calculate text length)
	//glBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL);

	//Finnish the display list
	glEndList();
}
Example #24
0
PixelSize
Font::TextSize(const TCHAR *text) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  const FT_Face face = this->face;
#ifdef USE_KERNING
  const bool use_kerning = FT_HAS_KERNING(face);
  unsigned prev_index = 0;
#endif

  int x = 0;
#ifdef FIX_HINTING
  FT_Pos prev_rsb_delta=0;
#endif

#ifndef ENABLE_OPENGL
  const Poco::ScopedLock<Poco::Mutex> protect(freetype_mutex);
#endif

  while (true) {
    const auto n = NextChar(text);
    if (n.first == 0)
      break;

    const unsigned ch = n.first;
    text = n.second;

    FT_UInt i = FT_Get_Char_Index(face, ch);
    if (i == 0)
      continue;

    FT_Error error = FT_Load_Glyph(face, i, load_flags);
    if (error)
      continue;

    const FT_GlyphSlot glyph = face->glyph;
    #if (defined LIGHT_KERNING) || !(defined USE_KERNING)
    const FT_Glyph_Metrics metrics = glyph->metrics;
    #endif

#ifdef USE_KERNING
    if (use_kerning && x) {
      if (prev_index != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default, &delta);
        #ifdef LIGHT_KERNING
        if (-delta.x <= metrics.horiBearingX)
            x += delta.x ;
        else
            x -= (metrics.horiBearingX +64);
        #else
        x += delta.x ;
        #endif
      }
    }
    prev_index = i;
#endif


#ifdef FIX_HINTING
    if (prev_rsb_delta - glyph->lsb_delta >= 32 )
        x -= 64;
    else if ( prev_rsb_delta - glyph->lsb_delta < -32 )
        x += 64;

    prev_rsb_delta = glyph->rsb_delta;
#endif


#ifdef USE_KERNING
    x += glyph->advance.x;
#else
    x += (metrics.width > metrics.horiAdvance ? metrics.width : metrics.horiAdvance);
#endif


  }

  return PixelSize{unsigned(std::max(0, x >> 6 )), height};
}
Example #25
0
// ------------------------------------------------------------------- main ---
int main( int argc, char **argv )
{
    size_t i, j;
    int ptSize = 50*64;
    int device_hdpi = 72;
    int device_vdpi = 72;


    glutInit( &argc, argv );
    glutInitWindowSize( 512, 512 );
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
    glutCreateWindow( argv[0] );
    glutReshapeFunc( reshape );
    glutDisplayFunc( display );
    glutKeyboardFunc( keyboard );

#ifndef __APPLE__
    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if (GLEW_OK != err)
    {
        /* Problem: glewInit failed, something is seriously wrong. */
        fprintf( stderr, "Error: %s\n", glewGetErrorString(err) );
        exit( EXIT_FAILURE );
    }
    fprintf( stderr, "Using GLEW %s\n", glewGetString(GLEW_VERSION) );
#endif

    texture_atlas_t * atlas = texture_atlas_new( 512, 512, 3 );


    /* Init freetype */
    FT_Library ft_library;
    assert(!FT_Init_FreeType(&ft_library));

    /* Load our fonts */
    FT_Face ft_face[NUM_EXAMPLES];
    assert(!FT_New_Face( ft_library, fonts[ENGLISH], 0, &ft_face[ENGLISH]) );
    assert(!FT_Set_Char_Size( ft_face[ENGLISH], 0, ptSize, device_hdpi, device_vdpi ) );
    // ftfdump( ft_face[ENGLISH] );            // wonderful world of encodings ...
    force_ucs2_charmap( ft_face[ENGLISH] ); // which we ignore.

    assert( !FT_New_Face(ft_library, fonts[ARABIC], 0, &ft_face[ARABIC]) );
    assert( !FT_Set_Char_Size(ft_face[ARABIC], 0, ptSize, device_hdpi, device_vdpi ) );
    // ftfdump( ft_face[ARABIC] );
    force_ucs2_charmap( ft_face[ARABIC] );

    assert(!FT_New_Face( ft_library, fonts[CHINESE], 0, &ft_face[CHINESE]) );
    assert(!FT_Set_Char_Size( ft_face[CHINESE], 0, ptSize, device_hdpi, device_vdpi ) );
    // ftfdump( ft_face[CHINESE] );
    force_ucs2_charmap( ft_face[CHINESE] );

    /* Get our harfbuzz font structs */
    hb_font_t *hb_ft_font[NUM_EXAMPLES];
    hb_ft_font[ENGLISH] = hb_ft_font_create( ft_face[ENGLISH], NULL );
    hb_ft_font[ARABIC]  = hb_ft_font_create( ft_face[ARABIC] , NULL );
    hb_ft_font[CHINESE] = hb_ft_font_create( ft_face[CHINESE], NULL );

    /* Create a buffer for harfbuzz to use */
    hb_buffer_t *buf = hb_buffer_create();

    for (i=0; i < NUM_EXAMPLES; ++i)
    {
        hb_buffer_set_direction( buf, text_directions[i] ); /* or LTR */
        hb_buffer_set_script( buf, scripts[i] ); /* see hb-unicode.h */
        hb_buffer_set_language( buf,
                                hb_language_from_string(languages[i], strlen(languages[i])) );

        /* Layout the text */
        hb_buffer_add_utf8( buf, texts[i], strlen(texts[i]), 0, strlen(texts[i]) );
        hb_shape( hb_ft_font[i], buf, NULL, 0 );

        unsigned int         glyph_count;
        hb_glyph_info_t     *glyph_info   = hb_buffer_get_glyph_infos(buf, &glyph_count);
        hb_glyph_position_t *glyph_pos    = hb_buffer_get_glyph_positions(buf, &glyph_count);


        FT_GlyphSlot slot;
        FT_Bitmap ft_bitmap;
        float size = 24;
        size_t hres = 64;
        FT_Error error;
        FT_Int32 flags = 0;
        flags |= FT_LOAD_RENDER;
        flags |= FT_LOAD_TARGET_LCD;
        FT_Library_SetLcdFilter( ft_library, FT_LCD_FILTER_LIGHT );
        FT_Matrix matrix = { (int)((1.0/hres) * 0x10000L),
                             (int)((0.0)      * 0x10000L),
                             (int)((0.0)      * 0x10000L),
                             (int)((1.0)      * 0x10000L) };
        /* Set char size */
        error = FT_Set_Char_Size( ft_face[i], (int)(ptSize), 0, 72*hres, 72 );
        if( error )
        {
            //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n",
            //         __LINE__, FT_Errors[error].code, FT_Errors[error].message );
            FT_Done_Face( ft_face[i] );
            break;
        }

        /* Set transform matrix */
        FT_Set_Transform( ft_face[i], &matrix, NULL );

        for (j = 0; j < glyph_count; ++j)
        {
            /* Load glyph */
            error = FT_Load_Glyph( ft_face[i], glyph_info[j].codepoint, flags );
            if( error )
            {
                //fprintf( stderr, "FT_Error (line %d, code 0x%02x) : %s\n",
                //         __LINE__, FT_Errors[error].code, FT_Errors[error].message );
                FT_Done_Face( ft_face[i] );
                break;
            }

            slot = ft_face[i]->glyph;
            ft_bitmap = slot->bitmap;
            int ft_bitmap_width = slot->bitmap.width;
            int ft_bitmap_rows  = slot->bitmap.rows;
            int ft_bitmap_pitch = slot->bitmap.pitch;
            int ft_glyph_top    = slot->bitmap_top;
            int ft_glyph_left   = slot->bitmap_left;

            int w = ft_bitmap_width/3; // 3 because of LCD/RGB encoding
            int h = ft_bitmap_rows;

            ivec4 region = texture_atlas_get_region( atlas, w+1, h+1 );
            if ( region.x < 0 )
            {
                fprintf( stderr, "Texture atlas is full (line %d)\n",  __LINE__ );
                continue;
            }
            int x = region.x, y = region.y;
            texture_atlas_set_region( atlas, region.x, region.y,
                                      w, h, ft_bitmap.buffer, ft_bitmap.pitch );
            printf("%d: %dx%d %f %f\n",
                   glyph_info[j].codepoint,
                   ft_bitmap_width,
                   ft_bitmap_rows,
                   glyph_pos[j].x_advance/64.,
                   glyph_pos[j].y_advance/64.);
        }

        /* clean up the buffer, but don't kill it just yet */
        hb_buffer_reset(buf);
    }


    /* Cleanup */
    hb_buffer_destroy( buf );
    for( i=0; i < NUM_EXAMPLES; ++i )
        hb_font_destroy( hb_ft_font[i] );
    FT_Done_FreeType( ft_library );

    glClearColor(1,1,1,1);
    glEnable( GL_BLEND );
    glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    glEnable( GL_TEXTURE_2D );

    glBindTexture( GL_TEXTURE_2D, atlas->id );
    texture_atlas_upload( atlas );

    typedef struct { float x,y,z, u,v, r,g,b,a, shift, gamma; } vertex_t;
    vertex_t vertices[4] =  {
        {  0,  0,0, 0,1, 0,0,0,1, 0, 1},
        {  0,512,0, 0,0, 0,0,0,1, 0, 1},
        {512,512,0, 1,0, 0,0,0,1, 0, 1},
        {512,  0,0, 1,1, 0,0,0,1, 0, 1} };
    GLuint indices[6] = { 0, 1, 2, 0,2,3 };
    buffer = vertex_buffer_new( "vertex:3f,"
                                "tex_coord:2f,"
                                "color:4f,"
                                "ashift:1f,"
                                "agamma:1f" );






    vertex_buffer_push_back( buffer, vertices, 4, indices, 6 );
    shader = shader_load("shaders/text.vert", "shaders/text.frag");
    mat4_set_identity( &projection );
    mat4_set_identity( &model );
    mat4_set_identity( &view );
    glutMainLoop( );
    return 0;
}
Example #26
0
//
// 2015-04-18  note by Paolo
//
// The original code from xcsoar was not spacing characters correctly in LK.
// I have no idea if the problem exists in xcsoar, but we had to fix it here.
// After quite some time, and frustration reading the confusing docs of FreeType,
// I came to this solution which is much more accurate.
// We use subpixels assuming we are always grid-aligned, which is true for our case.
// Kerning does work, but we must always check that we are not going below the 
// available space, to avoid overlapping previous glyph. This is necessary since
// the bitmap operations are copying, not merging, bitmaps. I have no idea how 
// Windows is doing this, apparently microsoft does not merge glyphs too.
// Hinting is required to keep vertical alignement, which may hide a bug.
// I am not sure if all of this (long and complicated) work is correct or it is instead
// a workaround for a more complex problem existing elsewhere.
// However it does work for us, against all odds.
// Update april 21st: merging instead of copying makes the kerning process working fine.
//
void
Font::Render(const TCHAR *text, const PixelSize size, void *_buffer) const
{
  assert(text != nullptr);
#ifndef _UNICODE
  assert(ValidateUTF8(text));
#endif

  uint8_t *buffer = (uint8_t *)_buffer;
  std::fill_n(buffer, BufferSize(size), 0);

  const FT_Face face = this->face;
  const FT_GlyphSlot glyph = face->glyph;

#ifdef USE_KERNING
  bool use_kerning = FT_HAS_KERNING(face);
  unsigned prev_index = 0;
#endif

  int x = 0;
#ifdef FIX_HINTING
  FT_Pos prev_rsb_delta=0;
#endif


#ifndef ENABLE_OPENGL
  const Poco::ScopedLock<Poco::Mutex> protect(freetype_mutex);
#endif


  while (true) {
    const auto n = NextChar(text);
    if (n.first == 0)
      break;

    const unsigned ch = n.first;
    text = n.second;

    FT_UInt i = FT_Get_Char_Index(face, ch);
    if (i == 0)
      continue;

    FT_Error error = FT_Load_Glyph(face, i, load_flags);
    if (error)
      continue;

    const FT_Glyph_Metrics metrics = glyph->metrics;

#ifdef USE_KERNING
    if (use_kerning && x) {
      if (prev_index != 0) {
        FT_Vector delta;
        FT_Get_Kerning(face, prev_index, i, ft_kerning_default, &delta);
        #ifdef LIGHT_KERNING
        if (-delta.x <= metrics.horiBearingX)
            x += delta.x ;
        else
            x -= (metrics.horiBearingX + 64);
        #else
            x += delta.x;
        #endif
      }
    }
    prev_index = i;
#endif


#ifdef FIX_HINTING
    if (prev_rsb_delta - glyph->lsb_delta >= 32 )
        x -= 64;// >> 6;
    else if ( prev_rsb_delta - glyph->lsb_delta < -32 )
        x += 64;// >> 6;

    prev_rsb_delta = glyph->rsb_delta;
#endif

    error = FT_Render_Glyph(glyph, render_mode);
    if (error)
      continue;
    /* 
     *  32,  0  = Microsoft GDI weight=600 (64=32)
     */
    if (demibold) FT_Bitmap_Embolden(ft_library,&glyph->bitmap, 32,0);

    RenderGlyph((uint8_t *)buffer, size.cx, size.cy,
#ifdef USE_KERNING
        glyph, (x >> 6)+glyph->bitmap_left , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += glyph->advance.x; // equivalent to metrics.horiAdvance
#else
        glyph, (x + metrics.horiBearingX ) >> 6 , ascent_height - FT_FLOOR(metrics.horiBearingY));

    x += (metrics.width > metrics.horiAdvance ? metrics.width : metrics.horiAdvance);
#endif

  }
}
Example #27
0
static GF_Glyph *ft_load_glyph(GF_FontReader *dr, u32 glyph_name)
{
	GF_Glyph *glyph;
	u32 glyph_idx;
	FT_BBox bbox;
	FT_OutlineGlyph outline;
	ft_outliner outl;
	FT_Outline_Funcs ft_outl_funcs;

	FTBuilder *ftpriv = (FTBuilder *)dr->udta;
	if (!ftpriv->active_face || !glyph_name) return NULL;

	FT_Select_Charmap(ftpriv->active_face, FT_ENCODING_UNICODE);

	glyph_idx = FT_Get_Char_Index(ftpriv->active_face, glyph_name);
	/*missing glyph*/
	if (!glyph_idx) {
		GF_LOG(GF_LOG_WARNING, GF_LOG_PARSER, ("[FreeType] Glyph not found for char %d in font %s (style %s)\n", glyph_name, ftpriv->active_face->family_name, ftpriv->active_face->style_name));
		return NULL;
	}

	/*work in design units*/
	FT_Load_Glyph(ftpriv->active_face, glyph_idx, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP);

	FT_Get_Glyph(ftpriv->active_face->glyph, (FT_Glyph*)&outline);

#ifdef FT_GLYPH_FORMAT_OUTLINE
	/*oops not vectorial...*/
	if (outline->root.format != FT_GLYPH_FORMAT_OUTLINE) return NULL;
#endif


	GF_SAFEALLOC(glyph, GF_Glyph);
	if (!glyph) return NULL;
	GF_SAFEALLOC(glyph->path, GF_Path);
	if (!glyph->path) {
		gf_free(glyph);
		return NULL;
	}
	/*setup outliner*/
	ft_outl_funcs.shift = 0;
	ft_outl_funcs.delta = 0;
	ft_outl_funcs.move_to = ft_move_to;
	ft_outl_funcs.line_to = ft_line_to;
	ft_outl_funcs.conic_to = ft_conic_to;
	ft_outl_funcs.cubic_to = ft_cubic_to;
	outl.path = glyph->path;
	outl.ftpriv = ftpriv;

	/*FreeType is marvelous and gives back the right advance on space char !!!*/
	FT_Outline_Decompose(&outline->outline, &ft_outl_funcs, &outl);

	FT_Glyph_Get_CBox((FT_Glyph) outline, ft_glyph_bbox_unscaled, &bbox);

	glyph->ID = glyph_name;
	glyph->utf_name = glyph_name;
	glyph->horiz_advance = (s32) ftpriv->active_face->glyph->metrics.horiAdvance;
	glyph->vert_advance = (s32) ftpriv->active_face->glyph->metrics.vertAdvance;
	/*
		glyph->x = bbox.xMin;
		glyph->y = bbox.yMax;
	*/
	glyph->width = (u32) ftpriv->active_face->glyph->metrics.width;
	glyph->height = (u32) ftpriv->active_face->glyph->metrics.height;
	FT_Done_Glyph((FT_Glyph) outline);
	return glyph;
}
Example #28
0
bool CFontConverter::ToOTF(std::wstring sFontIn, std::wstring sFontOut, unsigned int* pSymbols, int nCount, std::wstring sNameW, long nFlag)
{
    FT_Library pLibrary = NULL;
    if ( FT_Init_FreeType( &pLibrary ) )
        return false;

    FT_Face pFace = NULL;

    NSFile::CFileBinary oFileBinary;
    if (!oFileBinary.OpenFile(sFontIn))
        return false;

    FT_Long nFileSize = (FT_Long)oFileBinary.GetFileSize();
    BYTE* pBaseAddress = new BYTE[nFileSize];
    DWORD dwRead = 0;
    oFileBinary.ReadFile(pBaseAddress, (DWORD)nFileSize, dwRead);

    FT_Open_Args oOpenArgs;
    oOpenArgs.flags = FT_OPEN_MEMORY;
    oOpenArgs.memory_base = (BYTE*)pBaseAddress;
    oOpenArgs.memory_size = nFileSize;

    NSFontConverter::CFontFileTrueType* pTTF = NSFontConverter::CFontFileTrueType::LoadFromFile( sFontIn.c_str() );
    FT_Error oerrr;
    if ( oerrr = FT_Open_Face( pLibrary, &oOpenArgs, 0, &pFace ) )
    {
        FT_Done_FreeType( pLibrary );
        RELEASEARRAYOBJECTS(pBaseAddress);
        return false;
    }

    std::string sFontFormat( FT_Get_X11_Font_Format( pFace ) );

    // Проверим флаг конвертации и исходный формат шрифта
    bool bNeedConvert = false;

    if ( nFlag == NSFontConverter::c_lFromAll ||
         ( "TrueType" == sFontFormat && nFlag & NSFontConverter::c_lFromTT ) ||
         ( "CFF" == sFontFormat && nFlag & NSFontConverter::c_lFromCFF ) ||
         ( "Type 1" == sFontFormat && nFlag & NSFontConverter::c_lFromT1 ) )
        bNeedConvert = true;

    bool bIsGids = (NSFontConverter::c_lFlagsGids & nFlag);

    if ( bNeedConvert )
    {
        if ( "CFF" == sFontFormat || "Type 1" == sFontFormat )
        {
            NSFontConverter::TCharBuffer oCFF;
            NSFontConverter::CFontFileType1C *pT1C = NULL;
            if ( "Type 1" == sFontFormat )
            {
                // Сначала сконвертируем Type1 в CFF
                NSFontConverter::CFontFileType1* pT1 = NSFontConverter::CFontFileType1::LoadFromFile( sFontIn.c_str() );
                pT1->ToCFF( &NSFontConverter::CharBufferWrite, &oCFF );
                delete pT1;

                // Конвертируем CFF в OpenTypeCFF
                pT1C = NSFontConverter::CFontFileType1C::LoadFromBuffer( oCFF.sBuffer, oCFF.nLen );
            }
            else
            {
                // FreeType отдает тип шрифта CFF, в случаях когда файл имеет тип OpenType(CFF).
                // Если так оно и есть, тогда нам с файлом ничего делать на надо.
                pT1C = NSFontConverter::CFontFileType1C::LoadFromFile( sFontIn.c_str() );
            }

            if ( pT1C )
            {
                NSFile::CFileBinary oWriteFile;
                oWriteFile.CreateFileW(sFontOut);
                pT1C->ToOpenTypeCFF( &NSFontConverter::FileWrite, oWriteFile.GetFileNative(), pFace );
                oWriteFile.CloseFile();
            }

            delete pT1C;
        }
        else if ( "TrueType" == sFontFormat && ( pSymbols != NULL || !sNameW.empty() ) )
        {
            NSFontConverter::CFontFileTrueType* pTTF = NSFontConverter::CFontFileTrueType::LoadFromFile( sFontIn.c_str() );
            if ( pTTF )
            {
                std::string sName = U_TO_UTF8(sNameW);
                unsigned char *pUseGlyfs = NULL;
                long lGlyfsCount = pFace->num_glyphs;

                if ( pSymbols )
                {
                    // Сначала составим список нужных нами GID
                    unsigned int* pUnicode = pSymbols;
                    unsigned short* pGIDs = new unsigned short[nCount];
                    int nCMapIndex = 0;

                    int nSymbolicIndex = NSFontConverter::GetSymbolicCmapIndex(pFace);

                    if (!bIsGids)
                    {
                        for ( int nIndex = 0; nIndex < nCount; nIndex++ )
                        {
                            pGIDs[nIndex] = NSFontConverter::SetCMapForCharCode( pFace, pUnicode[nIndex], &nCMapIndex  );

                            if ((pGIDs[nIndex] == 0) && (-1 != nSymbolicIndex) && (pUnicode[nIndex] < 0xF000))
                            {
                                pGIDs[nIndex] = NSFontConverter::SetCMapForCharCode( pFace, pUnicode[nIndex] + 0xF000, &nCMapIndex  );
                            }
                        }
                    }
                    else
                    {
                        for (int i = 0; i < nCount; ++i)
                            pGIDs[i] = (unsigned short)pUnicode[i];
                    }

                    pUseGlyfs = new unsigned char[lGlyfsCount];
                    ::memset( pUseGlyfs, 0x00, lGlyfsCount * sizeof(unsigned char) );
                    pUseGlyfs[0] = 1; // нулевой гид всегда записываем
                    for ( int nGID = 1; nGID < lGlyfsCount; nGID++ )
                    {
                        if ( 1 != pUseGlyfs[nGID] )
                        {
                            bool bFound = false;
                            for ( int nIndex = 0; nIndex < nCount; nIndex++ )
                            {
                                if ( nGID == pGIDs[nIndex] )
                                {
                                    bFound = true;
                                    break;
                                }
                            }

                            // Если данный символ составной (CompositeGlyf), тогда мы должны учесть все его дочерные символы (subglyfs)
                            if ( bFound && 0 == FT_Load_Glyph( pFace, nGID, FT_LOAD_NO_SCALE | FT_LOAD_NO_RECURSE ) )
                            {
                                for ( int nSubIndex = 0; nSubIndex < pFace->glyph->num_subglyphs; nSubIndex++ )
                                {
                                    FT_Int       nSubGID;
                                    FT_UInt      unFlags;
                                    FT_Int       nArg1;
                                    FT_Int       nArg2;
                                    FT_Matrix    oMatrix;
                                    FT_Get_SubGlyph_Info( pFace->glyph, nSubIndex, &nSubGID, &unFlags, &nArg1, &nArg2, &oMatrix );

                                    if ( nSubGID < lGlyfsCount )
                                        pUseGlyfs[nSubGID] = 1;
                                }
                            }

                            if ( bFound )
                                pUseGlyfs[nGID] = 1;
                        }
                    }
                }

                NSFile::CFileBinary oWriteFile;
                oWriteFile.CreateFileW(sFontOut);
                pTTF->WriteTTF( &NSFontConverter::FileWrite, oWriteFile.GetFileNative(), sName.c_str(), NULL, pUseGlyfs, lGlyfsCount );
                oWriteFile.CloseFile();
            }
            else
            {
                // error parse font
                // Просто копируем файл
                NSFile::CFileBinary::Copy(sFontIn, sFontOut);
            }
        }
    }
    else
    {
        // Просто копируем файл
        NSFile::CFileBinary::Copy(sFontIn, sFontOut);
    }

    FT_Done_Face( pFace );
    FT_Done_FreeType( pLibrary );

    RELEASEARRAYOBJECTS(pBaseAddress);

    return true;
}
Example #29
0
  static FT_Error
  af_loader_load_g( AF_Loader  loader,
                    AF_Scaler  scaler,
                    FT_UInt    glyph_index,
                    FT_Int32   load_flags,
                    FT_UInt    depth )
  {
    FT_Error          error;
    FT_Face           face     = loader->face;
    FT_GlyphLoader    gloader  = loader->gloader;
    AF_ScriptMetrics  metrics  = loader->metrics;
    AF_GlyphHints     hints    = &loader->hints;
    FT_GlyphSlot      slot     = face->glyph;
    FT_Slot_Internal  internal = slot->internal;
    FT_Int32          flags;


    flags = load_flags | FT_LOAD_LINEAR_DESIGN;
    error = FT_Load_Glyph( face, glyph_index, flags );
    if ( error )
      goto Exit;

    loader->transformed = internal->glyph_transformed;
    if ( loader->transformed )
    {
      FT_Matrix  inverse;


      loader->trans_matrix = internal->glyph_matrix;
      loader->trans_delta  = internal->glyph_delta;

      inverse = loader->trans_matrix;
      FT_Matrix_Invert( &inverse );
      FT_Vector_Transform( &loader->trans_delta, &inverse );
    }

    switch ( slot->format )
    {
    case FT_GLYPH_FORMAT_OUTLINE:
      /* translate the loaded glyph when an internal transform is needed */
      if ( loader->transformed )
        FT_Outline_Translate( &slot->outline,
                              loader->trans_delta.x,
                              loader->trans_delta.y );

      /* copy the outline points in the loader's current                */
      /* extra points which are used to keep original glyph coordinates */
      error = FT_GLYPHLOADER_CHECK_POINTS( gloader,
                                           slot->outline.n_points + 4,
                                           slot->outline.n_contours );
      if ( error )
        goto Exit;

      FT_ARRAY_COPY( gloader->current.outline.points,
                     slot->outline.points,
                     slot->outline.n_points );

      FT_ARRAY_COPY( gloader->current.outline.contours,
                     slot->outline.contours,
                     slot->outline.n_contours );

      FT_ARRAY_COPY( gloader->current.outline.tags,
                     slot->outline.tags,
                     slot->outline.n_points );

      gloader->current.outline.n_points   = slot->outline.n_points;
      gloader->current.outline.n_contours = slot->outline.n_contours;

      /* compute original horizontal phantom points (and ignore */
      /* vertical ones)                                         */
      loader->pp1.x = hints->x_delta;
      loader->pp1.y = hints->y_delta;
      loader->pp2.x = FT_MulFix( slot->metrics.horiAdvance,
                                 hints->x_scale ) + hints->x_delta;
      loader->pp2.y = hints->y_delta;

      /* be sure to check for spacing glyphs */
      if ( slot->outline.n_points == 0 )
        goto Hint_Metrics;

      /* now load the slot image into the auto-outline and run the */
      /* automatic hinting process                                 */
      if ( metrics->clazz->script_hints_apply )
        metrics->clazz->script_hints_apply( hints,
                                            &gloader->current.outline,
                                            metrics );

      /* we now need to adjust the metrics according to the change in */
      /* width/positioning that occurred during the hinting process   */
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT )
      {
        FT_Pos        old_rsb, old_lsb, new_lsb;
        FT_Pos        pp1x_uh, pp2x_uh;
        AF_AxisHints  axis  = &hints->axis[AF_DIMENSION_HORZ];
        AF_Edge       edge1 = axis->edges;         /* leftmost edge  */
        AF_Edge       edge2 = edge1 +
                              axis->num_edges - 1; /* rightmost edge */


        if ( axis->num_edges > 1 && AF_HINTS_DO_ADVANCE( hints ) )
        {
          old_rsb = loader->pp2.x - edge2->opos;
          old_lsb = edge1->opos;
          new_lsb = edge1->pos;

          /* remember unhinted values to later account */
          /* for rounding errors                       */

          pp1x_uh = new_lsb    - old_lsb;
          pp2x_uh = edge2->pos + old_rsb;

          /* prefer too much space over too little space */
          /* for very small sizes                        */

          if ( old_lsb < 24 )
            pp1x_uh -= 8;

          if ( old_rsb < 24 )
            pp2x_uh += 8;

          loader->pp1.x = FT_PIX_ROUND( pp1x_uh );
          loader->pp2.x = FT_PIX_ROUND( pp2x_uh );

          if ( loader->pp1.x >= new_lsb && old_lsb > 0 )
            loader->pp1.x -= 64;

          if ( loader->pp2.x <= edge2->pos && old_rsb > 0 )
            loader->pp2.x += 64;

          slot->lsb_delta = loader->pp1.x - pp1x_uh;
          slot->rsb_delta = loader->pp2.x - pp2x_uh;
        }
        else
        {
          FT_Pos  pp1x = loader->pp1.x;
          FT_Pos  pp2x = loader->pp2.x;


          loader->pp1.x = FT_PIX_ROUND( pp1x );
          loader->pp2.x = FT_PIX_ROUND( pp2x );

          slot->lsb_delta = loader->pp1.x - pp1x;
          slot->rsb_delta = loader->pp2.x - pp2x;
        }
      }
      else
      {
        FT_Pos  pp1x = loader->pp1.x;
        FT_Pos  pp2x = loader->pp2.x;


        loader->pp1.x = FT_PIX_ROUND( pp1x + hints->xmin_delta );
        loader->pp2.x = FT_PIX_ROUND( pp2x + hints->xmax_delta );

        slot->lsb_delta = loader->pp1.x - pp1x;
        slot->rsb_delta = loader->pp2.x - pp2x;
      }

      /* good, we simply add the glyph to our loader's base */
      FT_GlyphLoader_Add( gloader );
      break;

    case FT_GLYPH_FORMAT_COMPOSITE:
      {
        FT_UInt      nn, num_subglyphs = slot->num_subglyphs;
        FT_UInt      num_base_subgs, start_point;
        FT_SubGlyph  subglyph;


        start_point = gloader->base.outline.n_points;

        /* first of all, copy the subglyph descriptors in the glyph loader */
        error = FT_GlyphLoader_CheckSubGlyphs( gloader, num_subglyphs );
        if ( error )
          goto Exit;

        FT_ARRAY_COPY( gloader->current.subglyphs,
                       slot->subglyphs,
                       num_subglyphs );

        gloader->current.num_subglyphs = num_subglyphs;
        num_base_subgs                 = gloader->base.num_subglyphs;

        /* now read each subglyph independently */
        for ( nn = 0; nn < num_subglyphs; nn++ )
        {
          FT_Vector  pp1, pp2;
          FT_Pos     x, y;
          FT_UInt    num_points, num_new_points, num_base_points;


          /* gloader.current.subglyphs can change during glyph loading due */
          /* to re-allocation -- we must recompute the current subglyph on */
          /* each iteration                                                */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          pp1 = loader->pp1;
          pp2 = loader->pp2;

          num_base_points = gloader->base.outline.n_points;

          error = af_loader_load_g( loader, scaler, subglyph->index,
                                    load_flags, depth + 1 );
          if ( error )
            goto Exit;

          /* recompute subglyph pointer */
          subglyph = gloader->base.subglyphs + num_base_subgs + nn;

          if ( subglyph->flags & FT_SUBGLYPH_FLAG_USE_MY_METRICS )
          {
            pp1 = loader->pp1;
            pp2 = loader->pp2;
          }
          else
          {
            loader->pp1 = pp1;
            loader->pp2 = pp2;
          }

          num_points     = gloader->base.outline.n_points;
          num_new_points = num_points - num_base_points;

          /* now perform the transformation required for this subglyph */

          if ( subglyph->flags & ( FT_SUBGLYPH_FLAG_SCALE    |
                                   FT_SUBGLYPH_FLAG_XY_SCALE |
                                   FT_SUBGLYPH_FLAG_2X2      ) )
          {
            FT_Vector*  cur   = gloader->base.outline.points +
                                num_base_points;
            FT_Vector*  limit = cur + num_new_points;


            for ( ; cur < limit; cur++ )
              FT_Vector_Transform( cur, &subglyph->transform );
          }

          /* apply offset */

          if ( !( subglyph->flags & FT_SUBGLYPH_FLAG_ARGS_ARE_XY_VALUES ) )
          {
            FT_Int      k = subglyph->arg1;
            FT_UInt     l = subglyph->arg2;
            FT_Vector*  p1;
            FT_Vector*  p2;


            if ( start_point + k >= num_base_points         ||
                               l >= (FT_UInt)num_new_points )
            {
              error = FT_THROW( Invalid_Composite );
              goto Exit;
            }

            l += num_base_points;

            /* for now, only use the current point coordinates; */
            /* we eventually may consider another approach      */
            p1 = gloader->base.outline.points + start_point + k;
            p2 = gloader->base.outline.points + start_point + l;

            x = p1->x - p2->x;
            y = p1->y - p2->y;
          }
          else
          {
            x = FT_MulFix( subglyph->arg1, hints->x_scale ) + hints->x_delta;
            y = FT_MulFix( subglyph->arg2, hints->y_scale ) + hints->y_delta;

            x = FT_PIX_ROUND( x );
            y = FT_PIX_ROUND( y );
          }

          {
            FT_Outline  dummy = gloader->base.outline;


            dummy.points  += num_base_points;
            dummy.n_points = (short)num_new_points;

            FT_Outline_Translate( &dummy, x, y );
          }
        }
      }
      break;

    default:
      /* we don't support other formats (yet?) */
      error = FT_THROW( Unimplemented_Feature );
    }

  Hint_Metrics:
    if ( depth == 0 )
    {
      FT_BBox    bbox;
      FT_Vector  vvector;


      vvector.x = slot->metrics.vertBearingX - slot->metrics.horiBearingX;
      vvector.y = slot->metrics.vertBearingY - slot->metrics.horiBearingY;
      vvector.x = FT_MulFix( vvector.x, metrics->scaler.x_scale );
      vvector.y = FT_MulFix( vvector.y, metrics->scaler.y_scale );

      /* transform the hinted outline if needed */
      if ( loader->transformed )
      {
        FT_Outline_Transform( &gloader->base.outline, &loader->trans_matrix );
        FT_Vector_Transform( &vvector, &loader->trans_matrix );
      }
#if 1
      /* we must translate our final outline by -pp1.x and compute */
      /* the new metrics                                           */
      if ( loader->pp1.x )
        FT_Outline_Translate( &gloader->base.outline, -loader->pp1.x, 0 );
#endif
      FT_Outline_Get_CBox( &gloader->base.outline, &bbox );

      bbox.xMin = FT_PIX_FLOOR( bbox.xMin );
      bbox.yMin = FT_PIX_FLOOR( bbox.yMin );
      bbox.xMax = FT_PIX_CEIL(  bbox.xMax );
      bbox.yMax = FT_PIX_CEIL(  bbox.yMax );

      slot->metrics.width        = bbox.xMax - bbox.xMin;
      slot->metrics.height       = bbox.yMax - bbox.yMin;
      slot->metrics.horiBearingX = bbox.xMin;
      slot->metrics.horiBearingY = bbox.yMax;

      slot->metrics.vertBearingX = FT_PIX_FLOOR( bbox.xMin + vvector.x );
      slot->metrics.vertBearingY = FT_PIX_FLOOR( bbox.yMax + vvector.y );

      /* for mono-width fonts (like Andale, Courier, etc.) we need */
      /* to keep the original rounded advance width; ditto for     */
      /* digits if all have the same advance width                 */
#if 0
      if ( !FT_IS_FIXED_WIDTH( slot->face ) )
        slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      else
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               x_scale );
#else
      if ( scaler->render_mode != FT_RENDER_MODE_LIGHT                      &&
           ( FT_IS_FIXED_WIDTH( slot->face )                              ||
             ( af_face_globals_is_digit( loader->globals, glyph_index ) &&
               metrics->digits_have_same_width                          ) ) )
      {
        slot->metrics.horiAdvance = FT_MulFix( slot->metrics.horiAdvance,
                                               metrics->scaler.x_scale );

        /* Set delta values to 0.  Otherwise code that uses them is */
        /* going to ruin the fixed advance width.                   */
        slot->lsb_delta = 0;
        slot->rsb_delta = 0;
      }
      else
      {
        /* non-spacing glyphs must stay as-is */
        if ( slot->metrics.horiAdvance )
          slot->metrics.horiAdvance = loader->pp2.x - loader->pp1.x;
      }
#endif

      slot->metrics.vertAdvance = FT_MulFix( slot->metrics.vertAdvance,
                                             metrics->scaler.y_scale );

      slot->metrics.horiAdvance = FT_PIX_ROUND( slot->metrics.horiAdvance );
      slot->metrics.vertAdvance = FT_PIX_ROUND( slot->metrics.vertAdvance );

      /* now copy outline into glyph slot */
      FT_GlyphLoader_Rewind( internal->loader );
      error = FT_GlyphLoader_CopyPoints( internal->loader, gloader );
      if ( error )
        goto Exit;

      /* reassign all outline fields except flags to protect them */
      slot->outline.n_contours = internal->loader->base.outline.n_contours;
      slot->outline.n_points   = internal->loader->base.outline.n_points;
      slot->outline.points     = internal->loader->base.outline.points;
      slot->outline.tags       = internal->loader->base.outline.tags;
      slot->outline.contours   = internal->loader->base.outline.contours;

      slot->format  = FT_GLYPH_FORMAT_OUTLINE;
    }

  Exit:
    return error;
  }
Example #30
0
    // ----------------------------------------------- texture_font_load_glyphs ---
    size_t
    texture_font_load_glyphs( texture_font_t * self,
                              const wchar_t * charcodes )
    {
        size_t i, j, x, y, width, height, depth, w, h;

        FT_Library library;
        FT_Error error;
        FT_Face face;
        FT_Glyph ft_glyph;
        FT_GlyphSlot slot;
        FT_Bitmap ft_bitmap;

        FT_UInt glyph_index;
        texture_glyph_t *glyph;
        FT_Int32 flags = 0;
        int ft_glyph_top = 0;
        int ft_glyph_left = 0;

        ivec4 region;
        size_t missed = 0;
        char pass;

        assert( self );
        assert( charcodes );


        width  = self->atlas->width;
        height = self->atlas->height;
        depth  = self->atlas->depth;

        if (!texture_font_get_face(self, &library, &face))
            return wcslen(charcodes);

        /* Load each glyph */
        for( i = 0; i < wcslen(charcodes); ++i ) {
            pass = 0;
            /* Check if charcode has been already loaded */
            for( j = 0; j < self->glyphs->size; ++j ) {
                glyph = *(texture_glyph_t **) vector_get( self->glyphs, j );
                // If charcode is -1, we don't care about outline type or thickness
                // if( (glyph->charcode == charcodes[i])) {
                if( (glyph->charcode == charcodes[i]) &&
                    ((charcodes[i] == (wchar_t)(-1) ) ||
                     ((glyph->outline_type == self->outline_type) &&
                      (glyph->outline_thickness == self->outline_thickness)) ))
                {
                    pass = 1;
                    break;
                }
            }

            if(pass)
                continue;

            flags = 0;
            ft_glyph_top = 0;
            ft_glyph_left = 0;
            glyph_index = FT_Get_Char_Index( face, charcodes[i] );
            // WARNING: We use texture-atlas depth to guess if user wants
            //          LCD subpixel rendering

            if( self->outline_type > 0 )
            {
                flags |= FT_LOAD_NO_BITMAP;
            }
            else
            {
                flags |= FT_LOAD_RENDER;
            }

            if( !self->hinting )
            {
                flags |= FT_LOAD_NO_HINTING | FT_LOAD_NO_AUTOHINT;
            }
            else
            {
                flags |= FT_LOAD_FORCE_AUTOHINT;
            }


            if( depth == 3 )
            {
                FT_Library_SetLcdFilter( library, FT_LCD_FILTER_LIGHT );
                flags |= FT_LOAD_TARGET_LCD;
                if( self->filtering )
                {
                    FT_Library_SetLcdFilterWeights( library, self->lcd_weights );
                }
            }

            error = FT_Load_Glyph( face, glyph_index, flags );
            if( error )
            {
                FT_Done_Face( face );
                FT_Done_FreeType( library );
                throw wcslen(charcodes)-i;
            }


            if( self->outline_type == 0 )
            {
                slot            = face->glyph;
                ft_bitmap       = slot->bitmap;
                ft_glyph_top    = slot->bitmap_top;
                ft_glyph_left   = slot->bitmap_left;
            }
            else
            {
                FT_Stroker stroker;
                FT_BitmapGlyph ft_bitmap_glyph;
                error = FT_Stroker_New( library, &stroker );
                if( error )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }
                FT_Stroker_Set(stroker,
                                (int)(self->outline_thickness * HRES),
                                FT_STROKER_LINECAP_ROUND,
                                FT_STROKER_LINEJOIN_ROUND,
                                0);
                error = FT_Get_Glyph( face->glyph, &ft_glyph);
                if( error )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }

                if( self->outline_type == 1 )
                {
                    error = FT_Glyph_Stroke( &ft_glyph, stroker, 1 );
                }
                else if ( self->outline_type == 2 )
                {
                    error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 0, 1 );
                }
                else if ( self->outline_type == 3 )
                {
                    error = FT_Glyph_StrokeBorder( &ft_glyph, stroker, 1, 1 );
                }
                if( error )
                {
                    FT_Done_Face( face );
                    FT_Stroker_Done( stroker );
                    FT_Done_FreeType( library );
					throw;
                }

                if( depth == 1)
                {
                    error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_NORMAL, 0, 1);
                    if( error )
                    {
                        FT_Done_Face( face );
                        FT_Stroker_Done( stroker );
                        FT_Done_FreeType( library );
						throw;
                    }
                }
                else
                {
                    error = FT_Glyph_To_Bitmap( &ft_glyph, FT_RENDER_MODE_LCD, 0, 1);
                    if( error )
                    {
                        FT_Done_Face( face );
                        FT_Stroker_Done( stroker );
                        FT_Done_FreeType( library );
						throw;
                    }
                }
                ft_bitmap_glyph = (FT_BitmapGlyph) ft_glyph;
                ft_bitmap       = ft_bitmap_glyph->bitmap;
                ft_glyph_top    = ft_bitmap_glyph->top;
                ft_glyph_left   = ft_bitmap_glyph->left;
                FT_Stroker_Done(stroker);
            }


            // We want each glyph to be separated by at least one black pixel
            // (for example for shader used in demo-subpixel.c)
            w = ft_bitmap.width/depth + 1;
            h = ft_bitmap.rows + 1;
            region = texture_atlas_get_region( self->atlas, w, h );
            if ( region.x < 0 )
            {
                missed++;
                fprintf( stderr, "Texture atlas is full (line %d)\n",  __LINE__ );
                continue;
            }
            w = w - 1;
            h = h - 1;
            x = region.x;
            y = region.y;
            texture_atlas_set_region( self->atlas, x, y, w, h,
                                      ft_bitmap.buffer, ft_bitmap.pitch );

            glyph = texture_glyph_new( );
            glyph->charcode = charcodes[i];
            glyph->width    = w;
            glyph->height   = h;
            glyph->outline_type = self->outline_type;
            glyph->outline_thickness = self->outline_thickness;
            glyph->offset_x = ft_glyph_left;
            glyph->offset_y = ft_glyph_top;
            glyph->s0       = x/(float)width;
            glyph->t0       = y/(float)height;
            glyph->s1       = (x + glyph->width)/(float)width;
            glyph->t1       = (y + glyph->height)/(float)height;

            // Discard hinting to get advance
            FT_Load_Glyph( face, glyph_index, FT_LOAD_RENDER | FT_LOAD_NO_HINTING);
            slot = face->glyph;
            glyph->advance_x = slot->advance.x / HRESf;
            glyph->advance_y = slot->advance.y / HRESf;

            vector_push_back( self->glyphs, &glyph );

            if( self->outline_type > 0 )
            {
                FT_Done_Glyph( ft_glyph );
            }
        }

        FT_Done_Face( face );
        FT_Done_FreeType( library );
        texture_atlas_upload( self->atlas );
        texture_font_generate_kerning( self );
        return missed;
    }