Jump to content
  • Advertisement
Sign in to follow this  

VBO & Fonts..

This topic is 3675 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey back over in this topic, I was told to use vbo's for everything, even fonts.. now after getting to know how vbo works, I dont get how this could be efficiently done.. To begin I'll tell you what my font system needs: The hud in the game dll can draw a lot of text, it can be colored differently with escape codes like in quake3 and it has its specified drawing order. Currently I have a fontclass with memberfunctions SetSize, DrawString, etc Now every frame the hud will draw quads over the screen using DrawString, while SetSize is only called on change. Now using VBO's, I thought I would need to have a new class VBO_TextObject, which will get called on text creation/change to init the vbo and on every frame, the hud calls the textobjects Draw function, so it's drawn in the correct order. Now to my problems: From what I can see there are 2 ways to solve the buffering & drawing: - Have a VBO for all texcoord of a font, and for the different sizes of the font a vbo that contains all verts for the glyphs, then doing something like: foreach char in string, translate to x-value & call drawrangelements for the char. - Or create 3 VBO's for every TextObject (vertex, color, texcoord), and call drawrangelements once on the textobjects vbo's both methods seem very ugly to me and cause a lot of memory to be lost for nothing. I'm not quite sure this will gain any performance at all. any other suggestions ?

Share this post

Link to post
Share on other sites
Normally, text doesn't change every frame, so you could just have an entire sentence in a single texture and render.
It only requires 1 call to glBindBuffer or perhaps 0 if you have already bound it.

Share this post

Link to post
Share on other sites
what do you mean by a single texture ?
like prerender the string into a texture which is then drawn as a single quad ?
some text items do update pretty frequently tho, like fps, teamoverlay, chat messages, console text, etc

Share this post

Link to post
Share on other sites
What I do (may be terrible way of doing it but, for conversation sake) I use a font texture, that contains all the characters, this font texture has an associated data file describing all the offsets and tweaks that each character needs to be positioned. I allocate a buffer (vbo) that can be used to draw MaxChars, say 128 at a time. When drawing, I set the font texture for use, then modify this vertex buffer (interleaved), changing the vertices position (for translating placing in right place), texcoord (based on characters parameters, so it use the right part of the texture), and color (for blending the texture with the vertices to change its color). This buffer lives in a manager for hud stuff, hud elements call it when they want to draw their text, or i can call it right away for throwing up debug text. So if I need to draw say 152 chars, I make two calls, a 128 call, and the rest goes in another call. So it goes something like this.

Load Font Texture
Load Font Texture Data (build a list of chars, 1:1 char array indexing)
Allocate a vbo with some limit I think is best
Draw Text
Build Text String (straight index into array to get char info I need)
Loop text, tweak two tris to position coords on say 'R' part of texture
Set texture
Draw Vbo

God how I hate text.

Share this post

Link to post
Share on other sites
How about using a round-robin of Streaming VBOs, use glMapBuffer and fill-in vtx-attribs of triangles. (2 triangles for each drawn character)

Here's an excerpt from a header of my implementation of such stuff:

//------------[ vertex-buffer-object procs ]--------------------------------------[
ILVBO ilCreateStaticVBO(const void* vtxData,int numVerts,const short* vtxDecl,const void* idxData=0,int idxDataSize=0,bool isDwordIndex=true);
ILVBO ilCreateStreamVBO(int VtxBufSize,int IdxBufSize,bool isDwordIndex);
void ilDeleteVBO(ILVBO vbo);
void ilDrawVBO(ILVBO vbo);
void ilDrawVBOs(ILVBO vboPrimary,ILVBO vboSecondary); // one of these VBOs has an index-buffer; vboPrimary must have ATTR0 (vertex-position). All attributes and data from the two VBOs are used to draw the primitives
int ilGetVertexDeclSize(const short* vtxDecl); // get expected size of a vertex, by passing its vertex-declaration

//-----------[ immediate-mode drawing ]----------------------------------------------[
void ilImmBegin(int NumVertsPerPrim1234,const short* vtxDecl); // start immediate mode, with expected type of primitives (1=points, 2=lines, 3=triangles, 4=quads and triangles). Each vertex has the same format, specified by vtxDecl. vtxDecl MUST NOT be NULL! vtxDecl must stay valid at least until ilImmEnd() - so don't put it on the thread's stack if the stack will be overwritten before ilImmEnd.
void ilImmEnd(); // flush and end drawing this set of immediate-mode primitives
void ilImmFlush();// flush drawing, expecting to continue drawing imm-mode primitives. Useful if you want to change an uniform-value in-between a range of primitives
void ilImmPoint(const void* vtx1); // add one vertex, defining a point
void ilImmLine(const void* vtx12); // add two vertices, defining a line. vtx12 contains both vertices in a contiguous range of memory
void ilImmLine(const void* vtx1,const void* vtx2); // like above, but the two vertices can be from different ranges of memory
void ilImmTriangle(const void* vtx123); // add three vertices, defining a triangle. Contiguous range of memory
void ilImmTriangle(const void* vtx1,const void* vtx2, const void* vtx3); // like above, but different mem-ranges
void ilImmQuad(const void* vtx1234); // add four vertices, defining a quad. They get internally split into two CW triangles.
void ilImmQuad(const void* vtx1,const void* vtx2, const void* vtx3,const void* vtx4); // like above, but different mem-ranges

void ilImmDrawArray(int NumPrimitives,int NumVertsPerPrim1234,const short* vtxDecl,const void* data);

I've uploaded the whole .h and .cpp implementation at:

Share this post

Link to post
Share on other sites
Original post by NumberXaero
So if I need to draw say 152 chars, I make two calls, a 128 call, and the rest goes in another call. So it goes something like this.

So you are uploading the string verts into the vbo every frame ?
wouldn't it be easier to draw a vertex array without allocating a buffer ?

I dont really get how this is working.. could you give an example of how you use the code ?

Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!