Rotating Images
by Robert Fritzen · in Torque 3D Beginner · 01/06/2014 (11:23 am) · 6 replies
So I've decided to give T3D pack development another spin (pun intended for my question) and I can't seem to find anything in the GFX codebase on rotating texture objects (namely gui bitmap controls).
Does anyone know how I can go about rotating bitmap images for usage in GUIs, I need this for a little "toy" I've been working on.
Does anyone know how I can go about rotating bitmap images for usage in GUIs, I need this for a little "toy" I've been working on.
About the author
Illinois Grad. Retired T3D Developer / Pack Dev.
#2
I believe the problem lies with Matrix::MulP, seeing as TexCoord, the coordinates I need to "rotate" is in a Point2F form where as mulP requires a Point3F. I'm not trying to rotate the control, but the image inside the control.
The reason this is a problem is because Matrix Multiplication is obviously handled on a row by row basis and simply defining a zero in the 3rd coordinate probably won't work. Any suggestions?
01/23/2014 (7:56 am)
I seem to be having more of a problem with this than I originally imagined. I've got the code written in a point that it "seems" like it should work, but the problem here is that upon performing the call to the code, it just renders a gray block, and no parts of the image in question whatsoever.void drawRotatableBitmap(GFXTextureObject* texture, const RectF &dstRect, const RectF &srcRect, F32 spinAngle) {
// Sanity if no texture is specified.
if(!texture) {
return;
}
Point3F offset( dstRect.point.x, dstRect.point.y, 0.0 ), temp;
GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, 4, 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);
const F32 fillConv = GFX->getFillConventionOffset(); //mDevice->getFillConventionOffset();
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 );
ColorI modulation;
GFX->getDrawUtil()->getBitmapModulation(&modulation);
verts[0].color = verts[1].color = verts[2].color = verts[3].color = modulation;
verts[0].texCoord.set( texLeft, texTop );
verts[1].texCoord.set( texRight, texTop );
verts[2].texCoord.set( texLeft, texBottom );
verts[3].texCoord.set( texRight, texBottom );
if (spinAngle == 0.0f) {
for( S32 i = 0; i < 4; i++ ) {
verts[i].texCoord += offset.asPoint2F();
}
}
else {
MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
for( S32 i = 0; i < 4; i++ ) {
temp.set(verts[i].texCoord.x, verts[i].texCoord.y, 0.0f);
rotMatrix.mulP( temp );
//temp now contains the multiplied vertex coords, set accordingly and apply offset
verts[i].texCoord.x = temp.x;
verts[i].texCoord.y = temp.y;
verts[i].texCoord += offset.asPoint2F();
}
}
verts.unlock();
GFX->setVertexBuffer( verts );
// Define the state block for the GFX mode.
GFXStateBlockDesc bitmapStretchSR;
bitmapStretchSR.setCullMode(GFXCullNone);
bitmapStretchSR.setZReadWrite(false);
bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
bitmapStretchSR.samplersDefined = true;
bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
GFXStateBlockRef mBitmapStretchLinearSB = GFX->createStateBlock(bitmapStretchSR);
GFX->setStateBlock(mBitmapStretchLinearSB);
GFX->setTexture( 0, texture );
GFX->setupGenericShaders( GFXDevice::GSModColorTexture );
GFX->drawPrimitive( GFXTriangleStrip, 0, 2 );
}I believe the problem lies with Matrix::MulP, seeing as TexCoord, the coordinates I need to "rotate" is in a Point2F form where as mulP requires a Point3F. I'm not trying to rotate the control, but the image inside the control.
The reason this is a problem is because Matrix Multiplication is obviously handled on a row by row basis and simply defining a zero in the 3rd coordinate probably won't work. Any suggestions?
#3

Using this function call:
Actual implementation:
The second drawRotatableBitmap function only exists to pretty much match GDXDrawUtil::drawBitmap() function with the addition of the rotation angle parameter. Enjoy!
01/23/2014 (10:36 pm)
I got it all fixed and working for you shown with this screenshot drawing some icons in my text list control:Using this function call:
drawRotatableBitmap(bitmap->texture, bmPos, GFXBitmapFlip_None, GFXTextureFilterPoint, true, mDegToRad(-90.0f));
Actual implementation:
void drawRotatableBitmap(GFXTextureObject* texture, const RectF &dstRect, const RectF &srcRect, F32 spinAngle)
{
// Sanity if no texture is specified.
if(!texture)
return;
GFXDevice *mDevice = GFX;
GFXVertexColor mBitmapModulation = ColorI( 255, 255, 255, 255 );
GFXVertexBufferHandle<GFXVertexPCT> verts(mDevice, 4, 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);
const F32 fillConv = mDevice->getFillConventionOffset();
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 );
if(spinAngle != 0.f)
{
MatrixF rotMatrix( EulerF( 0.0, 0.0, spinAngle ) );
Point3F offset( dstRect.point.x + dstRect.extent.x / 2,
dstRect.point.y + dstRect.extent.y / 2,
0.0f);
for( S32 i = 0; i < 4; i++ )
{
verts[i].point -= offset;
rotMatrix.mulP( verts[i].point );
verts[i].point += offset;
}
}
verts.unlock();
mDevice->setVertexBuffer( verts );
// Define the state block for the GFX mode.
// DrawBitmapStretchSR
GFXStateBlockDesc bitmapStretchSR;
bitmapStretchSR.setCullMode(GFXCullNone);
bitmapStretchSR.setZReadWrite(false);
bitmapStretchSR.setBlend(true, GFXBlendSrcAlpha, GFXBlendInvSrcAlpha);
bitmapStretchSR.samplersDefined = true;
// Linear: Create clamp SB
bitmapStretchSR.samplers[0] = GFXSamplerStateDesc::getClampLinear();
GFXStateBlockRef mBitmapStretchLinearSB = mDevice->createStateBlock(bitmapStretchSR);
mDevice->setStateBlock(mBitmapStretchLinearSB);
mDevice->setTexture( 0, texture );
mDevice->setupGenericShaders( GFXDevice::GSModColorTexture );
mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );
}
void drawRotatableBitmap(GFXTextureObject* texture, const Point2I &in_rAt, const GFXBitmapFlip in_flip, const GFXTextureFilterType filter , bool in_wrap /*= true*/, F32 spinAngle /*= 0.0f*/)
{
AssertFatal( texture != 0, "No texture specified for drawBitmap()" );
RectF subRegion( 0.0f, 0.0f, (F32)texture->mBitmapSize.x, (F32)texture->mBitmapSize.y );
RectF stretch( (F32)in_rAt.x, (F32)in_rAt.y, (F32)texture->mBitmapSize.x, (F32)texture->mBitmapSize.y );
drawRotatableBitmap( texture, stretch, subRegion, spinAngle );
}The second drawRotatableBitmap function only exists to pretty much match GDXDrawUtil::drawBitmap() function with the addition of the rotation angle parameter. Enjoy!
#4
EDIT: Here's to show what I'm "up to" per say. :)
I've got to fix the math calculations a little bit, and a few more renders are needed, but overall, this is good progress to me.
Because My Picture is Too Big
01/24/2014 (8:11 am)
And it's reasons like this that I just love this community. Thanks a bunch, you saved me a ton of time trying to figure that out.. :xEDIT: Here's to show what I'm "up to" per say. :)
I've got to fix the math calculations a little bit, and a few more renders are needed, but overall, this is good progress to me.
Because My Picture is Too Big
#5
I'm still trying to get the minimap resource to render more than a gray box, and keep it from crashing when I open the GUI editor... lol
01/24/2014 (10:41 am)
Ah, the ol' rotating minimap....I'm still trying to get the minimap resource to render more than a gray box, and keep it from crashing when I open the GUI editor... lol
#6
Also, since I'm doing pack spoilers right now, I thought I'd share this little thing I made earlier:
Shiny Eye Candy.
All I can say, is this pack is likely to be the most exciting and resourceful one I've made to date.
01/24/2014 (10:45 am)
@Richard: This is not the mini-map resource, It's one I'm writing myself for my new pack, using nothing more than mathematical distance calculations :)Also, since I'm doing pack spoilers right now, I thought I'd share this little thing I made earlier:
Shiny Eye Candy.
All I can say, is this pack is likely to be the most exciting and resourceful one I've made to date.
Torque Owner Nathan Martin
TRON 2001 Network