TGEA 1.8.0 - FontRenderBatcher::render
by Stephane Conde · in Torque Game Engine Advanced · 12/20/2008 (10:30 pm) · 1 replies
I'm not entirely sure if this is a bug with the code or I am doing something wrong, but I'm getting an assert inside FontRenderBatcher::render saying "FontRenderBatcher::render - too many verts for length of string!".
The assert looks like the following:
This seems like a reasonable assert to me, but there is definitely something wonky with the code just above the assert.
The code is allocating a vertex buffer big enough for mLength * 6 verts (the number of characters in the string * 6 verts):
The for loop then adds 6 verts per character per sheet! I only looked at the code inside this render function, so I have no idea what a 'sheet' is, but the code looks like it has the potential to add more verts to the buffer than were allocated initially... and that is exactly what is happening in my case since when I hit that assert there are two sheets trying to be rendered.
In case it matters, the code is asserting when trying to render a GuiMLTextCtrl. The text shows up, but it is garbled (it looks like, you guessed it, messed up verts).
Also, occationally, there are 0 sheets (mSheets.size() == 0), but there is no early-out in the function for this case since mLength is still 1. It will still create a buffer for 6 verts (mLength * 6) but it won't fill the buffer with anything and won't actually render anything.
Anyway, it looks like there might be some gremlins in this code that someone who knows more about this stuff than me should take a look at. Otherwise, maybe let me know if I am using this code incorrectly...
Stephane
The assert looks like the following:
AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!");
This seems like a reasonable assert to me, but there is definitely something wonky with the code just above the assert.
The code is allocating a vertex buffer big enough for mLength * 6 verts (the number of characters in the string * 6 verts):
GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile);
The for loop then adds 6 verts per character per sheet! I only looked at the code inside this render function, so I have no idea what a 'sheet' is, but the code looks like it has the potential to add more verts to the buffer than were allocated initially... and that is exactly what is happening in my case since when I hit that assert there are two sheets trying to be rendered.
In case it matters, the code is asserting when trying to render a GuiMLTextCtrl. The text shows up, but it is garbled (it looks like, you guessed it, messed up verts).
Also, occationally, there are 0 sheets (mSheets.size() == 0), but there is no early-out in the function for this case since mLength is still 1. It will still create a buffer for 6 verts (mLength * 6) but it won't fill the buffer with anything and won't actually render anything.
Anyway, it looks like there might be some gremlins in this code that someone who knows more about this stuff than me should take a look at. Otherwise, maybe let me know if I am using this code incorrectly...
Stephane
About the author
Torque 3D Owner Stephane Conde
This code doesn't actually delete (or zero-out) the first element in the array inside the mSheets vector. The call to Vector
This means that on a subsequent batched font render pass we can run into problems because mSheets[0] will not be NULL and furthermore will actually point to valid memory! For example, if only mSheets[1] is used on the next pass, but mSheets[0] is still valid then the batched font render will try to render too many vertices for a single piece of text (the exact issue I was seeing).
I'm not sure if I've come up with the best solution to this issue, but this should work to replace the above code:
This will zero-out the array in the mSheets vector first so that the next time we queue up characters to be batch rendered mSheets[0] will get re-allocated. We also clear the vector so that it doesn't think it has any valid sheets and we free all of the blocks in the DataChunker so that we don't have any memory leaks.
This solution seemed the most straight-forward, kept everything as index-based (rather than having to loop through the mSheets vector to find the sheet you want) and required very few changes. Please let me know if you have any better solutions though.
Cheers,
Stephane