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.

22 January, 2007

Big Improvements

In the past few weeks the engine has seen lots of improvements. The framerate for all of my test applications has increased by roughly 80%. I don't have exact numbers in front of me right now, but the "zazaka" program is now significantly faster than the HGE version.

Vertex and pixel shaders are now fully supported. The engine defines a default vertex shader that it uses to render with extremely fast! on initialization (this also means the engine requires a video card that supports vertex shader version 1.1 at least).

With pixel shaders, though, the sky's the limit for cool effects.
Want your entire game to be rendered embossed or add blur effects, read from multiple textures or add any other number of special effects? It's all possible now.

Shaders go through the exact same resource management as all other resources, and are extremely easy to load, set, and use. For example, below is an example of how to load and start using a pixel shader:
ps := PixelShaderResource get: 'my_ps.pso'.
GameEngine current render pixelShader: ps.
As you can see from the above example, the actual rendering has been pulled out of the engine finally into its own class: GameRender. This was done for two reasons: simplify the engine class and if in the future I wanted to do 3D, this is where it would be done - subclassing GameRender into an immediate 2D render class and a batch 3D render class.

The GameActor class is now exactly how I want it - as just a node in the scene. It controls translation, rotation, and scaling. Actors can be parented to other actors, allowing for complex transformations (eg, a particle emitter attached to a sprite). The GameActor class now is subclassed into SpriteActor, which controls rendering of a sprite somewhere on the screen.

A pretty simple and well-featured particle system. Creating new particle effects in game and playing them is very simple and fast. There are 3 main classes which make up the particle effect system: GameParticleSystem (defines how particles will be emitted), ParticleEmitterActor (subclassed from GameActor), and ParticleActor (subclassed from SpriteActor). This has been the most flexible method of doing particles so far, as one GameParticleSystem can be used within many emitter objects very easily.

Spritemaps are now supported as a new resource type. They are extremely similar to fonts. An XML spritemap file is read off disk, which gives information about a texture and all the sprites inside of it. The spritemap object will create sprites that can then be referenced by SpriteActors by the name given to them in the XML file.
map := SpritemapResource get: 'sprites.xml'.
ship := SpriteActor fromSprite: (map sprites at: 'ship').
Right now spritemaps are very convenient for organizing data, but later when I add scrolling, tiled backgrounds they will be worth 10x as much as they are right now.

The last, simple, yet nice addition is the ability to set different blending modes. The engine supports additive, multiplying, solid, and alpha blending modes.

That about covers most of the recent changes and additions. Next I hope to clean up some more code and centralize more of the rendering code to be more flexible and easy to use, add render targets to the mix (this will open another level is visual effects), and I need to start planning how I'm going to do user interface widgets.

01 January, 2007

It's The Small Things...

Been working on the game engine all day today, and made a few minor adjustments that made a big difference. Since the Bitmap Font Generator can generate a font description file in XML, I decided to dump the parser I was using and switched to Microsoft's DOM parser for XML (built into Dolphin). This cut down on another 3rd party piece of code that may need to be maintained, and simplified the font code significantly.

What made it so much easier to code was Smalltalk's reflection capabilities, and being able to send dynamic messages to objects at runtime. I've used XML before for various programs, and many times, I end up with a piece of code that invariably looks like the following:
while(elt) {
if (!stricmp(elt->tagName, "info")) { ... }
if (!stricmp(elt->tagName, "common")) { ... }
if (!stricmp(elt->tagName, "pages")) { ... }

// next element
elt = elt->nextSibling;
}

And this is just terrible code. Terrible to maintain, terribly slow, and not scalable; as new data is added to the file, and new programmers need to add code to the above loop, it will just turn into one hell of a mess. I often see the inside of { ... } turn into more parsing code, instead of being broken out into another function. Eventually we end up with a several-hundred-line function that no one wants to touch for fear of breaking some unrelated piece of very fragile code.

So, how can the above be made easier (and more scalable) with Smalltalk and reflection? Well, each tag can just be turned into a method descriptor and called by the parsing code. The above in my font loading code looks like this:
[elt isNull] whileFalse:
[self perform: (elt tagName , ':') asSymbol with: elt.

"Next element."
elt := elt nextSibling]

So, the tag name itself is just used as the method that is called to parse it. In essence, the object just parses itself. Very slick. If there is ever a new tag added later on, I just add a new method to parse it and it should just work. Just the way code should.

Another nice, small, feature of the Smalltalk language is being able to cascade messages to the same object and a wonderful little method called #yourself. When possible, I like to code as functionally as possible (without sacrificing performance), and the above has allowed me to do this many times over. And - in my opinion - makes the code more elegant. Something one may see in C/C++ (or many other imperative languages) is the following:
bool SomeFunction()
{
if (SomeCondition) {
/* do something */
return true;
}
return false;
}

Now, there's nothing wrong with this. But it always feels a little dirty to me. You aren't really returning true or false from SomeFunction, instead, you are returning the result of SomeCondition, and that's not immediately apparent from reading the code. And, believe it or not, this does lead to bugs down the road when other programmers have to go in and do something to it.

So, how does message cascading and #yourself help in Smalltalk? Well, it allows me to perform actions based on the result of some statement or expression, and then actually return that result separate from the actions performed. The above could instead be coded:
^(someCondition)
ifTrue: [ "do something" ];
yourself

Anyone should be able to clearly see that someCondition is being returned, and other actions just happen to be performed based on that condition. That's going to be pretty hard to foul-up down the road. And, it looks nicer, too.

As I come across more Smalltalk elegance, I'll be sure to post them. But for today, these were the two that caught my eye the most often.