25 January, 2007

Better Rendering Interface

One of the changes that I made when I pulled out the rendering from the engine into the GameRender object, was to really unify where the rendering happened, and move towards a more state-driven rendering (think OpenGL immediate rendering).

What I mean by this is that previously, a bunch of objects knew how to render themselves in odd ways. For example, GameSprite knew how to render itself at with some arbitrary transform. GameActor knew how to render the GameSprite, and FontResource could render text. This made testing easier, but as the interfaces are becoming more solidified, I definitely wanted to unify where and how the rendering happpened.

Enter the GameRender object, and now it is much cleaner. And also allows for more functionality, but at a bit finer level of detail. For example, currently the GameRender object has the following methods allowing the programmer to set render states and draw to the screen:
#alpha:
#blend:
#drawLine:to:
#drawBox:to:filled:
#drawSprite:
#drawText:
#font:
#loadIdentity
#origin:
#red:green:blue:
#rotate:
#scale:
#z:
So, using the above methods, an example of drawing a sprite somewhere on the screen, a line to the sprite, and some text would be:
(GameEngine current render)
loadIdentity;
origin: 100 @ 100;
rotate: 45;
drawSprite: mario;
drawLine: 0 @ 0 to: 100 @ 100;
font: courier;
origin: 10 @ 400;
drawText: 'FPS: ' , GameEngine current fps printString
This is actually much better for batching like-rendered objects together - characters in a string, sprites that all blend the same, or actors that should all render at transforms relative to each other. But, for just trivial rendering, it will probably be a little bit more troubling to code.

One minor concern I have is rendering state data carrying from one frame to the next. If the last object rendered on the previous frame was colored yellow, unless you reset the color at the start of this frame, it will be yellow again. Perhaps that isn't a serious problem, but unreset states bugs can be difficult to track down. Fortunately, actors always keep track of their entire state (transform, color, z-priority, alpha settings, etc), and will just render themselves in entirety.

Now I need to get background layers (tiled and non-tiled) and animated sprites working again. Once those are doing well I'll move onto the user interface system, which always turns out to be a beast no matter how simple it looks like it should be.

I'm starting to get pretty excited; I'm zeroing in on a pretty good engine.

1 comment:

tejón said...

Eagerly awaiting more updates!

Not sure how you feel about lengthy identifiers, but I can't help thinking that the proper Smalltalk names would be #drawLineFrom:to:, and so on. It seems important to me that as you're reading left to right, you should never have to worry about misunderstanding the first part of a keyword because you don't realize there's more to it! #drawLine: all by itself could want me to pass a line object. #drawLineFrom: clearly demands an origin point.

I'm also curious, have you taken a solid look at the Model-View-Presenter interface framework which Dolphin endorses (and provides library support for)? The separation of the three components, and methods of passing information between them, makes damn good sense. Twisting the Triad [PDF] is their explanation of how they came to adopt it (and what else they tried and discarded first).

While much of what you're doing right now is framework stuff outside of even the View domain, it would make very good sense to treat a sprite as a View, for instance; it could then update its own position as the Model it represents moves within the game space. If you extend to 3D, a View and a camera are obviously conceptually linked.