request for ofTexture 006

I know you guys have a lot on your plate and probably loads of todo’s for the new oF release, but I thought I’d post a little request for some changes to ofTexture (this was discussed a while ago, but maybe forgotten :P).
http://forum.openframeworks.cc/t/using-a-single-texture-for-multiple-objects/858/0

Some of the functionality mentioned in that thread can be done by extending/wrapping ofImage in an ofxSprite - which I’m happy to do - but to be able to do that some minor changes need to be done to ofTexture. Unfortunately I cannot add this functionality by extending ofTexture because an ofTexture is embedded into ofImage. So I would have to extend ofTexture and then rewrite ofImage if I wanted to use these methods. They are completely transparent to the user and 100% backwards compatible so should cause no problems.

The enableTextureTarget/bind/unbind/disableTextureTarget can be a massive bottleneck if you want to draw the same image a few thousand times (22fps vs 35fps for 15K draws).

Also the bind()/unbind() methods give the possibility of using alternative drawing methods in the future, e.g. if you have a few thousand instances want to draw using VBO’s and not using the ofImage/ofTexture draw at all, you can just bind() the ofTexture, then send your VBO and bob’s yer uncle.

(I know there have been some major changes to ofTexture with a pixels struct, so this code might not be accurate anymore, but you get the jist of it)

  
  
public:  
       void bind();  
	void unbind();  
	void quickDraw(float x, float y);  
	void quickDraw(float x, float y, float w, float h);  
	void drawQuad();  
	int getWidth();  
	int getHeight();  
	float getInvWidth();  
	float getInvHeight();  
  
protected:  
	float invWidth, invHeight;	  
	GLfloat	tx0, ty0, tx1, ty1;  
	GLint	        px0, py0, px1, py1;  
  
  

  
  
void ofTexture::bind() {  
	glEnable(textureTarget);  
	glBindTexture(textureTarget, (GLuint)textureName[0] );  
}  
  
  
  
void ofTexture::unbind() {  
	glDisable(textureTarget);  
	glBindTexture(textureTarget, 0);  
}  
  
  
  
// translates to the desired position and scales to desired size, then draws a quad (without binding and unbinding)  
void ofTexture::quickDraw(float x, float y, float w, float h) {  
	glPushMatrix();  
	glTranslatef(x, y, 0);  
	glScalef(w * invWidth, h * invHeight, 1.0f);  
	if (ofGetRectMode() == OF_RECTMODE_CENTER) glTranslatef(-width * 0.5f, -height * 0.5f, 0);  
  
	drawQuad();  
  
	glPopMatrix();  
}  
  
  
  
void ofTexture::quickDraw(float x, float y) {  
	quickDraw(x, y, width, height);  
}  
  
  
  
// draws a single quad with the correct dimenions and texture coordinates  
void ofTexture::drawQuad() {  
	// tx0, px0 etc. calculations are in allocate();  
	glBegin( GL_QUADS );  
		glTexCoord2f(tx0,ty0);			glVertex3i(px0, py0,0);  
		glTexCoord2f(tx1,ty0);			glVertex3i(px1, py0,0);  
		glTexCoord2f(tx1,ty1);			glVertex3i(px1, py1,0);  
		glTexCoord2f(tx0,ty1);			glVertex3i(px0, py1,0);  
	glEnd();  
}  
  
  
  
// functionality is already divided into different functions  
// so no need to duplicate code, this can just call the new functions  
void ofTexture::draw(float x, float y, float w, float h){		  
	bind();  
	quickDraw(x, y, w, h);  
	unbind();  
}  
  
  
  
void ofTexture::allocate(...) {  
	....  
	....  
  
	// precalculate these here as drawQuad needs them.  
	px0 = 0;  
	py0 = 0;  
	px1 = (GLint)width;  
	py1 = (GLint)height;  
  
	if (bFlipTexture == true){  
		GLint temp = py0;  
		py0 = py1;  
		py1 = temp;  
	}  
  
	GLfloat offsetw = 0;  
	GLfloat offseth = 0;  
  
	if (textureTarget == GL_TEXTURE_2D){  
		offsetw = 1.0f/(tex_w);  
		offseth = 1.0f/(tex_h);  
	}  
	// -------------------------------------------------  
  
	tx0 = 0+offsetw;  
	ty0 = 0+offseth;  
	tx1 = tex_t - offsetw;  
	ty1 = tex_u - offseth;  
		  
	invWidth = 1.0f/ width;	  
	invHeight = 1.0f / height;  
}  
  
  

I think the new ofTexture will have half of what you are looking for:

bind and unbind

but I don’t think it will have alternative drawing methods. for that, you can extend the class and add your own. (drawFast, drawWithDisplayLists, drawPolygon, etc). The reason is to keep ofTexture simple. Also, as per that conversation, all objects in the core that have textures will be able to pass back their internal texture, so you can do what you want with it, like bind and unbind, etc.

hope that helps – trying to find the right balance between flexible, powerful and simple.

take care!
zach

actually, on second thought, Im not that opposed to separating out the drawing routines as you’ve described.

the only worry is that beginners will get confused, so it’s got be very clear that drawing without binding will produce strange and unpredictable results unless you know what you are doing.

I think maybe it should be called drawCurrentlyBoundTexture() or something less promising then drawFast :wink:

there are a few things I’m still not sure about in the above code:

a) if using matrix operations per draw is going to be a bottleneck (seems like it)
b) if there is some pain in the overhead of having so many function calls per draw

for now, we might consider a simple bind, unbind and drawWithBoundTexture and normal draw() but you can feel free to jump in and extend or modify the texture to draw as you like.

  • zach

Hi Zach, I hear you on the drawFast thing. And yea that could be confusing. I’d be happy if you gave it a long scary name with comments saying ‘only use this if you know what you are doing’ :P.

I really spent a lot of time trying to do the ofxSprite thing with a minimum of changes to ofTexture and that was the minimum I could come up with. For the performance gain, all that tx0, ty0, px0 etc. needs to be precalculated. And obviously should not be public as people don’t wanna see that stuff. But then we need the ofTexture::drawQuad(), because an ofxSprite would not be able to access the protected properties of its texture - so that one is pretty essential.

Originally I didn’t have the quickDraw() in ofTexture and had it all in ofxSprite (as long as ofTexture has drawQuad its enough), but it didn’t seem logical to copy paste all the code from ofTexture::draw into ofxSprite. If ofImage gets optimized so should ofxSprite. And it does aid the readability of the code actually for draw() - { bind(); drawCurrentlyBoundTexture(); unbind(); }

I think with grouped comments (basic functions vs advanced functions) it should be clear to the user.

P.S. One thing just occurred to me :

if you dont like the drawQuad() or drawCurrentlyBoundTexture() being in ofTexture, one alternative could be that all the precalculated { tx0, ty0, tx1, ty1, px0, py0, px1, py1, width, height, invWidth, invHeight, } could be stored in a struct in oxTexture. And drawQuad and drawCurrentlyBoundTexture could be global functions which accept a reference to that struct. This kind of makes more sense maybe, because they dont actually draw the texture in ofTexture - which I guess is why you’re not keen on it.

So thinking about it, maybe that makes more sense? ofTexture creates a struct which the global functions ofDrawQuadWithCurrentBoundTexture() and ofDrawCurrentlyBoundTexture() use (for advanced uses)… and still has its own draw() methods to encapsulate all of that (for simple use)?

just a quick note –

And obviously should not be public as people don’t wanna see that stuff. But then we need the ofTexture::drawQuad(), because an ofxSprite would not be able to access the protected properties of its texture - so that one is pretty essential.

if it’s protected and not private, then a class that extends can access it -

I really like the idea of an accessible (yet private/protected) struct to organize that info – and to keep minimal the amount of functions:

draw();
bind();
unbind();
drawWithBoundTexture();

I’m not sure I understand the difference here:

ofDrawQuadWithCurrentBoundTexture() and ofDrawCurrentlyBoundTexture()

are these different functions?

thanks for all the input!
zach

HI Zach,

if it’s protected and not private, then a class that extends can access it -

Sure, but unfortunately the problem is that even if I extend ofTexture to ofxAdvancedTexture; ofxSprite would be extending ofImage, which is hardcoded to use an ofTexture… not the ofxAdvancedTexture… and you see the dilemma…

The protected struct idea is growing on me too, as long as we have a public getTextureInfo() or something :stuck_out_tongue:

regarding the 2 functions, i had split the functionality in two:
ofDrawQuadWithCurrentBoundTexture()
just draws an untransformed quad at 0,0 with no scale but the correct texture coordinates and size

ofDrawCurrentlyBoundTexture()
translates to the desired position and scale and then draws the quad (Calls the above function)

I found it easier to do it this way because then I could use the drawQuad separately whenever needed (e.g. for displayLists etc.). Splitting this into 2 functions isn’t essential I think, as long as we have public access to the struct with all the data then we can do whatever we want…

perhaps this can be solved with:

http://forum.openframeworks.cc/t/how-about-a-bindtexture-method-on-the-image-object/996/0

Don’t know for sure if it’s the same. If not, perhaps having some method to pass the texture that is used by ofImage or an aditional constructor with the ofTexture to use can be useful for this cases

Hi, don’t know if this discussion is still on for 06 but anyway,

I just made textureName, textureTarget and tex_t, tex_u public in ofTexture in order to draw video on quads. Since ofVideoplayer uses ofTexture extending ofTexture doesn’t work unless ofVideoPlayer is also extended…

If bind() and unbind() were in ofTexture I wouldn’t have had to make these properties public. But I’m thinking that it might be both simpler and more flexible to have getters for these properties instead of having bind()/unbind() and quickDraw() etc? That way advanced users have the power to do any opengl stuff they want and beginners wouldn’t be tempted to start using unnecessary bind() and unbind() calls… The getters would be perfectly safe for beginners and I think most ppl who need more than what draw() has to offer are wiling to deal with opengl directly and don’t need the convenience of bind()/unbind()… What do you think?

//e

this has been a topic of alot of discussion, because people do really want to bind and unbind by hand, but we want to keep textures simple for beginners.

we’ve talked about having passing back a struct with all necessary texture info (target, id, etc) that advanced people could then go to and bind(), unbind() etc.

we’re adding also getTexture() to all OF objects that have a texture, so that you can say, myImage.getTexture().getTexInfo().id, etc…

how does that sound?

take care!
zach

That sounds great :slight_smile:

// e