optimization for repeated textures in GuiBitmapCtrl
by Orion Elenzil · 05/13/2008 (2:39 pm) · 1 comments
This resource provides a new function in the dglDraw family, dglDrawFullBitmapRepeating(), and modifies GuiBitmapCtrl to take advantage of it when possible.
dglDrawFullBitmapRepeating() is substantially faster than dglDrawBitmapRepeating() when the number of tiles is large.
i tested an 8x8 image being tiled on an area about 1000 x 500, and saw my framerate drop from about 300 to about 80 FPS.
with the implementation here, the framerate impact of the same operation is well within the noise margin.
This resource is based on a TGE 1.3 codebase, so it's possible this has already been fixed in some later version.
All the code additions are presented below, but familiarity with C++ programming as assumed.
Commentary:
Unfortunately this optimization is only possible for bitmaps who are a power of two.
This is because bitmaps which are not a power of two are actually padded inside a texture which is,
so in that case, you would end up drawing the padding as well.
There may be more modern version of OpenGL which allow you to provide a texel stride for repeating textures, but i wouldn't know about that.
The modification here detects acceptable textures and uses the fast code where it can, and the slow code where it can't,
so it's backward compatible with existing assets.
The original implementation of GuiBitmapCtrl also re-implements dglDrawBitmapRepeating(),
so i've changed it here to not do that.
dgl.h,
after the declaration of dglDrawBitmapRepeating(), but before the "/// @}" add:
dgl.cc,
after the implementation of dglDrawBitmapStretchSR(), add:
guiBitmapCtrl.cc
in GuiBitmapCtrl::onRender(),
change this:
dglDrawFullBitmapRepeating() is substantially faster than dglDrawBitmapRepeating() when the number of tiles is large.
i tested an 8x8 image being tiled on an area about 1000 x 500, and saw my framerate drop from about 300 to about 80 FPS.
with the implementation here, the framerate impact of the same operation is well within the noise margin.
This resource is based on a TGE 1.3 codebase, so it's possible this has already been fixed in some later version.
All the code additions are presented below, but familiarity with C++ programming as assumed.
Commentary:
Unfortunately this optimization is only possible for bitmaps who are a power of two.
This is because bitmaps which are not a power of two are actually padded inside a texture which is,
so in that case, you would end up drawing the padding as well.
There may be more modern version of OpenGL which allow you to provide a texel stride for repeating textures, but i wouldn't know about that.
The modification here detects acceptable textures and uses the fast code where it can, and the slow code where it can't,
so it's backward compatible with existing assets.
The original implementation of GuiBitmapCtrl also re-implements dglDrawBitmapRepeating(),
so i've changed it here to not do that.
dgl.h,
after the declaration of dglDrawBitmapRepeating(), but before the "/// @}" add:
/// Draws a complete texture repeating. substantially faster than dglDrawBitmapRepeating. /// Orion Elenzil 20080513 /// @param texObject texture object to be drawn /// @param in_rDest rectangle where the texture object will be drawn void dglDrawFullBitmapRepeating(TextureObject* texture, const RectI& dstRect);
dgl.cc,
after the implementation of dglDrawBitmapStretchSR(), add:
void dglDrawFullBitmapRepeating(TextureObject* texture, const RectI& dstRect)
{
AssertFatal(texture != NULL, "dglDrawBitmapRepeatingPow2: NULL Handle");
if(!dstRect.isValidRect())
return;
glDisable(GL_LIGHTING);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, texture->texGLName);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_REPEAT );
glTexParameteri(GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_REPEAT );
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
F32 texLeft = 0.0f;
F32 texTop = 0.0f;
F32 texRight = (F32)(dstRect.extent.x) / (F32)(texture->texWidth );
F32 texBottom = (F32)(dstRect.extent.y) / (F32)(texture->texHeight);
F32 screenLeft = (F32)(dstRect.point.x );
F32 screenTop = (F32)(dstRect.point.y );
F32 screenRight = (F32)(dstRect.point.x + dstRect.extent.x);
F32 screenBottom = (F32)(dstRect.point.y + dstRect.extent.y);
glColor4ub(sg_bitmapModulation.red,
sg_bitmapModulation.green,
sg_bitmapModulation.blue,
sg_bitmapModulation.alpha);
glBegin(GL_TRIANGLE_FAN);
glTexCoord2f(texLeft , texBottom );
glVertex2f (screenLeft , screenBottom);
glTexCoord2f(texRight , texBottom );
glVertex2f (screenRight, screenBottom);
glTexCoord2f(texRight , texTop );
glVertex2f (screenRight, screenTop );
glTexCoord2f(texLeft , texTop );
glVertex2f (screenLeft , screenTop );
glEnd();
glDisable(GL_BLEND);
glDisable(GL_TEXTURE_2D);
}guiBitmapCtrl.cc
in GuiBitmapCtrl::onRender(),
change this:
if(mWrap)
{
<re-implementation of dglDrawBitmapRepeating()>
}to this:if(mWrap)
{
TextureObject* texture = (TextureObject *) mTextureHandle;
RectI dstRegion;
if ((texture->texWidth == texture->bitmapWidth) && (texture->texHeight == texture->bitmapHeight))
{
// FAST!
dstRegion.set(offset, mBounds.extent);
dglDrawFullBitmapRepeating(texture, dstRegion);
}
else
{
// SLOW!
// note for code clarity this should be changed into a single call to dglDrawBitmapRepeating,
// but i had some off-by-one issues with my first pass, so just using the original code for now.
RectI srcRegion;
float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1;
int xshift = startPoint.x%texture->bitmapWidth;
int yshift = startPoint.y%texture->bitmapHeight;
for(int y = 0; y < ydone; ++y)
for(int x = 0; x < xdone; ++x)
{
srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight);
dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift,
((texture->bitmapHeight*y)+offset.y)-yshift,
texture->bitmapWidth,
texture->bitmapHeight);
dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
}
}
}About the author

Associate Orion Elenzil
Real Life Plus