Sign in to follow this  
wforl

Optimizing a Bitmap Font

Recommended Posts

At the moment im just rendering out each letter via its only shader call, which is obviously not a good way of doing things, and am planning to optimize it. The code at the moment works by, 1. converting the data into a sting 2. loop throught each letter - calculate bitmap UV location - apply position, scaling, and ratio correction - send polgon to effect So im looking at making some sort of spritebatch that allows for a container to be filled up with data to be rendered, but renders it all in one go to be more optimized, or when it is manualy flushed. My plan is that when a letter is added to the spritebatch, i calculate the UV,scale, pos, and ratio correction into one matrix, along with the char, and then pop this into the container. And then when the spritebatch comes to render, i multiply the same polygon vertices by each of the spritbatch data members, so that rendering is done all in one go, with the sprite batch being rendered each frame, and the spritebatch then being renewed each frame, for when the letters chnage, or some affect is applied,
//add to batch call
///////////////////////////////

spritebatchObject t;
t.U = getU(char)
t.V = getV(char)
t.colour = col
t.transform = ( pos,scale,ratio corection etc etc)

spritebatch.pushback(t);


//render entire batch call
/////////////////////////////////

SendShader(BitmapImage);

start pass

for(i = 0, i < spritebatch.size(), ++i){
    SendShader(spritebatch[i].transform);
    SendShader( "           ".colour;
    .. etc etc

    lockVbuffer squarePoly
    //set verts UVs
    unlockVbuffer squarePoly

    dev->SetStreamSource(squarePoly);
} 

end pass


but this is still going to be slow as each letter gets sent to the effect. And then theres the wasteage that the text is getting calculated each frame, when generally its only the UVs that are going to change. So im basically looking for way to create a descent optimzed bitmap font renderer

Share this post


Link to post
Share on other sites
Sorry if I'm missing something, but why do you have to render each letter separately?

Can't you just take the string, create a quad for every letter in it, put the quads in a dynamic VB and render the whole VB in one draw call?

You also don't have to do this every frame for every string, just for the strings that change. In fact, if some of your strings are constant, you can put them in a static VB and never touch the VB.

EDIT: You might also want to take a look here.

Share this post


Link to post
Share on other sites
Quote:
Original post by Gage64
Can't you just take the string, create a quad for every letter in it, put the quads in a dynamic VB and render the whole VB in one draw call?

You also don't have to do this every frame for every string, just for the strings that change. In fact, if some of your strings are constant, you can put them in a static VB and never touch the VB.
Yep, that's how my font renderer works.
Whenever the string is modified, I calculate all the vert/UV coordinates and fill up a VB with a bunch of quads.
Then every frame I just render the VB using the font shader.

Share this post


Link to post
Share on other sites
So you're creating a new vertex buffer each time the data changes?, and then rendering a triangle strip with the whole string?

Hmm, have you also allowed for +/- padding between the letters?

So do you mean something like



//render current health
static int LastHealth = 0;
static VertexPT* healthVB = 0;


if(LastHealth == player.health)
RenderFont(&healthVB );
else
{
healthVB ->Release();
calculateNewBuffer(&healthVB , player.health);
lasthealth = health;
}




Share this post


Link to post
Share on other sites
Quote:
Original post by wforl
healthVB ->Release();


Destroying and recreating the VB is expensive and is unnecessary; you can just modify it's contents. If you're using a dynamic VB (as you should for this sort of thing), this can be done in an efficient way. See here for more info.

Share this post


Link to post
Share on other sites
Quote:
Original post by wforl
but i wont know what size to create the buffer until i receive the string. Do you mean just create a buffer thats longer than i'll ever need?


Usually you use a VB to store geometry data (such as the characters in your game). Such a VB is usually large enough to hold thousands of vertices (especially if you put several models in one VB, which is often done to reduce switching between VBs).

I think a string of text needs far less vertices than that. Even if you want to use one VB to render several strings to reduce VB switches, you can reuse the VB's memory as shown in the link I posted.

So to answer your question - yes, I think creating a VB large enough to hold any string is reasonable.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this