Transparency Mask for GUI objects
by Aldavidson · in Torque 3D Professional · 09/08/2009 (11:09 am) · 8 replies
Hi guys,
Does T3D support a transparency mask for GUI objects?
I'm in the process of creating my overview GUI object, and im wondering what the best aproach is to get the gui object to display in the shape that i want it too.
Below is a screenshot that demonstrates what im trying to acheive:

Im trying to exclude anything with the blue lines over it from being rendered (or atleast shown). The best aproach i came up with was to use a transparency mask on the GUI object but i dont know if that is supported by T3D or if their is an alternative method?
Any help guys?
Does T3D support a transparency mask for GUI objects?
I'm in the process of creating my overview GUI object, and im wondering what the best aproach is to get the gui object to display in the shape that i want it too.
Below is a screenshot that demonstrates what im trying to acheive:

Im trying to exclude anything with the blue lines over it from being rendered (or atleast shown). The best aproach i came up with was to use a transparency mask on the GUI object but i dont know if that is supported by T3D or if their is an alternative method?
Any help guys?
#2
Unfortunately my Background (and most other textures seen on the hud) are being rendered with GFXDrawUtil::drawBitmapRotCtr...
I'm not sure how on earth to get from this stage of having a rotated texture being displayed on screen to getting it only rendered in a circle.... (alas i have no clue on how to use your code with my needs).
Is it possible to somehow "cut-out" a circle shaped set of verts from the 4 verts produced from drawBitmapRotCtr and then display that?
Any help?
12/22/2009 (8:10 pm)
Hi Ryan, Thanks for your input so far.Unfortunately my Background (and most other textures seen on the hud) are being rendered with GFXDrawUtil::drawBitmapRotCtr...
void GFXDrawUtil::drawBitmapRotCtr(GFXTextureObject *texture,const RectI& dstRect,const RectI& srcRect,const GFXBitmapFlip in_flip,F32 spinAngle, const Point2F spinOffset, F32 X, F32 Y)
{
if(!texture)
return;
GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, GFXBufferTypeVolatile );
verts.lock();
F32 texLeft = F32(srcRect.point.x) / F32(texture->mTextureSize.x);
F32 texRight = F32(srcRect.point.x + srcRect.extent.x) / F32(texture->mTextureSize.x);
F32 texTop = F32(srcRect.point.y) / F32(texture->mTextureSize.y);
F32 texBottom = F32(srcRect.point.y + srcRect.extent.y) / 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;
}
// spin angle is in degree's so convert to radians..radians = degrees * pi /180
spinAngle = spinAngle * 3.14 / 180.0f;
Point2F screenPoint(X,Y);
F32 width = dstRect.extent.x;
width *= 0.5;
MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
Point3F offset( screenPoint.x, screenPoint.y, 0.0 );
//const F32 fillConv = mDevice->getFillConventionOffset();
verts[0].point.set( -width + spinOffset.x, -width + spinOffset.y, 0.0 );
verts[1].point.set( -width + spinOffset.x, width + spinOffset.y, 0.0 );
verts[2].point.set( width + spinOffset.x, width + spinOffset.y, 0.0 );
verts[3].point.set( width + spinOffset.x, -width + spinOffset.y, 0.0 );
verts[0].color = verts[1].color = verts[2].color = verts[3].color = mBitmapModulation;
verts[0].texCoord.set( texLeft, texTop );
verts[1].texCoord.set( texLeft, texBottom );
verts[2].texCoord.set( texRight, texBottom );
verts[3].texCoord.set( texRight, texTop );
for( int i=0; i<4; i++ )
{
rotMatrix.mulP( verts[i].point );
verts[i].point += offset;
}
verts.unlock();
mDevice->setVertexBuffer( verts );
mDevice->setStateBlock(mBitmapStretchSB);
mDevice->setTexture( 0, texture );
mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );
mDevice->drawPrimitive(GFXTriangleFan, 0, 2 );
}I'm not sure how on earth to get from this stage of having a rotated texture being displayed on screen to getting it only rendered in a circle.... (alas i have no clue on how to use your code with my needs).
Is it possible to somehow "cut-out" a circle shaped set of verts from the 4 verts produced from drawBitmapRotCtr and then display that?
Any help?
#3
12/22/2009 (10:01 pm)
It should be possible to create a hybrid of the two to accomplish what you need. I'm in the middle a project at the moment but I will see if I can put something together.
#4
12/23/2009 (7:29 am)
Thanks alot Ryan, I'll continue to give this a stab as well.
#5
I'm just trying to determine how you are aligning your image. If the image is already set up when it comes into the method above then that makes it a bit easier. If the image needs to be rotated in the function that complicates it a little.
12/31/2009 (4:25 pm)
@Aldavidson, from the image above I am assuming you are using a camera to take an overhead image in real time. Does the image rotate with the player or does it always stay in a fixed orientation? If it rotates with the player are you rotating the camera to match the players rotation before you collect the image?I'm just trying to determine how you are aligning your image. If the image is already set up when it comes into the method above then that makes it a bit easier. If the image needs to be rotated in the function that complicates it a little.
#6
int gfxDrawUtil.cpp add:
Use that instead of your function and you should be good to go. Let me know if you have any questions.
12/31/2009 (6:18 pm)
Ok, I think I may have what you need. In gfxDrawUtil.h add this:void GFXDrawUtil::drawDisk(const Point2I ¢er, const ColorI &color, F64 outerRadius, F32 spinAngle, GFXTextureObject *texture);
int gfxDrawUtil.cpp add:
void GFXDrawUtil::drawDisk(const Point2I ¢er, const ColorI &color, F64 outerRadius, F32 spinAngle, GFXTextureObject *texture);
void GFXDrawUtil::drawDisk(const Point2I ¢er, const ColorI &color, F64 outerRadius, F32 spinAngle, GFXTextureObject *texture)
{
//This is the number of segments in the disk
S32 slices = 48;
//This is the start angle for the disk
F64 startAngle = 0;
//This is the final angle for the disk
F64 sweepAngle = 360;
//This is the number of loops only one is supported
S32 loops = 1;
//Define our state blocks
GFXStateBlockDesc mDiskBitmapTexture;
GFXStateBlockRef diskBitmapTextureSB;
mDiskBitmapTexture.setCullMode(GFXCullNone);
mDiskBitmapTexture.zEnable = false;
mDiskBitmapTexture.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
mDiskBitmapTexture.samplersDefined = true;
mDiskBitmapTexture.samplers[0].textureColorOp = GFXTOPModulate;
mDiskBitmapTexture.samplers[1].textureColorOp = GFXTOPDisable;
diskBitmapTextureSB = GFX->createStateBlock(mDiskBitmapTexture);
GFXStateBlockDesc mDiskNoBitmapTexture;
GFXStateBlockRef noDiskBitmapTextureSB;
mDiskNoBitmapTexture.setCullMode(GFXCullNone);
mDiskNoBitmapTexture.zEnable = false;
mDiskNoBitmapTexture.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
noDiskBitmapTextureSB = GFX->createStateBlock(mDiskNoBitmapTexture);
//Set up the texture
GFX->setTexture(0, texture);
//Determine which state blocks to use
if (!texture){
PrimBuild::color4i(color.red,color.green,color.blue,color.alpha);
GFX->setStateBlock(noBitmapTextureSB);
GFX->setupGenericShaders( GFXDevice::GSColor );
}
else{
F32 newAlpha = color.alpha/255.0f;
PrimBuild::color4f(1, 1, 1, newAlpha);
GFX->setStateBlock(bitmapTextureSB);
GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
}
//Define our variables for rendering coordinates
F32 sinCache[48], cosCache[48];
F32 angle, radiusLow;
F32 texLow, angleOffset;
GFX->pushWorldMatrix();
MatrixF t(true);
t.setPosition( Point3F( center.x, center.y, 0 ) );
GFX->multWorld( t );
/* Cache is the vertex locations cache */
angleOffset = startAngle / 180.0 * M_PI;
S32 i;
for (i = 0; i <= slices; i++)
{
angle = angleOffset + ((M_PI * sweepAngle) / 180.0) * i / slices;
sinCache[i] = mSin(angle);
cosCache[i] = mCos(angle);
}
//Make sure we end where we started
sinCache[slices] = sinCache[0];
cosCache[slices] = cosCache[0];
// spin angle is in degree's so convert to radians..radians = degrees * pi /180
spinAngle = spinAngle * 3.14 / 180.0f;
MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
//Begin rendering the disk
/* Triangle strip for inner polygons */
PrimBuild::begin(GFXTriangleFan,(slices * loops) + 2);
PrimBuild::texCoord2f(0.5, 0.5);
PrimBuild::vertex3f(0.0, 0.0, 0.0);
radiusLow = outerRadius;
texLow = radiusLow / outerRadius / 2;
for (i = slices; i >= 0; i--){
//Plot the texture and vertex coordinates
Point3F ptTexCoord((texLow * sinCache[i] + 0.5), (texLow * cosCache[i] + 0.5), 0.0);
Point3F ptVertexCoord(radiusLow * sinCache[i], radiusLow * cosCache[i], 0.0);
//Rotate the vertex coordinate
rotMatrix.mulP( ptVertexCoord );
//Send to the PrimBuilder
PrimBuild::texCoord2f(ptTexCoord.x, ptTexCoord.y);
PrimBuild::vertex3f(ptVertexCoord.x, ptVertexCoord.y, ptVertexCoord.z);
}
//This causes the disk to be rendered
PrimBuild::end();
GFX->popWorldMatrix();
}Use that instead of your function and you should be good to go. Let me know if you have any questions.
#7
Ryan, thanks for that snippet! Today I was wondering how to solve the same problem, and your idea set me in the right direction. So I wanted to share my solution in exchange.
It's compatible with T3D 1.1 Final and works just like the rest of the drawBitmap... functions. The width and height of the disc is set by the width and height of the destination rectangle. You can specify a texture for it. Only the part covered by the circle will be displayed. (We use a large pre-drawn minimap that has only a given area displayed at a time underneath a circular compass)
It is hardwired to work with 48 fans (or slices) to give you a smooth circular shape.
Add this to gfxDrawUtil.cpp:
...and don't forget the header file:
Thanks again, hope this comes handy for someone.
Edit: work in progress shot of the thing...

11/07/2011 (7:35 am)
Sorry for necroing this thread.Ryan, thanks for that snippet! Today I was wondering how to solve the same problem, and your idea set me in the right direction. So I wanted to share my solution in exchange.
It's compatible with T3D 1.1 Final and works just like the rest of the drawBitmap... functions. The width and height of the disc is set by the width and height of the destination rectangle. You can specify a texture for it. Only the part covered by the circle will be displayed. (We use a large pre-drawn minimap that has only a given area displayed at a time underneath a circular compass)
It is hardwired to work with 48 fans (or slices) to give you a smooth circular shape.
Add this to gfxDrawUtil.cpp:
void GFXDrawUtil::drawBitmapStretchSRDisk( GFXTextureObject *texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/ )
{
RectF dstRectF = RectF((F32)dstRect.point.x,(F32)dstRect.point.y,(F32)dstRect.extent.x,(F32)dstRect.extent.y);
RectF srcRectF = RectF((F32)srcRect.point.x,(F32)srcRect.point.y,(F32)srcRect.extent.x,(F32)srcRect.extent.y);
drawBitmapStretchSRDisk(texture,dstRectF,srcRectF,in_flip,filter,in_wrap);
}
void GFXDrawUtil::drawBitmapStretchSRDisk(GFXTextureObject* texture, const RectF &dstRect, const RectF &srcRect, const GFXBitmapFlip in_flip /*= GFXBitmapFlip_None*/, const GFXTextureFilterType filter /*= GFXTextureFilterPoint */ , bool in_wrap /*= true*/)
{
if (!texture)
return;
S32 fans = 48;
GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, fans+2, GFXBufferTypeVolatile );
verts.lock();
F32 texLeft = (srcRect.point.x) / (texture->mTextureSize.x);
F32 texRight = (srcRect.point.x + srcRect.extent.x) / (texture->mTextureSize.x);
F32 texTop = (srcRect.point.y) / (texture->mTextureSize.y);
F32 texBottom = (srcRect.point.y + srcRect.extent.y) / (texture->mTextureSize.y);
F32 screenLeft = dstRect.point.x;
F32 screenRight = (dstRect.point.x + dstRect.extent.x);
F32 screenTop = dstRect.point.y;
F32 screenBottom = (dstRect.point.y + dstRect.extent.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();
Point2F screenRadii = Point2F((screenRight - screenLeft) / 2, (screenBottom - screenTop) / 2);
Point2F texRadii = Point2F((texRight - texLeft) / 2, (texBottom - texTop) / 2);
verts[0].point.set( screenLeft + screenRadii.x - fillConv, screenTop + screenRadii.y - fillConv, 0.f ); // fan center
verts[0].color = mBitmapModulation;
verts[0].texCoord.set( texLeft + texRadii.x, texTop + texRadii.y); // fan texture center
// fans number of points around the center point
F64 angle;
for (S32 v=0;v<=fans;v++) {
angle = v * (360.0f / fans) * M_PI_F / 180.0f; // in radians
verts[v+1].point.set( screenLeft + (screenRadii.x * (1 + mSin(angle))) - fillConv, screenTop + (screenRadii.y * (1 - mCos(angle))) - fillConv, 0.f);
verts[v+1].color = mBitmapModulation;
verts[v+1].texCoord.set( texLeft + texRadii.x * (1 + mSin(angle)), texTop + (texRadii.y * (1 - mCos(angle))) );
}
verts.unlock();
mDevice->setVertexBuffer( verts );
switch (filter)
{
case GFXTextureFilterPoint :
mDevice->setStateBlock(in_wrap ? mBitmapStretchWrapSB : mBitmapStretchSB);
break;
case GFXTextureFilterLinear :
mDevice->setStateBlock(in_wrap ? mBitmapStretchWrapLinearSB : mBitmapStretchLinearSB);
break;
default:
AssertFatal(false, "No GFXDrawUtil state block defined for this filter type!");
mDevice->setStateBlock(mBitmapStretchSB);
break;
}
mDevice->setTexture( 0, texture );
mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );
mDevice->drawPrimitive( GFXTriangleFan, 0, fans );
}...and don't forget the header file:
void drawBitmapStretchSRDisk(GFXTextureObject* texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None, const GFXTextureFilterType filter = GFXTextureFilterPoint, bool in_wrap = true ); void drawBitmapStretchSRDisk(GFXTextureObject* texture, const RectF &dstRect, const RectF &srcRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None, const GFXTextureFilterType filter = GFXTextureFilterPoint, bool in_wrap = true );
Thanks again, hope this comes handy for someone.
Edit: work in progress shot of the thing...

#8
11/07/2011 (2:04 pm)
Konrad, glad you necroed this! =) That is something I've been needing as well. Thanks!
Torque Owner Ryan Mick
Red Witch Entertainment
center: the center point to start drawing the disk on the screen.
color: Any color modulation you want to apply.
innerRadius: Use this to create a hollow disk or doughnut.
outerRadius: How big to make the disk.
slices: the number of segments that makes up the disk, the more segments the smoother the disk. I use 3 for every 90 degrees.
loops: The number of inner segments usually leave at 1.
startAngle: The angle to start rendering the disk at.
sweepAngle: How much of the disk to draw. use 360 for a complete disk.
texture: The texture to draw onto the disk.
Hopefully that helps point you in the right direction. Let me know if you need anything else.