GFXDrawUtil::drawBitmapTiledSR: draw a tile fill from a bitmap section (TGEA 1.7.1)
by Jaimi McEntire · 01/28/2009 (7:03 am) · 1 comments
This is a function you can add to GFXDrawUtil that will tile a rectangle from a source rectangle in a texture. This is used by several of my other GUI Controls. Pass the texture, the destination rectangle on the screen, and the source rectangle in the texture. I have tested this on various nVidia and ATI chipsets and did not see any texture artifacts. I will add a port to 1.8.X when I get around to porting to the newer version (afx is ported, 1.8.1 is released, etc.)
In gfxDrawUtil.h, add the following declaration after the declaration for drawBitmapStretchSR:
In gfxDrawUtil.cpp, add the function itself after the drawBitmapStretchSR function:
This function differs from "doing it manually" by setting the texture and render states only one time.
In gfxDrawUtil.h, add the following declaration after the declaration for drawBitmapStretchSR:
void drawBitmapTiledSR( GFXTextureObject*texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None );
In gfxDrawUtil.cpp, add the function itself after the drawBitmapStretchSR function:
void GFXDrawUtil::drawBitmapTiledSR( GFXTextureObject*texture, const RectI &dstRect,
const RectI &srcRect, const GFXBitmapFlip in_flip)
{
// Sanity if no texture is specified.
if(!texture)
return;
int xreps = dstRect.extent.x / srcRect.extent.x;
if (xreps * srcRect.extent.x != dstRect.extent.x) xreps++; // add one for the remainder, if any.
int yreps = dstRect.extent.y / srcRect.extent.y;
if (yreps * srcRect.extent.y != dstRect.extent.y) yreps++; // add one for the remainder, if any.
mDevice->setBaseRenderState();
GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile );
// Calculate the source coordinates
// Set all the device properties one time.
mDevice->setCullMode( GFXCullNone );
mDevice->setLightingEnable( false );
mDevice->setAlphaBlendEnable( true );
mDevice->setSrcBlend( GFXBlendSrcAlpha );
mDevice->setDestBlend( GFXBlendInvSrcAlpha );
mDevice->setTextureStageColorOp( 0, GFXTOPModulate );
mDevice->setTextureStageColorOp( 1, GFXTOPDisable );
mDevice->setTexture( 0, texture );
mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );
// calculate the right and bottom edge of the destination.
int TexW = srcRect.extent.x;
int TexH = srcRect.extent.y;
int ScreenMaxX = dstRect.point.x + dstRect.extent.x;
int ScreenMaxY = dstRect.point.y + dstRect.extent.y;
for (int xx = 0; xx<xreps; xx++)
{
for (int yy=0; yy<yreps; yy++)
{
// TODO: Calculate dest rect.
// TODO: Adjust src rect if it's too large for whats left.
// Get the location on the screen for this rep.
int dstLeft = dstRect.point.x + (xx * TexW);
int dstRight = dstLeft + TexW;
int dstTop = dstRect.point.y + (yy * TexH);
int dstBottom = dstTop + TexH;
// Adjust the source and destination rectangles to fit in the dstRect.
int WidthAdjust = 0;
int HeightAdjust = 0;
if (dstRight > ScreenMaxX)
{
WidthAdjust = dstRight - ScreenMaxX;
dstRight = ScreenMaxX;
}
if (dstBottom > ScreenMaxY)
{
HeightAdjust = dstBottom - ScreenMaxY;
dstBottom = ScreenMaxY;
}
// Calculate the position on the screen for this rep.
F32 screenLeft = (F32)dstLeft;
F32 screenRight = (F32)dstRight;
F32 screenTop = (F32)dstTop;
F32 screenBottom = (F32)dstBottom;
// Calculate the position in the source texture for this rep. We need to do this every time, because there is
// most likely an end rep where we are only moving part of the source.
F32 texLeft = F32(srcRect.point.x)
/ F32(texture->mTextureSize.x);
F32 texRight = F32((srcRect.point.x + srcRect.extent.x)-WidthAdjust)
/ F32(texture->mTextureSize.x);
F32 texTop = F32(srcRect.point.y)
/ F32(texture->mTextureSize.y);
F32 texBottom = F32((srcRect.point.y + srcRect.extent.y)-HeightAdjust)
/ F32(texture->mTextureSize.y);
if( in_flip & GFXBitmapFlip_X )
{
F32 temp = texLeft;
texLeft = texRight;
texRight = temp;
}
if( in_flip & GFXBitmapFlip_Y )
{
F32 temp = texTop;
texTop = texBottom;
texBottom = temp;
}
const F32 fillConv = mDevice->getFillConventionOffset();
verts.lock();
verts[0].point.set( screenLeft - fillConv, screenTop - fillConv, 0.f );
verts[1].point.set( screenRight - fillConv, screenTop - fillConv, 0.f );
verts[2].point.set( screenLeft - fillConv, screenBottom - fillConv, 0.f );
verts[3].point.set( screenRight - fillConv, screenBottom - fillConv, 0.f );
verts[0].color = verts[1].color = verts[2].color = verts[3].color = mBitmapModulation;
verts[0].texCoord.set( texLeft, texTop );
verts[1].texCoord.set( texRight, texTop );
verts[2].texCoord.set( texLeft, texBottom );
verts[3].texCoord.set( texRight, texBottom );
verts.unlock();
mDevice->setVertexBuffer( verts );
mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
}
}
mDevice->setAlphaBlendEnable( false );
}This function differs from "doing it manually" by setting the texture and render states only one time.
About the author
Recent Blogs
• Replicator Updates for TGEA 1.8.1• GuiLensFlareHud - Lens flares and white out for TGEA 1.8.1
• fxGenericObject for TGEA 1.8.1
• GuiStatusCtrl - *Updated* Display Field Name, Values, Status Bar for any field or method on any named object. TGEA and (new! TGE 1.52)
• Bitmap Channel Embedder
Associate Jaimi McEntire
King of Flapjacks