Planning the Spontaneous

It's more than just a blueprint.

Renderer: Renderables

Posted by Robert Chow on 15/01/2010

So with the majority of the Renderer library nearly finished (with the exception of layers and fonts; well, there are fonts, they’re just not perfect), the process of refactoring has started.  On top of that is also creating a toolkit which will be used as a helper library to make using the Renderer library a bit more user-friendly. Less typing means for more time to do other things.

Renderable Objects

So Renderer is based on the concept of having Renderable objects.  These are exactly what they say on the tin.  They’re are renderable.  To render them, you will need to access their properties.  These properties are fairly straight forward, and are what you would expect a Renderable object to have.  Of course, these have been fine-tuned to the usage of vertex buffer objects, so the properties are:

Vector[] Vertices; // vertices of the shape
Colour[] Colours;  // colours specified at each vertex
Vector[] Normals;  // normals specified at each vertex
Vector[] TexCoords;// 2D texture co-ordinate specified at each vertex, these map to the Renderable texture
uint[] Indices;    // the order of how the vertices are to be drawn 
IMaterial Material;// any material properties this Renderable may hold
ITexture Texture;  // the texture, if, bound to the Renderable
DrawType DrawType; // an enum representing each OpenGL drawtype, specifying how the Renderable is drawn

Without the Vertices, Indices or DrawType, the Renderable is unrenderable, so these are forced in the constructor.  Using the vertices as a core property, this cannot be changed, but all the other properties can be.  That is, due to validity checks.

Duplicate Duplicate

Drawing each Renderable as a vertex buffer object seems rather silly to store the core data multiple times, as it will already be in the GPU, as well as the artificial buffering system in Renderer (used to control and keep a track of what is in the GPU), so it is not necessary to have it in the Renderable object itself.  Instead, I have used the notion of a ‘pointer’ per property.  This is not the conventional pointer traditionally used in computing, as it does not directly correspond to a place in memory.  Instead it points to a place in the artificial buffer where the corresponding data is held.  Using this method means the Renderable object is rather lightweight and is cost effective in memory.

To obtain the ‘pointer’, the client needs to ask the Renderer library.  This is done through the RendererFacade (Facade design pattern), and only takes in the one parameter – the core data.  This core data is sent to the artificial buffer, and the ‘pointer’ is returned.

Where the vertex buffer objects are concerned, this changes the properties in the Renderable object to type ‘pointer’.  Of course this could cause problems, allowing clients to assign Colours ‘pointer’s to TexCoords, Indices ‘pointer’s to Normals and so forth, eventually causing the computer to crash because of a GPU error.  To solve this, each ‘pointer’ is wrapped in a DataPacket interface, and deriving from this are corresponding DataPackets for Vertices, Colours, Normals etc. making sure that the correct ‘pointer’ is matched with the right property.

IVerticesDataPacket Vertices;
IColoursDataPacket Colours;
INormalsDataPacket Normals;
ITexCoordsDataPacket TexCoords;
IIndicesDataPacket Indices;

Using the standard get and set methods that properties have, changing a property is relatively easy (we can also write these manually to do our validity checking).  But it could be better.

Fluent Refactoring

Since we are refactoring, we might as well try to make this as easy to understand and read as possible.  For this, I have touched upon fluent interfaces.

The idea behind this is relatively simple when assigning a property.  It’s a little more difficult when it comes to multiple states.  But more on that later.

For example, we want to assign a ColourDataPacket, a TexCoordsDataPacket and a Texture to a Renderable, it’s as easy as this:

renderable.Colours = colourDataPacket;
renderable.TexCoords = texCoordsDataPacket;
renderable.Texture = texture;

However, to create a fluent interface, I have created extension methods that more or less do exactly the same thing.  The difference is that it reads better, it’s less typing, and it’s also a single statement.

renderable.Assign(colourDataPacket)
.Assign(texCoordsDataPacket)
.Assign(texture);

The extension methods are simple.  Not only do they do pretty much exactly the same as per normal assignment, but they also return the Renderable instead of void, allowing more methods to be called – this is a form of method chaining.  To make it even more simple, I have also used polymorphism to defer from what is assigned to what, allowing me to just use variants of the one method, Assign(), throughout.

Pretty cool, eh?

 

Advertisements

2 Responses to “Renderer: Renderables”

  1. Simon said

    You should look at FreeType for fonts. Excellent quality and I could post you some sample code if you’d like to see it.

  2. Anthony Jones said

    A better use of fluent interfaces would give an indication of what you are actually doing:


    renderable.AddColour(red)
    .AddTexture(clouds, coords) // might as well bundle them together
    .GenerateNormals() // I'm lazy
    .MakeShiny(Shinyness.VeryShiny);// assigns/manipulates material properties

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: