Spritekin Limbo 2 - Bitmaps and progress bars
by Guimo · 04/05/2011 (6:13 am) · 3 comments
Hi everybody,
Continuing on my limbo series. I have cleaned up some more code and found this code you might find interesting regarding bitmaps and progress bars. So let me start with a image to give you an idea of this code before we start:

As you can see, this is no normal progressbar. The standard Torque progress bar stretches a bitmap over another one. This is fine for a square control, but when you need some detail it falls short. It is quite common to find this kind of progress bar, for example in Diablo life and mana spheres when they get depleted.
In order to solve this problem we need to start with a small improvement on the bitmap control.
The main issue here is that Torque always stretches bitmaps. Set them in a bitmap control, resize and they will stretch like rubber. But in this case you don't need them to stretch, you need them to clip (or wrap in 3D jargon) so it repeats a pattern. So if your texture is like the left one in the image, then the standard behaviour is to stretch like the middle one, but we want to let it wrap around like the right one.

Of course this have other uses but I will leave your creativity flow. Lets implement this in the engine:
in GuiBitmapCtrl.h find add:
In guiBitmapCtrl.cpp initialize it in the constructor:
Then add it in the initPersistField:
Fix it in inspectPostApply:
And finally alter the onRender method like:
Compile.
Now, try creating a UI and add a bitmap, try enabling and disabling the wrap flag and change the control size and understand the effect.
The nice thing is this won't break anything in the engine. In my point of view, probably the greatest benefit of this effect may not be the multiplying effect (which may have its uses) but its dividing effect. Indeed you can now render a portion of a bitmap which may be used for wipe effects or repeating backgrounds for windows when you don't want to lose detail. But for the sake of this post lets focus on the progress bar.
Lets create a couple controls in a UI:
In this example we have an outer control LoadingProgressBack which is a bitmap with a wrap mode 0. This control is precisely 360x24 and the bitmap we want to use as background srcRedSmall should be the same size as well.
There is also an inner bitmap called LoadingProgressBar with exactly the same size 360x24 pointing to the alter image srcGreenSmall which is also the same size. But this second bitmap uses the wrap mode.
So its basically a bitmap over other bitmap. Now lets create a simple function:
As the front has a wrap mode, it will properly be cut to an appropriate fraction of the size.
Just call this function as:
setProgressValue(0.45);
Now what?
This is just a simple example how to make a nice progress bar. Look at the mana and life bars in this shot:

Now think if you can make something like that. Maybe you need to fix the wrap mode a little to handle other modes (not only 0 and 1 values). Your move, change and create variations, but if you do, share your results please.
See you next week! I was interested in creating rotations for the UI controls, for some simple effects, lets see how it goes.
Luck!
Guimo
P.S. I'm having problems uploading the proper images. I will upload them when my FTP access problem is solved.
Continuing on my limbo series. I have cleaned up some more code and found this code you might find interesting regarding bitmaps and progress bars. So let me start with a image to give you an idea of this code before we start:
As you can see, this is no normal progressbar. The standard Torque progress bar stretches a bitmap over another one. This is fine for a square control, but when you need some detail it falls short. It is quite common to find this kind of progress bar, for example in Diablo life and mana spheres when they get depleted.
In order to solve this problem we need to start with a small improvement on the bitmap control.
The main issue here is that Torque always stretches bitmaps. Set them in a bitmap control, resize and they will stretch like rubber. But in this case you don't need them to stretch, you need them to clip (or wrap in 3D jargon) so it repeats a pattern. So if your texture is like the left one in the image, then the standard behaviour is to stretch like the middle one, but we want to let it wrap around like the right one.
Of course this have other uses but I will leave your creativity flow. Lets implement this in the engine:
in GuiBitmapCtrl.h find add:
... Point2I startPoint; + bool mWrap;
In guiBitmapCtrl.cpp initialize it in the constructor:
...
mBitmapName = StringTable->insert("");
startPoint.set(0, 0);
+ mWrap = false;
...Then add it in the initPersistField:
...
addGroup("Misc");
addProtectedField( "bitmap", TypeFilename, Offset( mBitmapName, GuiBitmapCtrl ), &setBitmapName, &defaultProtectedGetFn, "" );
//addField("bitmap", TypeFilename, Offset(mBitmapName, GuiBitmapCtrl));
+ addField("wrap", TypeBool, Offset(mWrap, GuiBitmapCtrl));
endGroup("Misc");
...Fix it in inspectPostApply:
...
Parent::inspectPostApply();
- if ((mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureHandle)
+ if (!mWrap && (mBounds.extent.x == 0) && (mBounds.extent.y == 0) && mTextureHandle)
{
...And finally alter the onRender method like:
void GuiBitmapCtrl::onRender(Point2I offset, const RectI &updateRect)
{
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);
}
}
if (mProfile->mBorder || !mTextureHandle)
{
RectI rect(offset.x, offset.y, mBounds.extent.x, mBounds.extent.y);
dglDrawRect(rect, mProfile->mBorderColor);
}
renderChildControls(offset, updateRect);
}Compile.
Now, try creating a UI and add a bitmap, try enabling and disabling the wrap flag and change the control size and understand the effect.
The nice thing is this won't break anything in the engine. In my point of view, probably the greatest benefit of this effect may not be the multiplying effect (which may have its uses) but its dividing effect. Indeed you can now render a portion of a bitmap which may be used for wipe effects or repeating backgrounds for windows when you don't want to lose detail. But for the sake of this post lets focus on the progress bar.
Lets create a couple controls in a UI:
new GuiBitmapCtrl(LoadingProgressBack) {
canSaveDynamicFields = "0";
Profile = "GuiDefaultProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "29 419";
Extent = "360 24";
MinExtent = "8 2";
canSave = "1";
Visible = "1";
hovertime = "1000";
bitmap = "./main/scrRedSmall.png";
wrap = "0";
new GuiBitmapCtrl(LoadingProgressBar) {
canSaveDynamicFields = "0";
Profile = "GuiDefaultProfile";
HorizSizing = "right";
VertSizing = "bottom";
Position = "0 0";
Extent = "360 24";
MinExtent = "8 2";
canSave = "1";
Visible = "1";
hovertime = "1000";
bitmap = "./main/scrGreenSmall.png";
wrap = "1";
};
};In this example we have an outer control LoadingProgressBack which is a bitmap with a wrap mode 0. This control is precisely 360x24 and the bitmap we want to use as background srcRedSmall should be the same size as well.
There is also an inner bitmap called LoadingProgressBar with exactly the same size 360x24 pointing to the alter image srcGreenSmall which is also the same size. But this second bitmap uses the wrap mode.
So its basically a bitmap over other bitmap. Now lets create a simple function:
//Sets the progress value in a 0-1 range.
function setProgressValue(%val) {
//Get the total width of the background
%ext = LoadingProgressBack.getExtent();
%width = getWord(%ext, 0);
%height = getWord(%ext, 1);
//Compute partial width of the foreground
%width = %width * %val;
//Set the new value
LoadingProgressBar.setExtent(%width, %height);
}As the front has a wrap mode, it will properly be cut to an appropriate fraction of the size.
Just call this function as:
setProgressValue(0.45);
Now what?
This is just a simple example how to make a nice progress bar. Look at the mana and life bars in this shot:

Now think if you can make something like that. Maybe you need to fix the wrap mode a little to handle other modes (not only 0 and 1 values). Your move, change and create variations, but if you do, share your results please.
See you next week! I was interested in creating rotations for the UI controls, for some simple effects, lets see how it goes.
Luck!
Guimo
P.S. I'm having problems uploading the proper images. I will upload them when my FTP access problem is solved.
#2
04/06/2011 (2:03 pm)
Forgot to mention is for TGE but I updating it to T3D shouldn't be that hard either. 
Torque Owner Richard Ranft
Roostertail Games