Game Development Community

dev|Pro Game Development Curriculum

Improved GuiAnimatedBitmapCtrl

by Jeffrey P. Bakke · 03/11/2003 (1:36 pm) · 10 comments

For the Codex Studios C3 project, I need to provide our artists with more advanced GUI elements for the menus, including the ability to provide animations. I started with the original posted GuiAnimatedBitmap. In this version I have removed some redundant code, fixed a problem with the timing intervals to improve playback and added the ability to use the control in a menu and not just on the player HUD.

GuiAnimatedCtrl.h
//-----------------------------------------------------------------------------
// GuiAnimatedBitmapCtrl.h
// Made by Robert Brower
// Modified by Jeff Bakke for C3 command www.c3command.com
//-----------------------------------------------------------------------------
#ifndef _GuiAnimatedBitmapCtrl_H_
#define _GuiAnimatedBitmapCtrl_H_

#ifndef _GUIBITMAPCTRL_H_
#include "gui/guiBitmapCtrl.h"
#endif
#ifndef _MATERIALLIST_H_
#include "dgl/materialList.h"
#endif


class GuiAnimatedBitmapCtrl : public GuiBitmapCtrl
{
private:
	typedef GuiBitmapCtrl Parent;
	

protected:
	bool mIs3d;
	S32		 mInterval;
	S32		 mLastTime;
	S32      mIndex;
	S32      mMaxBitmaps;
	MaterialList	mMaterialList;
	StringTableEntry mDmlFilename;
	StringTableEntry mBitmapNames[30];
	TextureHandle mTextureHandles[30];
		   
public:
	//creation methods
	DECLARE_CONOBJECT(GuiAnimatedBitmapCtrl);
	GuiAnimatedBitmapCtrl();
	static void initPersistFields();
	static void consoleInit();

	//Parental methods
	bool onWake();
	void loadDml();
	void setBitmap(S32 index, const char *name);
	void setIs3d(bool temp);
	void setInterval(F32 temp);
        void onPreRender();
	void onRender(Point2I offset, const RectI &updateRect); 
};

#endif //_GuiAnimatedBitmapCtrl_H_

GuiAnimatedBitmapCtrl.cc
//-----------------------------------------------------------------------------
// GuiAnimatedBitmapCtrl.cc
// Made by Robert Brower
// Changes by Jeff Bakke/Codex Studios
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "gui/guiCanvas.h"

#include "gui/c3/GuiAnimatedBitmapCtrl.h"

IMPLEMENT_CONOBJECT(GuiAnimatedBitmapCtrl);

GuiAnimatedBitmapCtrl::GuiAnimatedBitmapCtrl(void)
{
	mBitmapName = StringTable->insert("");
	mDmlFilename = StringTable->insert("");

	for (int i=0; i<30; i++)
	{
		mBitmapNames[i] = StringTable->insert("");
		mTextureHandles[i] = NULL;
	}
	
	startPoint.set(0,0);
	mWrap = false;
	mIs3d = false;
	mInterval = 0;
	mLastTime = 0;
	mMaxBitmaps = 0;
}

void GuiAnimatedBitmapCtrl::initPersistFields()
{
	Parent::initPersistFields();
	addField("is3d", TypeBool, Offset(mIs3d,GuiAnimatedBitmapCtrl));
	//
	removeField("Bitmap");
	addField("Interval", TypeS32, Offset(mInterval,GuiAnimatedBitmapCtrl));
	addField("DML", TypeFilename, Offset(mDmlFilename,GuiAnimatedBitmapCtrl));
	//
}

static void cAnimatedBitmapSetValue(SimObject *obj, S32, const char **argv)
{
   GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
   ctrl->setValue(dAtoi(argv[2]), dAtoi(argv[3]));
}

static void cAnimatedBitmapSetBitmap(SimObject *obj, S32, const char **argv)
{
   GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
   ctrl->setBitmap(dAtoi(argv[2]), argv[3]);
}

static void cAnimatedBitmapSetIs3d(SimObject *obj, S32, const char **argv)
{
	GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
	ctrl->setIs3d(dAtob(argv[2]));
}

static void cAnimatedBitmapSetFPS(SimObject *obj, S32, const char **argv)
{
	GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
	ctrl->setIs3d(dAtob(argv[2]));
}

void GuiAnimatedBitmapCtrl::consoleInit()
{
	Con::addCommand("GuiAnimatedBitmapCtrl", "setIs3d", cAnimatedBitmapSetIs3d, "GuiAnimatedBitmapCtrl.setIs3d(bool)", 3, 3);
	Con::addCommand("GuiAnimatedBitmapCtrl", "setFPS", cAnimatedBitmapSetFPS, "GuiAnimatedBitmapCtrl.setFPS(F32)", 3, 3);
	//Con::addCommand("GuiAnimatedBitmapCtrl", "setBitmap",  cAnimatedBitmapSetBitmap,   "GuiAnimatedBitmapCtrl.setBitmap(blah)", 3, 3);
	Con::addCommand("GuiAnimatedBitmapCtrl", "setValue",  cAnimatedBitmapSetValue,   "GuiAnimatedBitmapCtrl.setValue(xAxis, yAxis)", 4, 4);
}

void GuiAnimatedBitmapCtrl::setIs3d(bool temp)
{
	mIs3d = temp;
}

void GuiAnimatedBitmapCtrl::setInterval(F32 temp)
{
	mInterval = temp;
}

void GuiAnimatedBitmapCtrl::setBitmap(S32 index, const char *name)
{
   if (index < 0 || index > 29)
	   return;
   
   mBitmapNames[index] = StringTable->insert(name);
   if (*mBitmapNames[index])
      mTextureHandles[index] = TextureHandle(mBitmapNames[index], BitmapTexture, true);
   else
      mTextureHandles[index] = NULL;
   setUpdate();
}

bool GuiAnimatedBitmapCtrl::onWake()
{   
	if (! Parent::onWake())
		return false;
	setActive(true);

	if (dStrlen(mDmlFilename))
		loadDml();
	
	mIndex = 0;
	GuiBitmapCtrl::setBitmap(mTextureHandles[mIndex]);
	mLastTime = Sim::getCurrentTime();
	
	return true;
}

void GuiAnimatedBitmapCtrl::loadDml()
{
   S32 x;
   mMaxBitmaps = 0;      
   Stream *stream = ResourceManager->openStream(mDmlFilename);
   if(stream)
   {
      // match this code to the new sky loading code
      char path[1024], *p;
      dStrcpy(path, mDmlFilename);
      if ((p = dStrrchr(path, '/')) != NULL)
         *p = 0;

      mMaterialList.read(*stream);
      ResourceManager->closeStream(stream);
      mMaterialList.load(path);
      for(x = 0; x < mMaterialList.size(); ++x, ++mMaxBitmaps)
	  {
		  if (x >= 30) break;	
		  mTextureHandles[x] = mMaterialList.getMaterial(x);
	  }
   }
}

void GuiAnimatedBitmapCtrl::onPreRender() 
{
	S32 thisTime = Sim::getCurrentTime();
	S32 timeDelta = thisTime - mLastTime;
	if (timeDelta > mInterval)
	{
		setUpdate();
	}
}


void GuiAnimatedBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) 
{
	S32 thisTime = Sim::getCurrentTime();
	S32 timeDelta = thisTime - mLastTime;
	if (timeDelta > mInterval)
	{
		mIndex ++;
		if (mIndex >= mMaxBitmaps)
			mIndex = 0;
		mLastTime = thisTime;
	}
	if (mTextureHandles[mIndex])
		GuiBitmapCtrl::setBitmap(mTextureHandles[mIndex]);

	//Render the bitmap 
	if (mTextureHandle) 
	{ 
		dglClearBitmapModulation(); 
		if(mWrap) 
		{ 
			TextureObject* texture = (TextureObject *) mTextureHandle; 
			RectI srcRegion; 
			RectI dstRegion; 
			float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
			float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1; 
	
			int xshift = startPoint.x%texture->bitmapWidth; 
			int yshift = startPoint.y%texture->bitmapHeight; 
			for(int y = 0; y < ydone; ++y) 
			for(int x = 0; x < xdone; ++x) 
			{ 
				srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight); 
				
				dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift, 
					((texture->bitmapHeight*y)+offset.y)-yshift, 
						texture->bitmapWidth, 
				texture->bitmapHeight); 
				dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
			} 
		} 
		else 
		{ 
			RectI rect(offset, mBounds.extent); 
			dglDrawBitmapStretch(mTextureHandle, rect); 
		} 
	} 
	else 
	{ 
		RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
		dglDrawRect(rect, mProfile->mBorderColor);
	} 

	// glEnd(); 
	// glDisable(GL_BLEND); 

	// renderChildControls(offset, updateRect);
}

In developing our TGE derived game, we are making an effort to return useful controls, code snippets and other useful tidbits back to the GG community.

Enjoy

Jeff Bakke
Programmer
Codex Studios
Visit C3 Command at www.c3command.com

#1
03/05/2003 (1:12 am)
Very slick, thx for the improvement! :)
Copy/paste screws it up a bit (at least in Mozilla), though, but its only a couple of line breaks and some special chars...
But works great!
#2
03/05/2003 (5:18 am)
I know it is early and I have yet to have a cup of joe, so bare with me.

How are the bitmaps set via script? You have commented out the setBitmap name command and removed the bitmap field.

void GuiAnimatedBitmapCtrl::initPersistFields()
{
...
   removeField("Bitmap");
...
}
void GuiAnimatedBitmapCtrl::consoleInit()
{
  ...
   //Con::addCommand("GuiAnimatedBitmapCtrl", "setBitmap",  cAnimatedBitmapSetBitmap, "GuiAnimatedBitmapCtrl.setBitmap(blah)", 3, 3);
...
}

-Ron
#3
03/05/2003 (9:15 am)
It's using a DML file like the skies and precipitation... :-)

[code]
void GuiAnimatedBitmapCtrl::loadDml()
{
S32 x;
mMaxBitmaps = 0;
Stream *stream = ResourceManager->openStream(mDmlFilename);
if(stream) { // match this code to the new sky loading code
char path[1024], *p;
dStrcpy(path, mDmlFilename);
if ((p = dStrrchr(path,
#4
03/05/2003 (9:20 am)
I knew I was missing something, need to remind myself that its best not to look at code before having your initial cup of joe.

-Ron
#5
03/16/2003 (11:26 pm)
Wow great job! I'm glad people picked this up and ran with it. Keep up the great work! Robert
#6
04/12/2003 (12:56 pm)
ok how do I add it to a script :)
#7
01/07/2004 (11:08 am)
what is the setFPS command for?

In the console init you add the command:
Con::addCommand("GuiAnimatedBitmapCtrl", "setFPS", cAnimatedBitmapSetFPS, "GuiAnimatedBitmapCtrl.setFPS(F32)", 3, 3);

but the definition of the method cAnimatedBitmapSetFPS is just a copy of the cAnimatedBitmapSetIs3D
static void cAnimatedBitmapSetFPS(SimObject *obj, S32, const char **argv){
   GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
   ctrl->setIs3d(dAtob(argv[2]));
}

Were you going to adjust the interval based on a Frame-per-second calculation here?
#8
05/08/2007 (2:56 pm)
Tweaks to include paths to compile on TGE 1.5.1

header: GuiAnimatedBitmapCtrl.h
//-----------------------------------------------------------------------------
// GuiAnimatedBitmapCtrl.h
// Made by Robert Brower
// Modified by Jeff Bakke for C3 command www.c3command.com
//-----------------------------------------------------------------------------
#ifndef _GuiAnimatedBitmapCtrl_H_
#define _GuiAnimatedBitmapCtrl_H_

#ifndef _GUIBITMAPCTRL_H_
#include "gui/controls/guiBitmapCtrl.h"
#endif
#ifndef _MATERIALLIST_H_
#include "dgl/materialList.h"
#endif


class GuiAnimatedBitmapCtrl : public GuiBitmapCtrl
{
private:
	typedef GuiBitmapCtrl Parent;
	

protected:
	bool mIs3d;
	S32		 mInterval;
	S32		 mLastTime;
	S32      mIndex;
	S32      mMaxBitmaps;
	MaterialList	mMaterialList;
	StringTableEntry mDmlFilename;
	StringTableEntry mBitmapNames[30];
	TextureHandle mTextureHandles[30];
		   
public:
	//creation methods
	DECLARE_CONOBJECT(GuiAnimatedBitmapCtrl);
	GuiAnimatedBitmapCtrl();
	static void initPersistFields();
	static void consoleInit();

	//Parental methods
	bool onWake();
	void loadDml();
	void setBitmap(S32 index, const char *name);
	void setIs3d(bool temp);
	void setInterval(F32 temp);
        void onPreRender();
	void onRender(Point2I offset, const RectI &updateRect); 
};

#endif //_GuiAnimatedBitmapCtrl_H_

body: GuiAnimatedBitmapCtrl.cc

//-----------------------------------------------------------------------------
// GuiAnimatedBitmapCtrl.cc
// Made by Robert Brower
// Changes by Jeff Bakke/Codex Studios
//-----------------------------------------------------------------------------
#include "console/console.h"
#include "console/consoleTypes.h"
#include "dgl/dgl.h"
#include "gui/core/guiCanvas.h"

#include "gui/controls/GuiAnimatedBitmapCtrl.h"

IMPLEMENT_CONOBJECT(GuiAnimatedBitmapCtrl);

GuiAnimatedBitmapCtrl::GuiAnimatedBitmapCtrl(void)
{
	mBitmapName = StringTable->insert("");
	mDmlFilename = StringTable->insert("");

	for (int i=0; i<30; i++)
	{
		mBitmapNames[i] = StringTable->insert("");
		mTextureHandles[i] = NULL;
	}
	
	startPoint.set(0,0);
	mWrap = false;
	mIs3d = false;
	mInterval = 0;
	mLastTime = 0;
	mMaxBitmaps = 0;
}

void GuiAnimatedBitmapCtrl::initPersistFields()
{
	Parent::initPersistFields();
	addField("is3d", TypeBool, Offset(mIs3d,GuiAnimatedBitmapCtrl));
	//
	removeField("Bitmap");
	addField("Interval", TypeS32, Offset(mInterval,GuiAnimatedBitmapCtrl));
	addField("DML", TypeFilename, Offset(mDmlFilename,GuiAnimatedBitmapCtrl));
	//
}

static void cAnimatedBitmapSetValue(SimObject *obj, S32, const char **argv)
{
   GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
   ctrl->setValue(dAtoi(argv[2]), dAtoi(argv[3]));
}

static void cAnimatedBitmapSetBitmap(SimObject *obj, S32, const char **argv)
{
   GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
   ctrl->setBitmap(dAtoi(argv[2]), argv[3]);
}

static void cAnimatedBitmapSetIs3d(SimObject *obj, S32, const char **argv)
{
	GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
	ctrl->setIs3d(dAtob(argv[2]));
}

static void cAnimatedBitmapSetFPS(SimObject *obj, S32, const char **argv)
{
	GuiAnimatedBitmapCtrl *ctrl = static_cast<GuiAnimatedBitmapCtrl*>(obj);
	ctrl->setIs3d(dAtob(argv[2]));
}

void GuiAnimatedBitmapCtrl::consoleInit()
{
	Con::addCommand("GuiAnimatedBitmapCtrl", "setIs3d", cAnimatedBitmapSetIs3d, "GuiAnimatedBitmapCtrl.setIs3d(bool)", 3, 3);
	Con::addCommand("GuiAnimatedBitmapCtrl", "setFPS", cAnimatedBitmapSetFPS, "GuiAnimatedBitmapCtrl.setFPS(F32)", 3, 3);
	//Con::addCommand("GuiAnimatedBitmapCtrl", "setBitmap",  cAnimatedBitmapSetBitmap,   "GuiAnimatedBitmapCtrl.setBitmap(blah)", 3, 3);
	Con::addCommand("GuiAnimatedBitmapCtrl", "setValue",  cAnimatedBitmapSetValue,   "GuiAnimatedBitmapCtrl.setValue(xAxis, yAxis)", 4, 4);
}

void GuiAnimatedBitmapCtrl::setIs3d(bool temp)
{
	mIs3d = temp;
}

void GuiAnimatedBitmapCtrl::setInterval(F32 temp)
{
	mInterval = temp;
}

void GuiAnimatedBitmapCtrl::setBitmap(S32 index, const char *name)
{
   if (index < 0 || index > 29)
	   return;
   
   mBitmapNames[index] = StringTable->insert(name);
   if (*mBitmapNames[index])
      mTextureHandles[index] = TextureHandle(mBitmapNames[index], BitmapTexture, true);
   else
      mTextureHandles[index] = NULL;
   setUpdate();
}

bool GuiAnimatedBitmapCtrl::onWake()
{   
	if (! Parent::onWake())
		return false;
	setActive(true);

	if (dStrlen(mDmlFilename))
		loadDml();
	
	mIndex = 0;
	GuiBitmapCtrl::setBitmap(mTextureHandles[mIndex]);
	mLastTime = Sim::getCurrentTime();
	
	return true;
}

void GuiAnimatedBitmapCtrl::loadDml()
{
   S32 x;
   mMaxBitmaps = 0;      
   Stream *stream = ResourceManager->openStream(mDmlFilename);
   if(stream)
   {
      // match this code to the new sky loading code
      char path[1024], *p;
      dStrcpy(path, mDmlFilename);
      if ((p = dStrrchr(path, '/')) != NULL)
         *p = 0;

      mMaterialList.read(*stream);
      ResourceManager->closeStream(stream);
      mMaterialList.load(path);
      for(x = 0; x < mMaterialList.size(); ++x, ++mMaxBitmaps)
	  {
		  if (x >= 30) break;	
		  mTextureHandles[x] = mMaterialList.getMaterial(x);
	  }
   }
}

void GuiAnimatedBitmapCtrl::onPreRender() 
{
	S32 thisTime = Sim::getCurrentTime();
	S32 timeDelta = thisTime - mLastTime;
	if (timeDelta > mInterval)
	{
		setUpdate();
	}
}


void GuiAnimatedBitmapCtrl::onRender(Point2I offset, const RectI &updateRect) 
{
	S32 thisTime = Sim::getCurrentTime();
	S32 timeDelta = thisTime - mLastTime;
	if (timeDelta > mInterval)
	{
		mIndex ++;
		if (mIndex >= mMaxBitmaps)
			mIndex = 0;
		mLastTime = thisTime;
	}
	if (mTextureHandles[mIndex])
		GuiBitmapCtrl::setBitmap(mTextureHandles[mIndex]);

	//Render the bitmap 
	if (mTextureHandle) 
	{ 
		dglClearBitmapModulation(); 
		if(mWrap) 
		{ 
			TextureObject* texture = (TextureObject *) mTextureHandle; 
			RectI srcRegion; 
			RectI dstRegion; 
			float xdone = ((float)mBounds.extent.x/(float)texture->bitmapWidth)+1;
			float ydone = ((float)mBounds.extent.y/(float)texture->bitmapHeight)+1; 
	
			int xshift = startPoint.x%texture->bitmapWidth; 
			int yshift = startPoint.y%texture->bitmapHeight; 
			for(int y = 0; y < ydone; ++y) 
			for(int x = 0; x < xdone; ++x) 
			{ 
				srcRegion.set(0,0,texture->bitmapWidth,texture->bitmapHeight); 
				
				dstRegion.set( ((texture->bitmapWidth*x)+offset.x)-xshift, 
					((texture->bitmapHeight*y)+offset.y)-yshift, 
						texture->bitmapWidth, 
				texture->bitmapHeight); 
				dglDrawBitmapStretchSR(texture,dstRegion, srcRegion, false);
			} 
		} 
		else 
		{ 
			RectI rect(offset, mBounds.extent); 
			dglDrawBitmapStretch(mTextureHandle, rect); 
		} 
	} 
	else 
	{ 
		RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
		dglDrawRect(rect, mProfile->mBorderColor);
	} 

	// glEnd(); 
	// glDisable(GL_BLEND); 

	// renderChildControls(offset, updateRect);
}
#9
02/21/2008 (6:18 pm)
total noob here..

where would one put the .h file and the .cc file?

im thinking of in the directory of:

C:\Torque\TGE_1_5_2\engine\game\fps

would i be wrong in that?
#10
02/27/2008 (3:17 pm)
I used engine/gui/controls since it is a GUI control, and that put it in the same folder as its base class, the guiBitmapCtrl.