Hi!
I experience some weird behaviour when rendering a BakedFont object in OpenGL.
I have written some code that uses stbtt_truetype's BakedFont in order to render a String with the specified font.
However, for days I have been trying to solve a very weird issue when it comes to the ByteBuffers.
The code below works fine. It does not crash or do anything else crazy.
However, if I add
stbtt_FreeBitMap(ttf)
after the
stbtt_BakeFontBitmap(...)
call - it crashes.
The same thing occurs if I free the bitmap object after the
glTexImage2D(...)]
call.
Not only this, but it also crashes if I remove the ByteBuffer ttf as a parameter into the Font object.
Basically, it seems like the ttf object has be kept alive in order for it to NOT crash.
Just to be clear, it does not crash in the creating process - but rather during the rendering process.
I can't see any visible flaws in my code (but there must be... because it crashes), and I have difficulties understanding the crash report from Java.
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffe7c96829a, pid=9772, tid=17808
This tells me that I access memory that is NULL (I guess?). This makes be believe that the program tries to access the data
after it has been removed.
Here is a pastebin link to the full crash report:
https://pastebin.pl/view/aa818779The creating process:/** Creates a Font object with a fixed size from a path to a .ttf file.
* @param path - the path to the .ttf file.
* @param fontSize - the size in pixels
* @return the generated Font object that is needed upon rendering.
*/
@SuppressWarnings("unused")
public Font loadFont(final String path, final int fontSize) {
//Convert .ttf file to data we can deal with, that being a ByteBuffer.
ByteBuffer ttf = Resources.loadFileAsByteBuffer(path);
STBTTFontinfo info = STBTTFontinfo.create();
if(ttf == null || !STBTruetype.stbtt_InitFont(info,ttf)) {
throw new IllegalStateException("Failed to initialize font information. Check the log for exact reason.");
}
try (MemoryStack stack = stackPush()) {
IntBuffer pAscent = stack.mallocInt(1);
IntBuffer pDescent = stack.mallocInt(1);
IntBuffer pLineGap = stack.mallocInt(1);
stbtt_GetFontVMetrics(info, pAscent, pDescent, pLineGap);
}
//Capacity is the ASCII max
STBTTBakedChar.Buffer charData = STBTTBakedChar.malloc(215);
int bitmapWidth = fontSize * 16;
int bitmapHeight = fontSize * 16;
ByteBuffer bitmap = BufferUtils.createByteBuffer(bitmapWidth * bitmapHeight);
stbtt_BakeFontBitmap(ttf, fontSize, bitmap, bitmapWidth, bitmapHeight, 32, charData);
int texId = glGenTextures();
glBindTexture(GL_TEXTURE_2D, texId);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R,GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G,GL_ONE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B,GL_ONE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, bitmapWidth, bitmapHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap);
glBindTexture(GL_TEXTURE_2D, 0);
Texture2D texture2D = new Texture2D(texId, bitmapWidth, bitmapHeight);
return new Font(fontSize,ttf,info,charData,texture2D);
}
This returns a Font object. This contains the information that we want to keep until later. Such as the STBTTFontInfo.
The rendering process/** Draws a string with a specified font,color and transform to the screen.
*
* @param font - the Font object. This contains necessary information regarding the font that is used during rendering.
* @param text - the string that is to be rendered.
* @param color - the RGBA color.
* @param transform - the Matrix4f transform.
*/
public void drawText(final Font font, final String text, final Vector4f color,
final Matrix4f transform) {
FloatBuffer x = BufferUtils.createFloatBuffer(1),y = BufferUtils.createFloatBuffer(1);
STBTTAlignedQuad q = STBTTAlignedQuad.create();
for(int i = 0; i < text.length(); i++) {
stbtt_GetBakedQuad(font.getCharData(), font.getBitmapWidth(), font.getBitMapHeight(), text.charAt(i) - 32,
x, y, q, false);
Vertex[] vertices = new Vertex[]{
new Vertex(new Vector2f( q.x0(), q.y0()), color, transform, new Vector2f(q.s0(), q.t0()),
font.getTexture2d().getRenderSlot()),
new Vertex(new Vector2f(q.x1(), q.y0()), color, transform, new Vector2f(q.s1(), q.t0()),
font.getTexture2d().getRenderSlot()),
new Vertex(new Vector2f(q.x1(), q.y1()), color, transform, new Vector2f(q.s1(), q.t1()),
font.getTexture2d().getRenderSlot()),
new Vertex(new Vector2f(q.x0(), q.y1()), color, transform, new Vector2f(q.s0(), q.t1()),
font.getTexture2d().getRenderSlot())
};
DefaultModel model = new DefaultModel(vertices, quadIndices);
batchRenderer.addToDrawCall(model, font.getTexture2d(), defaultShader);
}
This renders a String with the created font. A Vertex object simply contains the following data: (Vector2f pos, Vector4f color, Matrix4f transform, Vector2f textureCoords).
These vertices are then put into a Model object which is then inserted into a batch rendering system. All the batches are drawn at the end of each render call.
Does anyone know why it crashes? If so, how can I modify my code to make it stop? I tried using getCodePointBitmap(...) but it crashes as well.
If you need additional information, feel free to ask!
Thanks in advance
