GUIControl color modulation
by Guimo · 12/08/2006 (10:29 am) · 7 comments
Im not used to send resources, in fact Im not that skilled with Torque but in this ocassion I was really surprised to find that Torque doesnt provide support for setting transparency or opacity levels for the GUI controls. Im not talking about bitmaps with alpha regions but being able to draw a GUI control with a certain opacity... like 50% transparent or 30% transparent... not just turning it visible or invisible. Or maybe being able to shade the control with another color, like setting a red shade or blue shade.
As usual my first move was to look for anyone who also find this annoying and only found two small controls (FadeBitmap and FadeBlack control) which really wasnt what I was looking for.
Not being a complete illiterate writing GUI libraries I set my mind to solve the mistery. So after digging a little inside the engine I found that even when internally Torque is ready to allow the previously described effects, its just not used for any of the GUI controls so I decided to write this resource. Notice that I dont pretend to change all the GUI controls but will point where you must change the engine in order to accomplish this objective.
Requisites
Torque 1.4 (don't know if this will work for other versions)
Theory
First, lets make a quick review. You have to understand that in order to render a bitmap on screen you need two things, colored vertices and a bitmap. Both are required because rendering libraries renders 2D bitmaps using two screen-oriented triangles forming a rectangle and then stretches the bitmap over the quad.
The vertices requires position, color and UV coordinate information. The color is required because the vertices are not transformed and lighted as in 3D rendering. You are supposed to send a color which will be modulated with the bitmap texels like this:
Texel Modulation Result
(r,g,b,a) * (1,1,1,1) = (r,g,b,a) //texel * white = texel
(r,g,b,a) * (1,1,1,0.5)=(r,g,b,a*0.5) //texel * white with 50% alpha = texel color at 50% transparency
(r,g,b,a) * (0,0,1,1) = (0,0,b,a) //texel * blue = blue shaded texel
The resulting color is then blended with the background. So in order to manage this we must enable vertex colors.
Now, in Torque every GUI control is rendered using its onRender method and it uses the dgl rendering routines. Every control uses functions called dglDrawBitmap or dglDrawBitmapStretch or dglDrawBitmapSR or dglDrawBitmapStretchSR. Of those four, the dglDrawBitmapStretchSR is the key of the problem. If you look at this function in the dgl.cc code you will find this:
So this is the command that sets the vertex color and uses the sg_bitmapModulation structure (if you search for it, its a ColorI structure). This means the engine is completely ready to handle transparent or shaded controls and all depends on this value in order to work. The problem now is how to set the structure to any value we want.
In the dgl.cc code find the following functions almost at the beggining of the file:
Of these four functions check and remember the dglClearBitmapModulation() function which is used to set the modulation color to 255,255,255,255 (that is 1,1,1,1).
So we have functions for setting the modulation... then where's the problem???
In order to find this, open the guiBitmapControl.cc at guiBitmapCtrl::onRender method and search this:
So this is it... Torque clears the modulation color to (1,1,1,1) before rendering a control. You will find this same approach in every control then if we can set other value for the modulation we are done.
Solution
Fixing every control in Torque is completely out of the scope of this resource but I can show you how to fix one and then you are free to go for the others. For simplicity I'm taking the guiBitmapControl as my example control but Im sure that with a little common sense you can expand this and update any control. A line which starts with (+) should be added, if it starts with (-) it should be removed or commented.
First we should fix the base guiControl and add a new attribute. So at the guiControl.h find and add:
Second, go to the guiControl.cc, at the guiControl constructor and find:
Lets expose this new attribute. In the guiControl.cc, at the guiContro::initPersistFields method, find and add:
These are all the changes we need in order to provide the basic color modulation for the GUI controls. After this, all changes are done in each particular control.
So in order to show how to use this functions we will modify the guiBitmapCtrl.cc file, at the GuiBitmapCtrl::onRender method. Locate and change:
That is, don't clear the modulation as that will make the engine to use a default white color. Instead set the specified modulation color.
Thats all. Compile the engine and run any demo.
Usage
Open the GUI Editor and add a bitmap control. You will find the Color attribute in the editor and you may change the modulation color. If you want to change the opacity level change the last value (the alpha component) of the color.
If you are running your game and want to affect the bitmap color, just do something like:
myBitmap.color = "0 0 1 1": //affect the control with a blue shade
Uses
With the ability to control modulation color you can do many presentation tricks.
You can use this to fade your controls to black or increase the visibility of some controls while leaving others more opaque. Making a control flash in red when your player is hit in your FPS. You can also draw a image as a grayscale bitmap and when you add it to your GUI you can change its shade color to match the color of your units in an RTS so you can shade it red or blue or green dinamically. You may also use it to show items with different colors for an RPG, a heal potion may be shaded blue while a poison can be shaded green and both using the same bitmap, or to show a blessed weapon with a yellow glow or a cursed item with a red glow.
Benefits
Being able to control the opacity level allows to save texture memory. You don't need to have bitmaps for each alpha level as you can set it dinamycally. Also you can shade an object allowing for dinamic colloring also saving some texture memory.
Improvements
This resource covers only changing a bitmap control, but you can do similar work for any control you wish. For example,a bitmap button could greatly improve with some alpha effects.
Also you may compute modulation cascades so if you set the alpha level for a parent control, all child controls should be affected as well as well.
Screenshot
This is a shot of my current prototype called Starquake. Just for demonstration I have stretched a bitmap, shaded it with a green color and applied a 50% alpha. Blame my art skills... I'm just a programmer. I hope you get the idea.
Luck!
Guimo
As usual my first move was to look for anyone who also find this annoying and only found two small controls (FadeBitmap and FadeBlack control) which really wasnt what I was looking for.
Not being a complete illiterate writing GUI libraries I set my mind to solve the mistery. So after digging a little inside the engine I found that even when internally Torque is ready to allow the previously described effects, its just not used for any of the GUI controls so I decided to write this resource. Notice that I dont pretend to change all the GUI controls but will point where you must change the engine in order to accomplish this objective.
Requisites
Torque 1.4 (don't know if this will work for other versions)
Theory
First, lets make a quick review. You have to understand that in order to render a bitmap on screen you need two things, colored vertices and a bitmap. Both are required because rendering libraries renders 2D bitmaps using two screen-oriented triangles forming a rectangle and then stretches the bitmap over the quad.
The vertices requires position, color and UV coordinate information. The color is required because the vertices are not transformed and lighted as in 3D rendering. You are supposed to send a color which will be modulated with the bitmap texels like this:
Texel Modulation Result
(r,g,b,a) * (1,1,1,1) = (r,g,b,a) //texel * white = texel
(r,g,b,a) * (1,1,1,0.5)=(r,g,b,a*0.5) //texel * white with 50% alpha = texel color at 50% transparency
(r,g,b,a) * (0,0,1,1) = (0,0,b,a) //texel * blue = blue shaded texel
The resulting color is then blended with the background. So in order to manage this we must enable vertex colors.
Now, in Torque every GUI control is rendered using its onRender method and it uses the dgl rendering routines. Every control uses functions called dglDrawBitmap or dglDrawBitmapStretch or dglDrawBitmapSR or dglDrawBitmapStretchSR. Of those four, the dglDrawBitmapStretchSR is the key of the problem. If you look at this function in the dgl.cc code you will find this:
glColor4ub(sg_bitmapModulation.red,
sg_bitmapModulation.green,
sg_bitmapModulation.blue,
sg_bitmapModulation.alpha);So this is the command that sets the vertex color and uses the sg_bitmapModulation structure (if you search for it, its a ColorI structure). This means the engine is completely ready to handle transparent or shaded controls and all depends on this value in order to work. The problem now is how to set the structure to any value we want.
In the dgl.cc code find the following functions almost at the beggining of the file:
void dglSetBitmapModulation(const ColorF& in_rColor) void dglGetBitmapModulation(ColorF* color) void dglGetBitmapModulation(ColorI* color) void dglClearBitmapModulation()
Of these four functions check and remember the dglClearBitmapModulation() function which is used to set the modulation color to 255,255,255,255 (that is 1,1,1,1).
So we have functions for setting the modulation... then where's the problem???
In order to find this, open the guiBitmapControl.cc at guiBitmapCtrl::onRender method and search this:
if (mTextureHandle)
{
dglClearBitmapModulation();
....
}So this is it... Torque clears the modulation color to (1,1,1,1) before rendering a control. You will find this same approach in every control then if we can set other value for the modulation we are done.
Solution
Fixing every control in Torque is completely out of the scope of this resource but I can show you how to fix one and then you are free to go for the others. For simplicity I'm taking the guiBitmapControl as my example control but Im sure that with a little common sense you can expand this and update any control. A line which starts with (+) should be added, if it starts with (-) it should be removed or commented.
First we should fix the base guiControl and add a new attribute. So at the guiControl.h find and add:
bool mVisible; + ColorF mColor; //The modulation color
Second, go to the guiControl.cc, at the guiControl constructor and find:
mVisible = true; + mColor.set(1,1,1,1); //set the base control color
Lets expose this new attribute. In the guiControl.cc, at the guiContro::initPersistFields method, find and add:
addField("Visible", TypeBool, Offset(mVisible, GuiControl));
+ addField("Color", TypeColorF, Offset(mColor, GuiControl));These are all the changes we need in order to provide the basic color modulation for the GUI controls. After this, all changes are done in each particular control.
So in order to show how to use this functions we will modify the guiBitmapCtrl.cc file, at the GuiBitmapCtrl::onRender method. Locate and change:
if (mTextureHandle)
{
- dglClearBitmapModulation();
+ dglSetBitmapModulation(mColor); //use out color valueThat is, don't clear the modulation as that will make the engine to use a default white color. Instead set the specified modulation color.
Thats all. Compile the engine and run any demo.
Usage
Open the GUI Editor and add a bitmap control. You will find the Color attribute in the editor and you may change the modulation color. If you want to change the opacity level change the last value (the alpha component) of the color.
If you are running your game and want to affect the bitmap color, just do something like:
myBitmap.color = "0 0 1 1": //affect the control with a blue shade
Uses
With the ability to control modulation color you can do many presentation tricks.
You can use this to fade your controls to black or increase the visibility of some controls while leaving others more opaque. Making a control flash in red when your player is hit in your FPS. You can also draw a image as a grayscale bitmap and when you add it to your GUI you can change its shade color to match the color of your units in an RTS so you can shade it red or blue or green dinamically. You may also use it to show items with different colors for an RPG, a heal potion may be shaded blue while a poison can be shaded green and both using the same bitmap, or to show a blessed weapon with a yellow glow or a cursed item with a red glow.
Benefits
Being able to control the opacity level allows to save texture memory. You don't need to have bitmaps for each alpha level as you can set it dinamycally. Also you can shade an object allowing for dinamic colloring also saving some texture memory.
Improvements
This resource covers only changing a bitmap control, but you can do similar work for any control you wish. For example,a bitmap button could greatly improve with some alpha effects.
Also you may compute modulation cascades so if you set the alpha level for a parent control, all child controls should be affected as well as well.
Screenshot
This is a shot of my current prototype called Starquake. Just for demonstration I have stretched a bitmap, shaded it with a green color and applied a 50% alpha. Blame my art skills... I'm just a programmer. I hope you get the idea.
Luck!
Guimo
#2
Luck!
Guimo
12/09/2006 (4:57 pm)
Updated code tags for easier readability (does that word exists?).Luck!
Guimo
#3
05/23/2007 (2:11 am)
A very useful ressource for my game, thx!
#4
it does pull the mFillColor directly from the profile however.
03/05/2008 (10:12 am)
How would this work for GuiControl itself? in its onRender, it doesn't have "dglClearBitmapModulation();", it does pull the mFillColor directly from the profile however.
#5
04/01/2008 (1:48 am)
Ed Johnson, correct, change GuiControl::mProfile->mFillColor for controlling color of any GuiControl object (including children). But it should has the GuiControlProfile with enabled mOpaque.
#6
04/02/2008 (6:11 am)
oh sorry man, of course its incorrect to modify mProfile cause its global stuff. Add dglSetBitmapModulation where it doesnt exist.
#7
02/04/2009 (9:16 am)
Nice resource! This is going straight in... something that should have been there from the start. And yes, readability's a word ;) 
Associate Stefan Beffy Moises