Contents

[hide]

Concept

RenderDelgate is a new component introduced by TGEA 1.8. The concept and functionality behind RenderDelgate gives you, the developer, a lot of flexibility when you are creating your own rendering objects.


The concept is based on the system sending a signal, which is caught by an object's RenderDelegate. The RenderDelgate itself calls an object's render function. Prior to TGEA 1.8, every object that requires rendering required a renderObject(...) function.


The function had to have that exact name, and identical parameters. Using a RenderDelgate breaks those requirements. Let's take a look at a few simple examples.

Sky Example

The Sky object is a great example of a custom object that requires rendering. The class is derived from SceneObject, which does not have a rendering function. Open engine/source/terrain/sky.h. If you scroll through the Sky class, you will find the declaration of its RenderDelegate:

ObjectRenderInst::RenderDelegate mRenderDelegate;


Open Sky.cpp (same directory), then locate the Sky::Sky() function. At the bottom of the function, Sky's RenderDelegate is bound.

mRenderDelegate.bind(this, &Sky::renderObject);


When binding, we are passing in the Sky class (this), and its rendering function. Let's say Sky's rendering function had a different name, such as renderSky.

mRenderDelegate.bind(this, &Sky::renderSky);


What we are doing is preparing the Sky class to receive a render signal and act on it. One of our manager's (which we will discuss in a minute), will parse through all of its contained objects. When it comes across Sky, it will send a render signal to the class. It doesn't care about the name of the rendering function, it just tells the object to render with certain information:

void Sky::renderObject(ObjectRenderInst *ri, BaseMatInstance* overrideMat)
{
   if (overrideMat)
      return;

   SceneState* state = ri->state;  

   GFX->disableShaders();
   
   ...

As you can see, the SceneState information is passed in via an ObjectRenderInst pointer (*ri). Nifty, huh?

ShapeBase Example

Let's talk about ShapeBase. The Sky class has shown us a great RenderDelegate example, but 2 is always better than one. The ShapeBase class contains two RenderDelegates. One is the standard mRenderDelegate, just like Sky has. The second one is mShadowRenderDelegate, which (you guessed it) is used for rendering a shape's shadow:


In engine/source/T3D/shapeBase.h:

ObjectRenderInst::RenderDelegate mRenderDelegate;
ObjectRenderInst::RenderDelegate mShadowRenderDelegate;


Remember the earlier discussion about signals and hooks? Well, GFX can send out signals for multiple functions. For instance, we can have a signal for rendering our shape and for rendering our shadow. The following code shows how we bind those signals:


In engine/source/T3D/shapeBase.cpp, ShapeBase::ShapeBase():

mRenderDelegate.bind(this, &ShapeBase::renderObject);
mShadowRenderDelegate.bind(this, &ShapeBase::renderShadow);


The above code shows our second RenderDelegate is attached to a function called renderShadow. Since we already have a basic idea of how a standard RenderDelegate works, let's skip right to mShadowRenderDelegate's purpose. Look at the following code chunk, then we'll break it down:


In ShapeBase::prepRenderImage(..):

if( renderSelf && mDataBlock->shadowEnable )
{
   ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();         
   ri->mRenderDelegate = mShadowRenderDelegate;
   ri->state = state;
   ri->type = RenderPassManager::RIT_Shadow;
   gRenderInstManager->addInst(ri);
}


Now, let's break it down. Here is the same chunk of code, but with my comments inserted above each line to detail the purpose:

// Check the shapebase's datablock to see if we render a shadow
if( renderSelf && mDataBlock->shadowEnable )
{
   // Datablock said we should render a shadow, so we are here...

   // We must have a render instance before we can proceed. 
   // We'll use our global RenderPassManager, gRenderInstManager, which is the lead render manager for GFX
   ObjectRenderInst *ri = gRenderInstManager->allocInst<ObjectRenderInst>();         

   // Now that we have an object render instance, let's assign the shadow render delegate
   ri->mRenderDelegate = mShadowRenderDelegate;

   // Assign the SceneState set up earlier in the function
   ri->state = state;

   // Assign the shadow render instance type (RIT_SHADOW)
   // This will tell our RenderPassManager what kind of render instance we are
   // working with, shadows as opposed to a mesh or sky
   ri->type = RenderPassManager::RIT_Shadow;

   // Add the new render instance to our global manager and move on.
   gRenderInstManager->addInst(ri);
}


To reiterate, ShapeBase has two separate RenderDelgates. One handles the standard object rendering, while the other handles the rendering of the object's shadow. Setting them up is extremely simple, which is the glory of using RenderDelegates.

Conclusion

This goal of this document was to provide you with an introduction and specific examples of the new RenderDelegate system introduced by TGEA 1.8's GFX2. Should you decide to create your own custom classes which require rendering of objects, please refer back to this doc. Making use of RenderDelegates can make your code cleaner and more modular.