Fade to Black - Featured in Warzone demo and April Dev Newsletter
by Benjamin Bradley · 04/11/2005 (8:57 pm) · 14 comments
Generally speaking, a fair majority of the features you implement in a project using Torque is going to be extending some existing functionality within the engine. In fact, all of Torque's GUI controls inherit from a single GUI control at some point in their class hierarchies. This one control called the GuiControl, is the most basic of all of the GUI controls, and it is this control we will extend to create our special fade-out control.
The approach I take when creating a new class is to identify two things. First, what task are we trying to accomplish. And second, what things are needed to accomplish that task. For the fade-out control the purpose is to fade a particular scene to black. To accomplish this task we need to be able to keep track of time, specifically three things: How long it takes the control to fade completely to black. How long to wait before starting the fade. And what time do we use as a reference. With these things in mind let's start fleshing out our control.
Note: For the sake of simplicity I am implementing the class entirely inline inside the class structure.
The first thing we need to do is include some headers:
Finally the last part of the control to discuss is the onRender function:
Finally what a script might look like which utilizes this new control:
The approach I take when creating a new class is to identify two things. First, what task are we trying to accomplish. And second, what things are needed to accomplish that task. For the fade-out control the purpose is to fade a particular scene to black. To accomplish this task we need to be able to keep track of time, specifically three things: How long it takes the control to fade completely to black. How long to wait before starting the fade. And what time do we use as a reference. With these things in mind let's start fleshing out our control.
Note: For the sake of simplicity I am implementing the class entirely inline inside the class structure.
The first thing we need to do is include some headers:
#include "dgl/dgl.h" // some utility drawing routines #include "console/console.h" // hooks into scripting #include "console/consoleTypes.h" // ... #include "gui/guiControl.h" // the basic GUI control we derive fromWhat I'll do now is write out the entire class and fill in the important sections later:
class GuiFadeoutCtrl : public GuiControl
{
typedef GuiControl Parent;
private:
U32 referenceTime; // time we use in reference to the other times
U32 fadeoutTime; // how long it takes to fade to black
U32 waitTime; // how long to wait before starting the fade
public:
GuiFadeoutCtrl()
{
// setup default values
referenceTime = 0;
fadeoutTime = 1000;
waitTime = 2000;
}
void onPreRender()
{
Parent::onPreRender();
setUpdate(); // when we render, update the entire control
}
// tell the engine we want this class to be exposed to scripting
DECLARE_CONOBJECT(GuiFadeoutCtrl);
bool onWake()
{
if(!Parent::onWake())
return false;
return true;
}
void resetFade()
{
// set our reference time to 'now' effectively resetting
// the fade-out
referenceTime = Platform::getRealMilliseconds();
}
void onRender(Point2I offset, const RectI &updateRect)
{
Parent::onRender(offset, updateRect);
// ...
}
static void initPersistFields()
{
Parent::initPersistFields();
addField("fadeoutTime", TypeS32, Offset(fadeoutTime, GuiFadeoutCtrl));
addField("waitTime", TypeS32, Offset(waitTime, GuiFadeoutCtrl));
}
};
// tell the engine we want this class to be exposed to scripting
IMPLEMENT_CONOBJECT(GuiFadeoutCtrl);
// expose resetFade to the scripting system
ConsoleMethod(GuiFadeoutCtrl, resetFade, void, 2, 2, "")
{
object->resetFade();
}Since this is a basic control there is only one function I haven't filled out in the above class, so I'll briefly explain what is going on above and then move onto the onRender function. In the constructor we fill out some default values. These are only ever used if for some reason the script setup for this control does not set them. Two of the three values listed here are exposed to script within the initPersistFields function. The other function worth mentioning is resetFade. This function will set the referenceTime to the current machine's time. Since the fadeoutTime and waitTime are in reference to the referenceTime this will effectively reset the fade control. You'll also notice that this function is exposed to script via a ConsoleMethod which takes the name of the class, the name of a function and binding them to the real function.Finally the last part of the control to discuss is the onRender function:
void onRender(Point2I offset, const RectI &updateRect)
{
Parent::onRender(offset, updateRect);
// subtract current time with reference time to get the time elapsed
U32 elapsed = Platform::getRealMilliseconds() - referenceTime;
U32 alpha;
if(elapsed < waitTime)
{
// we havn't started fading at all yet
alpha = 0;
}
else if(elapsed < fadeoutTime+waitTime)
{
// we've started fading, but we aren't completely faded to black yet
elapsed -= waitTime;
alpha = 255 * F32(elapsed) / F32(fadeoutTime);
}
else
{
// we are completley faded
alpha = 255;
}
// the color black
ColorI color(0,0,0,alpha);
// draw a rectangle the size of the entire control
dglDrawRectFill(offset, mBounds.extent + offset, color);
}Essentially what is going on is we are figuring out how much time has elapsed since the last time this control was rendered and the referenceTime. We then compare the elapsed time with the waitTime and fadeoutTime's we set in script and set an appropriate alpha value for the color of the rectangle we draw to the screen. This rectangle fills the space of the entire control, in the case of the GDC Demo, a full screen effect.Finally what a script might look like which utilizes this new control:
new GuiFadeoutCtrl(DemoEndFadeOut) {
profile = "GuiDefaultProfile";
horizSizing = "width";
vertSizing = "height";
position = "0 0";
extent = "640 480";
minExtent = "8 8";
visible = "0";
fadeoutTime = "1500";
waitTime = "2500";
};
#2
04/11/2005 (9:15 pm)
@Robert - I haven't tried this myself, but why did you choose to go with a custom control? I see the "blackout" functionality implemented in the game.cc function GameRenderFilters() and controlled via client.setBlackOut() in the console.
#3
04/12/2005 (4:22 am)
That's true Tom and not something I've actually thought about. However, to answer your question I would have still needed to write this control because it allows me to fade GUI components as well, not just the scene. Whereas the feature you mention is meant for a control object camera fade only.
#4
04/12/2005 (7:21 am)
@Robert - Ahhh... that's the key point... that "blackout" only would effect the scene and not the GUI.
#5
Toby.
04/12/2005 (11:16 am)
Wouldn't it be better to extent the colour value of this fade-in as an input from the GUI editor, so that we can change it to white or grey or pink if that's what we wanted.Toby.
#6
04/12/2005 (11:17 pm)
very nice Robert. I've been using the setBlackOut function to fadein and fadeout but I like the concept of being able to fade individual controls rather than the whole scene. I also like Toby's suggestion about controlling the color as well. This control appears to have a broader application than the guiFadeInBitmapCtrl.
#7
04/13/2005 (2:43 am)
Very cool, now I have a way to fade my GUI scopes. :D
#8
Thanks for taking the time to post this regardless of the answer.
04/13/2005 (5:00 am)
I know this is probably a lame question and all but I was wondering if this would work in T2d as well. It seems to me to be a general gui control so I don't know if it needs to be modified or not.Thanks for taking the time to post this regardless of the answer.
#9
04/15/2005 (7:08 pm)
Awesome, going to extend this for any color.
#10
08/01/2005 (4:21 am)
@Charlie: This works flawlessly with T2D.
#11
I must be using it wrong.
I'm trying to use it to fadeout my scene to black. Any examples would be great!
Thanks!
05/27/2007 (7:22 am)
Does this still work in TGE1.5.2? as I thought it would be straight forward but I can't get it to fade out, it just jumps to black.I must be using it wrong.
I'm trying to use it to fadeout my scene to black. Any examples would be great!
Thanks!
#12
11/19/2007 (10:10 pm)
I don't know where to put the code. Am I supposed to make my own *.cc file and execute it somewhere and rebuild the engine?
#13
Kingdutka, simply create a new .cc file, add it to your project, then paste all the code in and save. Executing it anywhere is unnecessary. Remember that the onRender function isn't complete in the first piece of code, and that you'll have to replace it with the second piece of code. And in order to avoid an error, change the last include to: #include "gui/core/guiControl.h"
As you can see, I got it working fine, Benjamin. Thanks!
04/01/2008 (12:58 am)
Edward, just use resetFade, and you'll see it work. :]Kingdutka, simply create a new .cc file, add it to your project, then paste all the code in and save. Executing it anywhere is unnecessary. Remember that the onRender function isn't complete in the first piece of code, and that you'll have to replace it with the second piece of code. And in order to avoid an error, change the last include to: #include "gui/core/guiControl.h"
As you can see, I got it working fine, Benjamin. Thanks!
#14
05/27/2008 (7:35 am)
What's the difference of this resource with GameConnection::setBlackOut() function?
Torque Owner Jerry Shaw