Game Development Community

Trying to Implement drawBitmapRotated in TGEA

by Jorge Luis Gandulfo · in Torque Game Engine Advanced · 05/21/2008 (9:38 am) · 8 replies

Since the Speedometer GUI don't work by default, i was checking old resources, and still Speedometer in TGEA displays the needle as a drawed box.
So i was planning in resurrect and old resource i modified long ago to draw a bitmap spin.

My problem is the dlg.h don't exist anymore, and i used to put a function there to do the rotation trick.

Now i ported my old resource to TGEA, i just need this function to be working, i placed it on gfxDrawUtil.

If anybody can help me finish the rotation part of the function i will release an updated TGEA resource, sorry for asking this, but im pretty newbie in TGEA still, and my math skills seems to be affected by the vodka i been drinking all this years :).

Here is the function i added in gfxDrawUtil.ccp (copy paste from drawBitmapStretchSR)

void GFXDrawUtil::drawBitmapRotated( GFXTextureObject *texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip, F32 Angle, const Point2F Offset ) 
{
   // Sanity if no texture is specified.
   if(!texture)
      return;

   mDevice->setBaseRenderState();

   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);

   F32 screenLeft   = (F32)dstRect.point.x;
   F32 screenRight  = (F32)(dstRect.point.x + dstRect.extent.x);
   F32 screenTop    = (F32)dstRect.point.y;
   F32 screenBottom = (F32)(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();
   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;

[b]
   //Apply Offset
   texLeft = texLeft + Offset.x;
   texRight = texRight + Offset.x;
   texTop = texTop + Offset.y;
   texBottom = texBottom + Offset.y;
   //Apply Offset
[/b]

   verts[0].texCoord.set( texLeft,  texTop );
   verts[1].texCoord.set( texRight, texTop );
   verts[2].texCoord.set( texLeft,  texBottom );
   verts[3].texCoord.set( texRight, texBottom );

[b]
   //Apply Rotation
   // angle is in degree's so convert to radians..radians = degrees * pi /180
   Angle = Angle * 3.14 / 180.0f;
   MatrixF rotMatrix( EulerF( 0.0, 0.0, Angle ) );
   for( int i=0; i<4; i++ )
   {
      rotMatrix.mulP( verts[i].point );
   }
[/b]

   verts.unlock();

   mDevice->setVertexBuffer( verts );

   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 );

   mDevice->drawPrimitive( GFXTriangleStrip, 0, 2 );

   mDevice->setAlphaBlendEnable( false );
}


I added the following in gfxDrawUtil.h

void drawBitmapRotated( GFXTextureObject*texture, const RectI &dstRect, const RectI &srcRect, const GFXBitmapFlip in_flip = GFXBitmapFlip_None ,F32 Angle = 0, const Point2F Offset = Point2F(0,0) );

#1
05/21/2008 (11:26 am)
I have a working drawBitmapRotated, but the code is currently at home. I'll post it up when I get home this evening, if someone doesn't get something up sooner...
#2
05/21/2008 (6:32 pm)
Ok, here is my draw rotated:

void GFXDrawUtil::drawBitmapRotated(GFXTextureObject *texture,const RectI& dstRect,const RectI& srcRect,const U32 in_flip,F32 spinAngle, const Point2F spinOffset)
{
	if(!texture)
      return;

   mDevice->setBaseRenderState();

   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);

   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;
   }

	F32 X = 0;

   // calculate the centroid of the rectangle (to use as rotation pivot)
   if (screenLeft < screenRight)
   {
        X = screenLeft + ((screenRight - screenLeft)*0.5f);
   }
   else
   {
        X = screenRight + ((screenLeft - screenRight)*0.5f);
   };

   F32 Y = 0;

   if (screenTop < screenBottom)
   {
        Y = screenTop + ((screenBottom - screenTop)*0.5f);
   }
   else
   {
        Y = screenBottom + ((screenTop - screenBottom)*0.5f);
   };
   
   // 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->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 );

   mDevice->drawPrimitive(GFXTriangleFan, 0, 2 );

   mDevice->setAlphaBlendEnable( false );
}

The above is working for what I'm using it for...
#3
05/21/2008 (7:46 pm)
Thanks a lot for your help, i'm still having a problem, but at least i know this code wasn't it, seems both functions (the one i wrote and the one you did) are giving the same results, so i might be doing something wrong when i'm calling this function, so at least i won't waste my time anymore on this, anyway im adopting your function for now just in case :)

Thanks again
#4
05/21/2008 (8:47 pm)
I had to mess around with how I was passing the angle values from script, it appears to reset itself at around 100 degrees, so I did the following:

if($fovRotating > 0 && $fovRotating < 100 )
	{
		$fovRotating = ($fovRotating + 0.1);
	}
	else if ($fovRotating < 0 && $fovRotating > -100)
	{
	   $fovRotating = ($fovRotating + 0.1);
	}
	else
	{
	   if($fovRotating > 0)
	       $fovRotating = 0.01;
           else
               $fovRotating = -0.01;
	}

I have my image rotating 360 degrees, and the above code works with the function as it is above..
#5
05/21/2008 (9:18 pm)
Im getting Weird results, after checking it better, i have 4 needles being diplaying instead of one if i use this Rotate Function, thats really weird to be honest (1 Needle is displayed in each corner of what appers to be an invisible BITMAP BOX, that rotates but with this error)

The code im using to call this function is this:

code from ( GuiMeterCtrl::onRender(Point2I offset, const RectI &updateRect) )

...

	RectI Bounds;
	Bounds = getBounds();
	// Center of widget
	Point2F half(Bounds.extent.x / 2  - 1,Bounds.extent.y / 2 - 1); 

	// Make center the UI object's coordinate center 
	half.x += offset.x; 
	half.y += offset.y; 

	// Draw frame
	if(mTextureObject) {
		//dglSetBitmapModulation(mColor);
		GFX->getDrawUtil()->setBitmapModulation(mColor);
		Point2I texSize(mTextureObject->getWidth(), mTextureObject->getHeight() );
		Point2I corner(half.x - mTextureObject->getWidth()/2, half.y - mTextureObject->getHeight()/2); 
		RectI srcRegion(0,0,mTextureObject->getWidth(),mTextureObject->getHeight()); 
		RectI dstRect(corner, texSize);
	    //dglDrawBitmapStretchSR(mTextureObject, dstRect, srcRegion, false);
		GFX->getDrawUtil()->drawBitmapStretchSR(mTextureObject, dstRect, srcRegion);
	}

	// Draw Spin
	if(mMeterSpin) {
		F32 ang = mAngle * (mSpinAng.y - mSpinAng.x) / 100.0 + mSpinAng.x;
		Point2I texSize(mTextureObject->getWidth() , mTextureObject->getHeight() );
		Point2I corner(half.x - mTextureObject->getWidth() /2 + mSpinOffset.x, half.y - mTextureObject->getHeight() /2 +mSpinOffset.y); 
		RectI srcRegion(0,0, mTextureObject->getWidth(), mTextureObject->getHeight() ); 
		RectI dstRect(corner, texSize);
[B]
	    GFX->getDrawUtil()->drawBitmapRotated(mMeterSpin, dstRect, srcRegion, GFXBitmapFlip_None, ang, mSpinBitmapOffset);
[/B]	}

..

In really Lost on what i could be doing wrong, since this is somehow a port of a code that WOrked on TGE.

THis is the resource im trying to port here
#6
05/22/2008 (6:43 am)
I started from the same resource... Here is my onRender:

if  ( ( mValueType == GuiMeterValueTypeSpeed ) ^ ( mValueType == GuiMeterValueTypeEnergy ) )
{
   // Must have a connection and player control object
   GameConnection* conn = GameConnection::getConnectionToServer();
   if (!conn)
      return;

   Vehicle* control = dynamic_cast<Vehicle*>(conn->getControlObject());
   if (!control || !(control->getType() & VehicleObjectType))
     return;
		
   if ( mValueType == GuiMeterValueTypeEnergy )
   {
      mValue = control->getEnergyLevel();//getEnergyValue();
   }

   if ( mValueType == GuiMeterValueTypeSpeed )
   {
      mValue = control->getVelocity().len();
   }

   if (mValue > mMaxValue)
   {
      mValue = mMaxValue;
   }
}

if ( !mInvert )
{
   mAngle = mMinAngle + (mMaxAngle - mMinAngle) * (mValue / mMaxValue);
}
else
{
   mAngle = mMaxAngle - (mMaxAngle - mMinAngle) * (mValue / mMaxValue);
}

// Center of widget
Point2F half(getBounds().extent.x / 2  - 1, getBounds().extent.y / 2 - 1); 

// Make center the UI object's coordinate center 
half.x += offset.x; 
half.y += offset.y; 

// Take back the tecture handle for spin and frame
GFXTextureObject* spin = (GFXTextureObject *) mMeterSpin;	
GFXTextureObject* frame = (GFXTextureObject *) mTextureHandle;

// Draw frame
if(frame) 
{
   GFX->getDrawUtil()->setBitmapModulation(mColor);
   Point2I texSize(frame->getBitmapWidth(), frame->getBitmapHeight() );
   Point2I corner(half.x-frame->getBitmapWidth() / 2, half.y-frame->getBitmapHeight() / 2); 
   RectI srcRegion(0,0,frame->getBitmapWidth(), frame->getBitmapHeight()); 
   RectI dstRect(corner, texSize);
   GFX->getDrawUtil()->drawBitmapStretchSR(frame, dstRect, srcRegion);
}

// Draw Spin
if(spin) 
{
   GFX->getDrawUtil()->clearBitmapModulation();
   F32 ang = mAngle * (mSpinAng.y - mSpinAng.x) / 100.0 + mSpinAng.x;
   Point2I texSize(spin->getBitmapWidth(), spin->getBitmapHeight() );
   Point2I corner(half.x-spin->getBitmapWidth() / 2 + mSpinOffset.x, half.y-spin->getBitmapHeight() / 2 + mSpinOffset.y); 
   RectI srcRegion(0, 0, spin->getBitmapWidth(), spin->getBitmapHeight()); 
   RectI dstRect(corner, texSize);
   if(mAdditive)
      GFX->getDrawUtil()->drawBitmapRotatedAdd(spin, dstRect, srcRegion, false, ang, mSpinBitmapOffset);
   else
      GFX->getDrawUtil()->drawBitmapRotated(spin, dstRect, srcRegion, false, ang, mSpinBitmapOffset);
}

renderChildControls(offset, updateRect);
#7
05/22/2008 (10:15 am)
Thanks a lot Eric i'm testing it now and works great, i will upload it tonight as a resource, if you didn't already do that.
#8
05/22/2008 (10:51 am)
Glad it's working, no I haven't put it up as a resource, so feel free to...