Game Development Community

TextObject. Generate a texture in OpenGL

by Pedro Vicente · in Torque 2D Beginner · 11/10/2013 (2:03 pm) · 3 replies

I am trying to do a vector class font (I named it TextObject), to use as a better alternative to the bitmap font class ImageFont of the engine.

The render function done so far is

void TextObject::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
{
  const char *p = mText.getPtr8();
  FT_GlyphSlot g = face->glyph;

  // Fetch number of characters to render.
  const U32 renderCharacters = mText.length();

  // Ignore if no text to render.
  if( renderCharacters == 0 )
    return;

  // Render all the characters.    
  for( U32 characterIndex = 0; characterIndex < renderCharacters; ++characterIndex )
  {
    // Fetch character.
    U32 character = mText.getChar( characterIndex );

    // Load and render the character 
    if (FT_Load_Char(face, *p, FT_LOAD_RENDER))
      continue;


    p++;
  }

}


I am using the FreeType library freetype.org/, that generates glyph images from a vector font file. The code above just iterates all the glyphs.

I am trying to do something similar to the ImageFont render, that generates a texture from a bitmap file, with the font.

void ImageFont::sceneRender( const SceneRenderState* pSceneRenderState, const SceneRenderRequest* pSceneRenderRequest, BatchRender* pBatchRenderer )
{
    // Finish if no image asset.
    if ( mImageAsset.isNull() )
        return;

    // Fetch number of characters to render.
    const U32 renderCharacters = mText.length();

    // Ignore if no text to render.
    if( renderCharacters == 0 )
        return;

    // Fetch render OOBB.
    const Vector2& renderOOBB0 = mRenderOOBB[0];
    const Vector2& renderOOBB1 = mRenderOOBB[1];
    const Vector2& renderOOBB3 = mRenderOOBB[3];

    Vector2 characterOOBB0;
    Vector2 characterOOBB1;
    Vector2 characterOOBB2;
    Vector2 characterOOBB3;

    // Calculate the starting render position based upon text alignment.
    
    // Size is the total padded text size as we're simply centered on the position.
    characterOOBB0 = renderOOBB0;
 
    // Calculate character width stride.
    Vector2 characterWidthStride = (renderOOBB1 - renderOOBB0);
    characterWidthStride.Normalize( mFontSize.x + mFontPadding );

    // Calculate character height stride.
    Vector2 characterHeightStride = (renderOOBB3 - renderOOBB0);
    characterHeightStride.Normalize( mFontSize.y );

    // Complete character OOBB.
    characterOOBB1 = characterOOBB0 + characterWidthStride;
    characterOOBB2 = characterOOBB1 + characterHeightStride;
    characterOOBB3 = characterOOBB2 - characterWidthStride;

    // Render all the characters.    
    for( U32 characterIndex = 0; characterIndex < renderCharacters; ++characterIndex )
    {
        // Fetch character.
        U32 character = mText.getChar( characterIndex );

        // Set character to "space" if it's out of bounds.
        if ( character < 32 || character > 128 )
            character = 32;

        // Calculate character frame index.
        const U32 characterFrameIndex = character - 32;

        // Fetch current frame area.
        const ImageAsset::FrameArea::TexelArea& texelFrameArea = mImageAsset->getImageFrameArea( characterFrameIndex ).mTexelArea;

        // Fetch lower/upper texture coordinates.
        const Vector2& texLower = texelFrameArea.mTexelLower;
        const Vector2& texUpper = texelFrameArea.mTexelUpper;

        // Submit batched quad.
        pBatchRenderer->SubmitQuad(
            characterOOBB0,
            characterOOBB1,
            characterOOBB2,
            characterOOBB3,
            Vector2( texLower.x, texUpper.y ),
            Vector2( texUpper.x, texUpper.y ),
            Vector2( texUpper.x, texLower.y ),
            Vector2( texLower.x, texLower.y ),
            mImageAsset->getImageTexture() );

        // Translate character OOBB.
        characterOOBB0 += characterWidthStride;
        characterOOBB1 += characterWidthStride;
        characterOOBB2 += characterWidthStride;
        characterOOBB3 += characterWidthStride;
    }
}


It seems all is needed is to call this function

pBatchRenderer->SubmitQuad

with the last parameter being a texture generated from the bitmap glyph.

I am looking to the sources, and there are several classes that seem to encapsulate OpenGL textures, like
TextureHandle, TextureObject.

Can someone point to some code that would accomplish this?
Thanks


#1
11/11/2013 (4:10 am)
This is a really good idea. It would be nice to have a VectorFont to compliment ImageFont and provide a better alternative to GuiTextCtrl since that class isn't wired to the batching system and you're stuck with the quirks of the GUI system. I know the recent Android port also uses freetype, it would be nice to commonize the entire font system around that library. Some other comments from another community member regarding the current font system's weaknesses:

Quote:4) The font system doesn't support generating or rendering retina fonts for IOS devices. Of course you can just double the coordinate system of your GUI controls & use 2x point sizes, but that just adds to the inconsistency. I had to hack the OSX font generator to render to a 2x bitmap while retaining the normal metrics to get everything looking right on both retina and non-retina displays.

5) In relation to #4, when drawing font characters everything is constrained to an integer grid which can create odd kerning issues on platforms other than windows where fonts are rendered more correctly rather than being hacked onto a grid to appear more legible.

Sorry for the slight thread derail!
#2
11/11/2013 (10:55 pm)
@Mike
Glad to know that the Android port uses FreeType. Do you know when are you going to merge the development branch into the master for a release? This looks like a much needed feature to me.
#3
11/12/2013 (2:27 pm)
No sorry, I don't know when we will merge development into master. The development branch is quite stable though, feel free to use it for any work you wish to do.