Game Development Community

dev|Pro Game Development Curriculum

T3D 1.2 - Image Modulation

by Robert Fritzen · 09/27/2012 (9:23 pm) · 1 comments

So, a while back I asked about in-game image coloration. I was pointed in the direction of using the GFXDrawUtil class' setImageModulation function to accomplish this and some sample code was provided. Unfortunately the sample code that I was provided is no longer there, and since I'm almost certain someone will be looking for a function like this at some point, I've decided to put up what I have recently re-coded and have functioning in my own copy of T3D 1.2

open GuiBitmapCtrl.h: (note, when I use .'s it indicated lines of code, just skip down to the relevant parts, I indicate those lines/sections with comments)

/// Renders a bitmap.
class GuiBitmapCtrl : public GuiControl
{
   .
   .
   .
   protected:
   .
      /// Loaded texture.
      GFXTexHandle mTextureObject;      

      //Phantom139: Added Here
      ColorI mImageModulation; 
   .
   .
   public:
   .
   .
      void setBitmapHandle(GFXTexHandle handle, bool resize = false);

      //Phantom139: Added
      void setImageColor(ColorI c);
      void deleteImageColor();
      ColorI getImageColor();
      //Phantom139: end   
   .
   .
};

This will add our new information to the class, now let's get it in the engine, open guiBitmapCtrl.cpp and make the following additions/changes:

change the constructor definition like so:
GuiBitmapCtrl::GuiBitmapCtrl(void)
 : mBitmapName(),
   mStartPoint( 0, 0 ),
   mWrap( false ),
   mImageModulation(0, 0, 0, 0)
{	
}

Add this line after the other fields in initPersistFields:
addField( "imageColor", TypeColorI, Offset( mImageModulation, GuiBitmapCtrl), 
         "Color modulation to apply to the bitmap.");

And change your definition of onRender to this:
void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
{
   if (mTextureObject)
   {
      GFX->getDrawUtil()->clearBitmapModulation();
      //Phantom139: Added Code
      if(mImageModulation.red == 0 && mImageModulation.green == 0 && mImageModulation.blue == 0 && mImageModulation.alpha == 0) 
      {
         //no modulation set.
      }
      else 
      {
         GFX->getDrawUtil()->setBitmapModulation(mImageModulation);
      }
      //Phantom139: End
      if(mWrap)
      {
         // We manually draw each repeat because non power of two textures will 
         // not tile correctly when rendered with GFX->drawBitmapTile(). The non POT
         // bitmap will be padded by the hardware, and we'll see lots of slack
         // in the texture. So... lets do what we must: draw each repeat by itself:
 			GFXTextureObject* texture = mTextureObject;
			RectI srcRegion;
			RectI dstRegion;
			float xdone = ((float)getExtent().x/(float)texture->mBitmapSize.x)+1;
			float ydone = ((float)getExtent().y/(float)texture->mBitmapSize.y)+1;

			int xshift = mStartPoint.x%texture->mBitmapSize.x;
			int yshift = mStartPoint.y%texture->mBitmapSize.y;
			for(int y = 0; y < ydone; ++y)
				for(int x = 0; x < xdone; ++x)
				{
		 			srcRegion.set(0,0,texture->mBitmapSize.x,texture->mBitmapSize.y);
  					dstRegion.set( ((texture->mBitmapSize.x*x)+offset.x)-xshift,
								      ((texture->mBitmapSize.y*y)+offset.y)-yshift,
								      texture->mBitmapSize.x,
								      texture->mBitmapSize.y);

               GFX->getDrawUtil()->drawBitmapStretchSR(texture,dstRegion, srcRegion, GFXBitmapFlip_None, GFXTextureFilterLinear);
				}

		}
		else
      {
         RectI rect(offset, getExtent());
         GFX->getDrawUtil()->drawBitmapStretch(mTextureObject, rect, GFXBitmapFlip_None, GFXTextureFilterLinear, false);
      }
      //Phantom139: Clear Bitmap Modulation...
      GFX->getDrawUtil()->clearBitmapModulation();
   }

   if (mProfile->mBorder || !mTextureObject)
   {
      RectI rect(offset.x, offset.y, getExtent().x, getExtent().y);
      GFX->getDrawUtil()->drawRect(rect, mProfile->mBorderColor);
   }

   renderChildControls(offset, updateRect);
}

Lastly we add some functions to the console to get and set the image modulation:
//Phantom139: Added Some New Stuffs!
void GuiBitmapCtrl::setImageColor(ColorI c) {
	mImageModulation.set(c, c.alpha);
	setUpdate();
}

void GuiBitmapCtrl::deleteImageColor() {
   mImageModulation.set(255, 255, 255, 255);
	setUpdate();
}

ColorI GuiBitmapCtrl::getImageColor() {
   return mImageModulation;
}

DefineEngineMethod(GuiBitmapCtrl, deleteImageColor, void, (),, "(void) Removes image modulation") {
   object->deleteImageColor();
}

DefineEngineMethod(GuiBitmapCtrl, setImageColor, void, (int r, int g, int b, int a),, 
						 "Set the image modulation color for this control, see ImageModulation var.") {
   ColorI newCol(r, g, b, a);
	object->setImageColor(newCol);
}

DefineEngineMethod(GuiBitmapCtrl, getImageColor, const char *, (),, "(void)") {
	ColorI modulation = object->getImageColor();
	char output[8]; //8 bits (U8 Type)
	std::string final;
	//
	_itoa(modulation.red, output, 10);
	final = output;
	strcpy(output, "");
	_itoa(modulation.green, output, 10);
	final.append(" ");
	final.append(output);
	strcpy(output, "");
	_itoa(modulation.blue, output, 10);
	final.append(" ");
	final.append(output);
	strcpy(output, "");
	_itoa(modulation.alpha, output, 10);
	final.append(" ");
	final.append(output);
	strcpy(output, "");

   char *str = Con::getReturnBuffer(final.size() +1);  
   dStrcpy(str, final.c_str());  
	return str;
}

And there you go! In game image modulation. I hope you like it, and if you have any changes to submit, or catch any of my silly programmatic errors, please fix them... fixes here benefit everyone else!

Enjoy!