Drawing ofTrueTypeFont to ofTexture then to screen - without opaque background?

In order to improve performance by avoiding re-drawing ofTrueTypeFont text every frame, I have made a function to draw the text only when the text changes, to an ofTexture, and then I usually draw the ofTexture.

But drawing from the ofTexture drawing an opaque background to the screen along with the text.

How can I get an ofTexture that will just draw the text, with a transparent background?

(I have tried several suggestions from other questions I found here that seemed related, but I always get an opaque background.)

My function so far looks like this:

ofTexture SpaceState::BuildTexture(string forText, ofTrueTypeFont inFont)
{
    ofRectangle boundingBox = inFont.getStringBoundingBox(forText, 0, 0);
    float width = boundingBox.getWidth() + theApp->textHt;
    float height = boundingBox.getHeight() + theApp->textHt;

    if ((forText == "") || (width == 0))
        return ofTexture();

    ofFbo fbo;
    fbo.allocate(width, height, GL_RGBA);

    fbo.begin();
    ofClear(0, 0, 0, 255.0f); // set the background, hopefully to be transparent...
    inFont.drawString(forText, theApp->textHt / 2.0f, inFont.getFirstGlyphPosForTexture(forText, false).y + theApp->textHt * 1.25f);
    fbo.end();

    ofPixels myPixels;
    fbo.readToPixels(myPixels);

    ofTexture Tex;
    Tex.loadData(myPixels, GL_RGBA);

    return Tex;
}

Hmm, also, looking at the result more closely, it also seems like the text is slightly dimmer in color than when drawn to the screen.

Ah, and I KNOW I had tried this before and it didn’t work (and I don’t know what was different then that might have made it not work then), but if I set ofClear(0, 0, 0, 0), then I DO get a transparent background… but I also get text that is then extremely faint.

Ah, ok, this sort of works, but is fainter than drawing on the screen, but at least not extremely faint:

ofClear(255, 255, 255, 0); // set the background, hopefully to be transparent...
ofSetColor(ofColor::white, 255);
inFont.drawString(forText, theApp->textHt / 2.0f,    inFont.getFirstGlyphPosForTexture(forText, false).y + theApp->textHt * 1.25f);

Hey,
right, you need to call ofClear with an alpha value of zero so it is totally transparent.
Also, make sure that you set the color to have no transparency before drawing the font.

1 Like

Thanks Roy!

Yeah, I wish I remember what the code looked like when I tried it with ofClear(0,0,0,0) and it got a black background anyway - that threw my logic off. Ah well.

I also partly figured out what was causing the faint text, though I don’t quite get why. It has to do with the screen resolution or windowed mode versus full screen. That is, in windowed 1024 x 768, I’m seeing the text faded when I draw it on the ofTexture and then draw the ofTexture. But when in full screen 1920 x 1080, it’s just (or very nearly) as bright as when drawn directly.

It’s not a big issue, but here are screenshots showing the difference or lack of difference.

1024 x 768 windowed (ofTexture text is duller, more grey):

1920 x 1080 full screen: (ofTexture text nearly as bright):

Hey I see. There are several things going on when you draw a texture that are different from the “regular” drawing. First try setting the fbo to be 32 bits using GL_RGBA32F_ARB instead of GL_RGBA. Take a look at the example in examples/gl/fbotrails and you’ll see how these bahave differently.
The other thing that might be causing problems is the blend mode. You’ll need to switch between the different blend modes and see whichone works best.

1 Like

Thanks for the information and tips, Roy!

What I have now is good enough for my current needs, but I’ll keep studying this.

Just setting the fbo to GL_RGBA32F_ARB on allocation had different effects depending on what I passed to ofTexture::loadData later.

Tex.loadData(myPixels , GL_RGBA); - like before, but very slightly less bright text.
Tex.loadData(myPixels); - like GL_RGBA
Tex.loadData(myPixels , GL_RGBA32F_ARB); - white background instead of black.

I will check out that example and play with different blend modes to see what happens.

Ohh, sorry, I meant that you should use GL_RGBA32F_ARB for allocating the FBO, not for the texture.

fbo.allocate(width, height, GL_RGBA32F_ARB);

Yep, that’s what I was doing, but I also tried setting the 2nd parameter on ofTexture::loadData, since I wasn’t sure what I was supposed to do with that. At first I assumed maybe they needed to match, but when I set those both to the one you suggested, the background went all white regardless of whether I set ofClear() to black or transparent.

ohh but wait. you are doing a completely unnecessary (and expensive) step. There is no need to read the fbo into pixels and then put those pixels in a texture. The fbo is already a in the GPU memory so you can simply call fbo.getTexture() and store it in the texture object you have.

1 Like

what happens with this:


#pragma once

#include "ofMain.h"

class ofApp : public ofBaseApp{

	public:
		void setup();
		void update();
		void draw();
		ofTexture tex;
	ofTrueTypeFont inFont;
	
		string txt = "Probando probando";
	
	
	void renderText(bool opaqueBg);
};
#include "ofApp.h"


//--------------------------------------------------------------
void ofApp::renderText(bool opaqueBg)
{
	ofRectangle boundingBox = inFont.getStringBoundingBox(txt, 0, 0);
	float width = boundingBox.getWidth() + 10;
	float height = boundingBox.getHeight() + 10;


	  ofFbo fbo;
	  fbo.allocate(width, height, GL_RGBA32F_ARB);

	  fbo.begin();
	  ofClear(0, 0, 0, opaqueBg?255:0.0f); // set the background, hopefully to be transparent...
	  inFont.drawString(txt, 5, 5 - boundingBox.y);
	  fbo.end();

	tex = fbo.getTexture();
}
//--------------------------------------------------------------
void ofApp::setup(){
	inFont.load(OF_TTF_SANS, 30);
	renderText(false);
}

//--------------------------------------------------------------
void ofApp::update(){

}

//--------------------------------------------------------------
void ofApp::draw(){

//	ofBackground(0);
	
	tex.draw(0,0);
	
	inFont.drawString(txt, 5, 220);
}
1 Like

Oh! Ok, I didn’t know I could skip the bitmap step. Great!

Your example code produces identical pure 255 255 255 white in both draws… I’ll try to get my game code to do the same thing . . .

Ok, it doesn’t affect the brightness at the lower resolution with the font I’m using, but that’s ok.

Using OF_TTF_SANS in my game program does end up showing brighter:

I think the scaling of the font is working differently when written into the texture rather than drawn to the screen, a little, and the font I’m using has narrower lines than OF_TTF_SANS, so the effect is more noticeable.

Ive noticed that too. I think it is because of how the transparency is handled. I’ve fixed it in the past but can not recall right now. Although I think that it has been answered several times here in the forum. make an search for “fbo” or “fbo transparency”

Ok, will do. Again, thanks so much for your help!