ofxFBOTexture: trouble copying texture to a member variable

In the test app pasted below, i have trouble drawing an ofxFBOTexture if it’s a copy of another ofxFBOTexture.

In testApp.cpp, the circle texture draws as expected if i call draw() directly on the ofxFBOTexture being returned by myCircle.get_texture(). The circle also draws as expected if i copy the returned texture to a local variable and draw that. But if i try to copy the returned texture to a member variable of testApp first (myMemberTexture), and then try to draw that, i get a white square instead of the exptected circle.

Can anyone see what’s going wrong here?

  
// tcircle.h ----------------------------------------------------  
#ifndef _TCIRCLE  
#define _TCIRCLE  
  
#include "ofMain.h"  
#include "ofxFBOTexture.h"  
  
class tcircle {  
	public :  
	tcircle ();  
	ofxFBOTexture get_texture();  
	int size;  
};  
#endif  
  
// tcircle.cpp -----------------------------------------------------  
#include "tcircle.h"  
tcircle::tcircle() : size(10) {  
}  
  
ofxFBOTexture tcircle::get_texture(){  
	ofxFBOTexture t;  
	t.allocate(size*2, size*2, true);  
	t.swapIn();  
	t.setupScreenForMe();  
	ofCircle(size, size, size);  
	t.swapOut();  
	t.setupScreenForThem();  
	return(t);  
}  
  
// testApp.h ----------------------------------------------------------------  
#ifndef _TEST_APP  
#define _TEST_APP  
#include "ofMain.h"  
#include "ofxFBOTexture.h"  
#include "tcircle.h"  
class testApp : public ofBaseApp{  
	public:  
		void setup();  
		void draw();  
		tcircle myCircle;  
		ofxFBOTexture myMemberTexture;  
};  
#endif  
  
// testApp.cpp --------------------------------------------------------------  
#include "testApp.h"  
void testApp::setup(){  
	myMemberTexture.allocate(20,20,true);  
}  
void testApp::draw(){  
	//draws the circle texture as expected  
	myCircle.get_texture().draw(0, 0);  
	  
	//draws the circle texture as expected  
	ofxFBOTexture myTempTexture=myCircle.get_texture();  
	myTempTexture.draw(20,0);  
	  
	//When i try to copy the texture to a member variable,  
	//drawing it results in a white square, why?  
	myMemberTexture=myCircle.get_texture();  
	myMemberTexture.draw(40,0);   
}  
  

Hmm. not sure what is going on…this is a bit weird. Maybe someone else can tell me what’s happening here. I think it may involve the fact that copying to myMemberTexture creates some temporary variable while myTempTexture gets constructed directly using the return value of get_texture().

I think however if you return the FBO by reference you should get the result you want.
i.e.

  
ofxFBOTexture & tcircle::get_texture()  

Ok I think I figured it out…

When you do this in get_texture():

  
return(t);  

you are calling the copy constructor of the object because it is returning by value.

Since the FBO class has not overridden the copy constructor, the copy constructor of ofTexture is called.

Step 1
Now, when you return by value to a new object like this

  
ofxFBOTexture myTempTexture=myCircle.get_texture();  

due to compiler return value optimizations, no temporary object is created. Instead, the FBO returned is copied into myTempTexture. At the end of the draw function, this temporary FBO will be destroyed and it’s destructor called.

Step 2
However, when you return by value to an object that has already been initialized/instantiated, then a temporary object is created during the copy. What happens then is that this object is destructed after the assignment.

Every time a temporary FBO class is destroyed, whether through Step 1 (myTempTexture variable goes out of scope) or Step 2 (temporary variable destructed), the ofTexture destructor is called (because the FBO class has not overridden it). The code for the ofTexture destructor is like this:

  
  
ofTexture::~ofTexture(){  
	clear();  
}  
  
void ofTexture::clear(){  
	if (texData.textureName[0] != 0){  
		glDeleteTextures(1, (GLuint *)texData.textureName);  
	}  
  
	texData.bAllocated = false;  
}  
  

So basically the temporary FBO texture is deleted, which is also the same texture as the one in the myCircle class. The difference in Step 2 is that the texture is deleted after the assignment and before the draw() call, which is why you see nothing.

So one solution is to return by reference (as in my last post), however when myTempTexture goes out of scope, your FBO texture (in myCircle) will still be deleted so you will have to redraw into the FBO every frame (which is what you are doing now).

The other solution is to implement a proper copy constructor for the FBO class which creates a new texture upon copy.

Hope this is not too confusing…

Actually, you shouldn’t need to create a copy constructor for the FBO class…this is actually an error in ofTexture. A new texture should be created in the constructor of the ofTexture class.
I’m going to file a bug report.

Thanks very much for your investigations grimus. I have to admit that much of this is more advanced than my knowledge can make sense of at the moment :slight_smile: I’m glad you were able to find the problem.

Oh, one last thing!

It’s not a good idea to do this:

  
  
 myCircle.get_texture().draw(0, 0);  
  

because by calling get_texture() and returning by value the ofxFBOTexture you create a temporary variable (which is unecessary because you are not assigning it to anything).

Better to do this:

  
 myCircle.draw(0, 0);  

and then in the tcircle class define this:

  
    void draw(int x, int y)  
    {  
        t.draw(x,y);  
    }  

then define t as a class member variable instead of a local variable in the get_texture() function:

  
   ofxFBOTexture t;  

Yes, That makes sense. Thanks!

Hi,

I think I have a similar problem like this described at http://forum.openframeworks.cc/t/weird-fbo-filling-problem/2659/0

I implented an draw function in my class file, but still have the problem. Maybe I need to modify the copy constructor in FBO like suggested, but I’m very confused how this should look like. Can anybody hint me in the right direction?

Thanks!