06 December, 2007

Sorry for the Lack of Posts

I've been quite busy of late. I've been trying to modify the GameEngine package (in the very little time I've had lately) so that it will "just work" with the Community Edition of Dolphin, but I've been unsuccessful so far. I'll be putting up a new version as soon as I get that working.

As far as future updates go, I must admit that my motivation has dropped significantly since Object Arts' announcement to discontinue development of Dolphin. I've been looking into porting it to VisualWorks, but I've grown to love Dolphin. While there are a couple things I'd like to add/change (a GUI layer primarily and then adding physics support), I feel that the engine is fairly complete for someone to make something simple with.

I've been toying with the idea of implementing my own [tiny] Smalltalk just for games, and even slapped together a simple image and interpreter. But, that's still a ways off (and a bit pie-in-the-sky) considering the time I have to "play" with.

12 August, 2007

Sad News

Looks like the future of Dolphin Smalltalk is rather uncertain. After a 10 year run, Andy and Blair are calling it quits. They did an amazing job with Dolphin, and their work was definitely appreciated by many. Here's hoping they do great in their next pursuit...

comp.lang.smalltalk.dolphin

22 June, 2007

Testing New Waters

It's been a while since my last post. I've been quite busy with life and work, and haven't had much of a chance to do anything with the game engine. I also purchased a new MacBook Pro (15"), which I absolutely love, and do miss my time with Dolphin (but not Windows!).

I've gotten the latest Parellels Desktop application running with Windows Vista, Dolphin is installed on it, but something isn't working with OpenGL in it. I'm not sure if it's Parallels that's having problems or Vista. Needless to say, this is the biggest hold-up for continued work on the engine. Hopefully there isn't a lynch mob forming because of my switch to Mac.

In the mean time, since it's based on Smalltalk, I downloaded Xcode from Apple and have started programming in Objective-C. I thought I'd give porting the basics of the game engine to it and see how that went. There have definitely been ups and downs. Objective-C is a very nice language, and Cocoa is a wonderful set of classes to help ease development. But I seriously miss the class browsers of Smalltalk.

Continuing my lust for more things Smalltalk, enter F-Script... Since Objective-C is derived from Smalltalk, it has reflection. F-Script is a Smalltalk scripting language intended to leverage that.

I've taken the Objective-C version of the engine (in its rudimentary form) and instead of subclassing GameActors and GameScenes (and overriding methods like #advance:) to create gameplay, each one is just an instance with a script, and calls out to the script methods that make it unique. Consider this example of an actor:
sprite := nil.

"Called when the actor is initially added to the scene."
create := [
GameSprite fromTexture: 'media/ship.bmp'.
self transform setPosition: 10 <> 10.
].

"Called once per frame to advance gameplay."
advance := [
self transform rotate: 10 * engine deltaTime.
].

"Called once per frame to render the actor."
render := [
sprite renderAt: self transform.
].

The above script shows off many cool features of Objective-C and F-Script....
  • F-Script instantly has access to all of the game code (as witnessed by the use of GameSprite).
  • Before the script was compiled, the game can assign identifiers in the script to objects (as seen through the use of "engine" and "self").
  • Objective-C code can query identifiers in the script and call them (as seen by the assignments of create, advance, and render, which are then called at runtime from Objective-C).
What makes this all-the-better is that none of this required any fancy function hooks, as would be required with other scripting languages like Lua. With a little more effort, it will be extremely trivial for actors and the scenes to even make direct calls to OpenGL.

Now, with anything "new and cool" there will always be pros and cons.

The biggest pros in this case are that the game doesn't need recompiling, and that scripts drive most of the gameplay. That's great, especially for teams that separate programmer and designer. Smalltalk still has it beat since I can recompile functions at runtime to update gameplay, but separating gameplay scripts from actual game code is a very good thing.

As for cons, the biggest one is that using any scripting language can make all but trivial games very difficult to program. For example, try and use a scripting language to program Othello. The interaction with the game and objects may be simple, but rules, and even simple min/max AI aren't so obvious in their solutions (and performance will suffer tremendously). In the end, I'm sure this code would just be done in Objective-C, though, and F-Script would just access to it (board isMoveValid: 2 <> 2).

F-Script isn't an actual Smalltalk. It does have a wonderful class browser, though. And while I take some time off from Dolphin (and Windows), I must say that programming in Objective-C with F-Script at the helm is a delight, and I'm hoping to leverage both significantly on the Mac.

If any of you have a Mac, be sure to download F-Script, and send me an email so I can share some of the work I've done.

19 May, 2007

Engine Available!

I've updated the Unstdio website and the 2D game engine is now available for download. It's definitely in an alpha stage, so as soon as I get some time to continue work on it some of the classes may change. There are also some classes that are currently there as placeholders, and not currently used (for example, GameMenu).

If you find anything wrong, definitely email me and I'll be sure to fix it as soon as I can. If you modify the code and add any features, I would very much appreciate those being made available to myself and everyone else, but that isn't required. Definitely do not claim ownership of the engine, and if used, please give credit where it's due.

Enjoy!

15 May, 2007

Brief Update

I'd like to apologize to everyone for the lack of updates here. Things have been very busy at work (and will be for a while), and I needed a bit of time off - so I took a brief vacation.

I'm going to trim out a few features that I've been working on as I won't be able to finish them up immediately (and they aren't strictly necessary - just nice to have), and post a version of the engine along with a couple incomplete packages. Hopefully that will be done in the next day or two. I'll also try and type up some documentation on how some of the packages work with each other.

I'll post a follow-up to this once they are available for download.

05 April, 2007

DirectX 9.0 Wrapper Available!

Even though the game engine is only using DirectInput, I now have the DirectX 9.0 wrappers that I've put together (Direct3D, DirectInput, XACT, and XINPUT) available for download at www.unstdio.com.

Feel free to download them and use them in your own projects. Not all the COM methods are wrapped, and the D3D version is lacking quite a bit, but has plenty enough to get started. As I add more functionality and improve on the overall package I'll be sure to post it here.

I'm in the process of adding a little more functionality to the BASS and DevIL packages now before putting them up for download, and OpenGL is just about done.

Stay tuned...!

31 March, 2007

Unstdio

Progress has been continuing, although a little slow the past few weeks. I've had a bit of "coder's block" and instead decided to start taking care of odds and ends: naming the engine, get web hosting, and the mundane task of creating documentation.

The name of the engine is now Unstdio. I've registered www.unstdio.com. I must say, Netfirms and Google Apps are nice and simple, and I was able to put together a few pages quickly enough. I highly recommend that combo for anyone that isn't super web savvy (like myself), but still has content they want to put online.

There's still nothing up for downloading, but I hope to start getting things up in the next couple weeks or so. Hopefully I can learn enough PHP so that I'm not copy/pasting HTML code all over the internet. I've never been one for web pages. :-)

And to give a few updates on new features and changes...

The resource system is just about in place. It's much better now, and resources can now be referenced by name instead of by filename. I've been putting that off for quite a while now for and it's nice to almost be done with it.

I've been slowly wrapping the Newton Game Dynamics library so games can have 2D physics built-in. It will probably be a while before this is completely implemented, but I'm hoping to make it dirt simple to wrap a physics body around a sprite actor and have simple callbacks for collisions and transform updates.

There should now be a decent number of comments in each of the top-level game object classes. I figure it will be a while before I get real documentation, so I'm trying to make this as good as possible for others. For example, here's an excerpt from the GameScene object class:
A GameScene is the heart of gameflow and logic. Examples of simple scenes for a Tetris game might be the main menu, basic playing, and the high score. When the game is told to enter a scene, the #exit method is called on the current scene and then the #enter: method is called for the new scene, with the old scene as an argument. Note: this won't actually happen until the end of the current frame during the handshake.

Each frame, the #advance: method is called (with the delta time - in seconds - since the last frame) as well as the #logic method. The #advance: method is only called when the engine is not paused, and is typically where the scene will advance actor's that are in the scene. However, #logic is called ever frame, regardless of the engine state, and is typically where user input is processed (quit, un/pause, etc). After advancing the frame and processing logic, #render is called by the engine allowing the scene to perform any necessary rendering. Like #logic, this is called regardless of the current engine state.

Once the entire frame has been advanced, processed, and rendered, before any scene changes happen, #handshake is called. This is a catch-all, post-frame method, where the scene can update anything that wasn't taken care of during the frame. For example, if actors were killed, and need to be removed from a list, this would be when that happens. While this isn't a true handshake, the term is being reserved for future use when (and if) the engine is ever multi-threaded, allowing the rendering to happen simultaneously with the simulation.

I'm slowly putting together an idea for a package documentation generator, that will generate HTML documentation for a package and all the classes in it. If something like that already exists, though, I'd be much appreciative if someone can point me to it.

16 March, 2007

Looking Good

I've made a static pool of particles - for emitter actors - that can be recycled instead of being destroyed and recreated over and over again. This has greatly reduced the number of garbage collections that are happening to well within acceptable limits.

The framerate back up to over 400 again with the single effect playing, which consists of an average 160 alpha blended, rotating, scaling, and tinted particles. Much better.

I also took a little time to get the collision detection optimized a bit. Eventually I'd like to get a simple quad tree in the playfields, but right now O(n^2) collision detection isn't much of an issue for an Asteroids clone.

All told, it's been a pretty productive week of optimizations, and I'm back on track to implementing more features that need done.

13 March, 2007

Full Speed Ahead!

When I added the first real particle effect into the game and saw the framerate drop from 480 to 150, I knew something was terribly wrong. Since then, the past few days have consisted of me in optimization mode.

I've since been in contact with Object Arts (awesome support, guys!) and been learning more about their compiler and VM implementation. I've written compilers myself, so this knowledge isn't falling on deaf ears. I'd rather not quote anything said or try and paraphrase comments for fear of stating something out of context. But, here's a quick summary of my optimizations so far....

Part 1: Points

Point objects are evil! Simply put, do not use them for temporary values unless they are only being used rarely - and I do mean rarely. Definitely not something to use in an #advance: method (called every frame for every actor).

I went through my transform class and added a handful of new methods that would not cause new points to be created. Similarly, I went into each method's code and made sure I wasn't calling methods with temporary points, and decided to inline any code that required this.

Last, I added some destructive, loose methods to the Point class. These were for rotating, normalizing, and getting the squared magnitude, without the need for creating a new, temporary Point object. And I then went through all the game code and made the necessary changes needed to support these adjustments.

These changes alone brought the terrible-case framerate from 150 up to about 300. It's great that a few changes could accomplish so much, but I think it's sad that the Point class is poorly implemented. Hopefully in the future Object Arts can make points a primitive type and really improve their performance.

Part 2: ByteArrays

Still, the framerate was not where I wanted it. So, I went through code snippets I wrote, originally thinking they would be obvious optimizations, and confirm that they actually were. These areas were typically ByteArrays that were pre-allocated and used for matrix transformations and similar state settings. After all, a single call to glLoadMatrixf() is much faster than 4 calls to glLoadIdentity(), glTranslatef(), glRotatef(), and glScalef(). Right? Sadly, no. It became obvious very quickly that this wasn't the case. I'll just sit back now and let some sample code and timings do the talking....
transform
"Create a 2D matrix FAST!"

^viewTM
_11: x * scale x;
_12: y * scale y;
_21: y * scale x negated;
_22: x * scale y;
_41: origin x;
_42: origin y;
_43: z;
yourself
The above code should not take longer to execute than OpenGL calls, but it does. I'm sure OpenGL does some very good assembly level optimizations under the hood for matrix creation and multiplication, but the above code is extremely trivial. Opening up a Workspace and doing some simple timings shows some interesting results:
Time microsecondsToRun: [10000 timesRepeat: [
GL
glLoadIdentity;
glTranslatef: 1.0 y: 1.0 z: 1.0;
glRotatef: 40 x: 0 y: 0 z: 1;
glScalef: 1 y: 1 z: 1]].
The above results (on my machine) in a ~2500 microsecond timing. That's pretty damn good for a foreign function interface (FFI). Now, just faking a similar MATRIX setup and slamming it through...
Time microsecondsToRun: [10000 timesRepeat: [
GL
glLoadMatrixf: (b
_11: 2.0; _12: 2.0;
_21: 2.0; _22: 2.0;
_41: 2.0; _42: 2.0;
bytes)]].
This results in ~6500 microsecond. That's more than 2.5 times what's required using just OpenGL! I highly doubt that #glLoadMatrixf: has any significant overhead above any other external method call. But it's possible that there is GP fault checking due to passing a buffer to an external call. Hopefully not.

My assumption at the moment is that there is a good amount of VM overhead for #floatAtOffset:put: in the ByteArray class - most likely due to bounds checking and type coercion. If this is the case, hopefully I can convice Object Arts to add a kind of UnsafeByteArray (or at least some "unsafe" methods to ByteArray).

Given the above information, I made the code change over to just make straight OpenGL calls. I also created a GameColor class instead of using a ByteArray for calls to glColor3fv().

These changes netted another significant win and the same particle effect (with about 200 particles) in game is now running at a solid 350 FPS. That's about a 200 FPS gain since my last post. Not too shabby, but still more room for improvement.

Part 3: What's next?


I'm going to continue correspondence with Object Arts regarding these issues. The more I learn about the inner workings of Dolphin the better I'll be able to push it for the benefit of others. Likewise, hopefully I can convince them of the need for certain functionality and it'll be a win-win senario.

Beyond that, I'm in the process of trying to create a fixed-size pool implementation for particles. Garbage collections on individual particles is still happening far too often with how quickly particles are created and destroyed. Giving each emitter a pool of 200 or so particles that are never released until the emitter dies should yield another decent gain.

12 March, 2007

Weekend Followup

I've been getting a lot of emails about my last post, particularly in regards to Dolphin's garbage collection (some of them generalized this to Smalltalk, which would be wrong), and some regarding garbage collection in games period. Instead of answering each of them or replying to blog comments in a comment, I decided to follow-up with another post....

In a garbage collected language, collection times are a reality. A 30 ms spike isn't horrible (I cringed as I typed that) as long as it's only once every 10-15 minutes. Right now, the collections are occurring roughly every couple minutes. This is unacceptable.

The only real choices are to either turn the collector off and force collections at known "good" times (which for some games isn't an option), write code in a manner that severely limits how often they are needed, or a combination of both. Either way, eventually the memory manager will need to sweep over a large set of objects and see what can be collected. And, while optimizations can be made, this is a problem that will always exist.

Turning off the collector isn't really an option [for me]. I can't make that generalization for all games created with the engine, and I can't generalize when a collection should happen. An individual game can choose to do this, but I won't be forcing that down anyone's throat. But, I do need to reduce how often a collection is needed. This will require special collection classes (pools), some intimate knowledge of the VM, and a certain amount of black-box trust. Sadly, "black-box trust" is something I keep in short supply these days.

Currently, I don't think lots of particles are causing the majority of the GC's - they're just shining a bright light on the real problem(s). My gut tells me that it's the VM not properly handling short-lived objects well. Particle updating currently uses a lot of Point objects for temporary calculations. The compiler probably doesn't recognize that they can't possibly be referenced outside the scope of the method, and therefore doesn't optimize their creation and deletion.

I need to ping Object Arts before making too many assumptions about the internals, though. I don't know if Dolphin uses mark and sweep, multi-generational garbage collection, simple reference counting, something else, or a combination approach. I could be pretty far off base. Be assured I will post a very detailed analysis of my findings and what I'm doing to take care of the problem.

11 March, 2007

Weekend Developments

I got quite a bit of work done this weekend. Animated sprites are working. They currently come in three flavors: forward, reverse, and ping-pong. They can loop forever or when done the animated actor will simply remove itself from the scene. This is useful for short-lived, sprite actors, and I'm now using them to add some nice explosions to Asteroids.

After adding animated sprites I worked on getting particles rendering. I decided to go the full-blown route here and really implement particle emitters. A particle system describes how the particles will behave. A particle emitter [actor] decides where and when the particles will be emitted, and the individual particles are finally advanced and rendered.

While there is a little bit of code cleanup left to do, I'm overall very happy with the results. I have added wormhole objects to the game, randomly appearing for 20-30 seconds, attracting the player and asteroids, and gaining intensity with each object that it swallows. A very cool effect.

I've cleaned up the OpenGLPresenter and OpenGLView objects, and they can now be used in the View Composer very easily to render any data desired. This is actually the first step of many to add some very slick game development tools to Dolphin (more on this at a later date), but in the meantime perhaps they will be useful to others as well.

On the downside, I'm finally starting to run into a few barriers that it looks like I'm going to have to address myself.

First up are the collection classes. I've had to create an UnorderedCollection class that will allow for O(1) removal of elements. It works very well, but it frustrates me to have to subclass a built-in class just to override a single function and implement it more efficiently. I rather wish something like this was already in there. I would have prefered to just add a #removeUnsortedAtIndex: loose method, but then #removeAll and similar methods wouldn't have worked as expected. I'm open to suggestions on this.

Next is the Point class. While I'm sure it works very well for 99.9% of all Dolphin users, it's extremely inefficient for my purposes. Running Ian's profiler reveals that almost 40% of all time is currently spent there. This means I'm going to have to go through a whole ton of code and adjust methods to take x:y: parameters instead. I'm also going to have to alter some of the code in the Point class to improve performance and add functionality (#rSquared and #normalized for use with intermediate results and #normalizedFast for not-quite-exact but really fast unit vectors).

Finally, with the particle system in and running, I've decided to really crank up the rate at which actors (and particles) are created and destroyed to test one other major concern: garbage collection. My own tests reveal that when a GC takes place, it usually takes between 30 and 40 milliseconds to run. This is an enormous amount of time. As progress continues, I'll be sure to post my findings.

07 March, 2007

Extending and Simplifying

Over the past week I've been slowly putting together a rather long post about all the changes that have been made. Instead of trying to make points or talk about experiences, I think this time around I'll just give the updates and explain a couple decisions made along the way.

I'll start with the biggest update: the game engine is now using OpenGL. I still have all my Direct3D9 wrappers (and anyone is welcome to them), but OpenGL offered [for this project] some extremely nice benefits over Direct3D. I'll get to those in a minute. But, for now, know that Dolphin now has a 100% implementation of OpenGL out there, with extension support.

I've also decided to implement 2/3's of an MVP triad (I'm still trying to wrap my head around MVP): the view and the presenter. This not only simplified my code a ton, but I imagine than an OpenGLPresenter would be extremely useful for others in the Dolphin community as well. Probably the smallest example I can give of it in action would be:
p := OpenGLPresenter show.

p makeCurrent
ifTrue: [(OpenGLLibrary default)
glClear: GL_COLOR_BUFFER_BIT].
p flip.
Simple enough. There should now be a rather large OpenGL rendering window on the desktop with nothing in it. The presenter can be attached to any view object (within reason I suppose), which means it should be very easy to use in dialog applications or anywhere else that rendering is needed.

Since the ExternalLibrary object uses its own #getProcAddress: for looking up external functions, this made creating OpenGL extensions very easy. Subclassed off of OpenGLLibrary is OpenGLExtension, which overrides the #getProcAddress: method and replaces it with wglGetProcAddress(). Also, it has a class method: #find. To use an OpenGL extension, just subclass the extension class, and then just start defining the instance methods as normal, just as if the extension exists. The #find method will search the extensions available against the class name and return it if found, otherwise nil.
"Declaring the extension class..."
OpenGLExtension subclass: #ARB_multitexture

"Defining one of the methods in the extension..."
glMultiTexCoord2fvARB: mode coords: v
<stdcall: void glMultiTexCoord2fvARB dword float*>
^self invalidCall

"Using the extension..."
ARB_multitexture ifFound: [:ext |
ext glMultiTexCoord2fvARB: GL_TEXTURE0_ARB coords: ptr].
That's it! Extensions in OpenGL have never been easier (in my experience).

Okay, so why the switch? Well, there were a few different reasons. The primary one is that all games are different. Sure, I'm making a 2D engine, but there are many flavors of 2D games. Each with its own set of requirements and rendering needs. And there's no way I could (or would want to) anticipate all of them.

With Direct3D, there were two big problems. First, D3D is handled entirely through a single interface object (the IDirect3DDevice9). This means that if I (or someone else) down the road wanted to do any special sort of rendering, it would require that I make the device available to everyone. And that brings me to the second problem: D3D state management can be a nightmare. Simply put, I couldn't trust external code to properly manage the device and the state. If the device were to get in a mucked state, it could cause serious problems (including image corruption).

Using OpenGL, not only is rendering easier and well understood by most hobby game developers, state is managed through stacks. Allowing outside code to push transforms, enable client states, render, then pop the state back to what it was is trivial. The engine won't be making use of client states or vertex arrays - just display lists and primitive OpenGL functionality. This means future games aren't limited by what I do now.

Asteroids does some of its own rendering (stars and thrust particles).

This allowed me to completely rid the engine of the GameRenderer class and a whole host of code that was just a waste of space. It always feels good when extending functionality actually reduces the overall code and what needs to be maintained.

Another benefit that I'll take a minute to mention was shown above in the OpenGLPresenter example. That is, while the game is running I can send OpenGL commands to the game to test ideas from a workspace. This is a wonderful debugging tool to have at my disposal, and I use it constantly to test state, get error codes, or even try out different rendering techniques.

Okay, so what else? It's been a while since my last progress update.

I'm still using DirectInput, and I have joysticks and gamepad controllers working. I've ported over the XINPUT libraries (for Xbox 360 controllers), but have no desire to really get those working in the engine. The interfaces are easy, but significantly different from DirectInput, so I'll just put that on the back burner for now.

Scenes are now composed of Playfield objects. A playfield is basically an Actor manager. A typical scene may have lots of playfields. In fact, the more the better, as they help to manage more than just what's being moved around and rendered. In the asteroids clone, there is a playfield just for asteroids, one for the player and the bullets fired, and one for particles and other short-lived actors. This separation of actors helps to manage z-ordering, collision detection, and more.

Another benefit to using playfields is that actors can now "kill" themselves. This would be akin to removing a renderable object from a scene graph. This is a huge burden off the game developer since actors can be responsible for their entire life cycle. The Asteroid>>explode method takes care of killing itself, as well as spawning new asteroids on the same playfield. And it just works, which is always a good thing.

Oh, wait! I almost forgot another great addition!

With the loss of Direct3D, I lost the D3DX libraries (which I didn't want to use anyway). This meant that texture loading was back to just plain, old bitmaps. But, I decided to code up some nice wrappers for the DevIL project. It's 95% complete. All that's missing are the D3D8, Allegro, and SDL functions, which were intentionally left out. But all 3 libraries (IL, ILU, and ILUT) are implemented, along with a helper object - DevILImage - that is useful for managing images loaded with DevIL and manipulating them.

The engine actually only uses the lowest level of the 3 libraries: IL. But the others are there if anyone would like to make use of them. Thanks to DevIL, the engine now supports an entire host of image formats. Also, Direct3D and OpenGL support for DevIL was pulled out into their own packages which just add loose methods to the ILUT library. This was done so that if you didn't need it, no need to install them.

I'm starting to move onto actual interface code now. I've also started playing with Seaside in Squeak a little, as I've done enough that I think getting some web hosting going so I can start publishing packages for others to use and help test. I'm a terrible web developer, but Seaside looks pretty neat and fun. If anyone can suggest some very reliable web hosting services, definitely let me know. Eventually I'd like to use Seaside hosting, but I think it will be a while before I'm ready for that.

Until the next update...

25 February, 2007

Smalltalk: An Application Language

When I started this project, the largest concern I had was that forcing anyone to use object-oriented programming would be extremely limiting or even detrimental to the final application. I've had some very bad experiences with OOP in the past: lots of hidden execution time and gross obfuscation of - and sometimes impossible to follow - code. OOP is a tool, and sometimes an extremely useful one. But, is it one that should be used exclusively?

My theory was that perhaps OOP wasn't the problem, but rather the implementations that I had used (namely C++ and its derivatives). Perhaps Smalltalk, the grand-daddy of OO languages had it right. Fast forward 7 months....

A typical program might begin with a few modules of "super" code - code that can do anything and everything. Then, as the program develops and molds, functionality is extracted and moved into new modules. As this continues, the code becomes easier to read, maintain, and extend. This is a good thing.

One of the many lessons learned (the hard way) by good programmers is knowing when to stop. Eventually a point will be reached when the returns are minimal, and if continued, the code may become so obfuscated that maintaining and extended (and performance) can be severely impacted.

The OO paradigm can have a way of clouding the judgment of otherwise excellent programmers with the allure of "perfect" code. The kind of code where everything is in it's place, only knows about what it needs to know about, all arrows point in one direction, and hides 90% of what all other code shouldn't be concerned with.

Sadly, that kind of code doesn't exist in the real world. It only exists on paper. I have yet to see any significantly large MFC program where the following macros (or similar functions) weren't declared globally:
#define MY_FRAME ((CMyMainFrame*)AfxGetMainWnd())
#define MY_VIEW ((CMyMainView*)MY_FRAME->GetActiveView())
#define MY_DOC ((CMyDoc*)MY_VIEW->GetDocument())
And then, little by little, the document class starts making assumptions about the view, and now someone adding functionality down the road is in a lot of trouble.

Let's just clear the air right now: arrows only pointing one direction are a great starting point, and should be maintained as long as possible, but someday your application needs to ship, bugs need to get fixed, and the end user is never going to care that your rendering engine just happens to know about this one, special level. The end user will care, however, if it can't render the level properly or efficiently.

Surely, hiding data and code is good, though, right? Well, do you want to just trust that the interface library you just plugged into your code base isn't using 10x as much memory as needed, leaking half of it every frame, and slowing down the rest of your application? I didn't think so. And neither do I.

Performance is always a concern - especially in games. And I get sick to my stomach when I purchase a new 2D, turn-based strategy game like Civilization IV at the store and find that it recommends:
  • Pentium 4 CPU with at least 1.8 GHz
  • 512 MB RAM
  • 128 MB graphics card
  • 1.7 GB free hard disk space
Seriously, we're talking about a 2D, turn-based game! Oh, and my laptop beats those specs, and it still runs slow! Maybe Firaxis shouldn't have just trusted some of the 3rd party code they used.

OOP is a tool, and can be very useful. But, it, like Mr. Worldly Wiseman, has a bad habit of "promising" the removal of a great burden from the programmer: having to write real code at the end of the day. For some reason, many programmers still think with that with the proper framework and a double-click, their application will just appear.

Now, the curtain lifts, and in walks Smalltalk...

- "What? What's gonna happen?"
- "Something wonderful!"

Let me state this unequivocally: Smalltalk is an application language! It's about creating applications; it's not about creating code. And there is a world of difference between the two. It's about removing the mundane barriers from the programmer so that he or she can focus on the real-deal, get it done, and move onto the next task.

Smalltalk dispenses with the "arrow" notion. (This is the term I use for those pretty code design diagrams that show object hierarchies and what systems know about, and how all the arrows should only point in one direction). That's left up to the programmer. It's definitely wise to design up front, and write the code as cleanly as possible for as long as possible. But, when it's a time to swing the hammer and make it work, Smalltalk doesn't make a programmer jump through hoops to get the job done.

Nothing is hidden. Nothing. Not even the compiler. Programmers like Ian Bartholomew can create profilers, that allow profiling every line of my application - including the core Smalltalk image - without having to write one extra line of code. Anyone can modify the core libraries to add, improve, or even completely remove functionality if and when it's needed.

Most languages that pride themselves on enabling the programmer to develop applications quickly are founded on the premise that programmers can't be trusted. Visual Basic and C# both jump to mind immediately.

These languages fall terribly short after the first 30 minutes of use. This is usually due to one, simple development truth: time constraints mean that prototypes have a nasty habit of turning into the final application. How often have you had to fix a bug or add a feature in an existing C# application at work, only to open it up and see this?
public partial class Form1 : public Form {
private void button1_Click(...) {
// ...
}
}
The default names given to forms, buttons, and other common controls haven't been updated. The original programmer was just trying out an idea that the boss then liked, but there wasn't time to go back and do it right. So, now you are wasting time trying to work around default code that is already difficult to follow, because you didn't code it to begin with.

Perhaps you even want to take [what should only amount to] 30 seconds and fix the problem by updating the name from button1 to SendButton, but soon give up when you realize that changing the name doesn't update the auto-generated function names, but did move it from a public place to a private place when it was renamed, and there are several places in code where button1 is directly referenced. Another 30 minutes wasted, and now enough code has changed that QA should probably have another round with it. More money wasted.

And that isn't even the worst case scenario. The worst case is when the button name was set originally, but it's text and implementation is now completely different from the original name given (the SendButton is actually the CheckSpelling button). Now it's harder to maintain, and a good programmer will feel morally compelled to fix it.

These are problems that seriously impede the development of applications. Applications that reduce overhead and iteration time, generate revenue, and give the programmer weekends with the family. An "application language" should free the programmer of such tedious, downright ridiculous, responsibilities, without treating the programmer as a miscreant who doesn't know how to properly manage code.

This is what Smalltalk does for me. I only write the code that matters. If I need to rename a class, all references everywhere else in my sources are automatically updated for me. If I change a method name, a browser window opens allowing me to see every caller so that I promptly fix them. These are just two of many, many, many features, all possible thanks to the reflective nature of Smalltalk, due in no small part, to it's object-oriented approach to problem solving.

I have learned to embrace object-oriented programming [in Smalltalk]. When it is implemented well (dare I say "properly?"), this paradigm doesn't just constitute another tool in the toolbox; it is the toolbox, from which everything else stems.

Since I started this endeavor to create a 2D game engine in Smalltalk, I've not once - wait, let me reiterate this - not once have I stopped, and started over again. I'm still working in the same image I started with in late August, 2006. All my designs began with prototypes (*cough* hacks *cough*) inside the main code base, and yet the code is clean. When they worked, it took minutes to reorganize and re-factor the code properly. And when they didn't, it took minutes to strip out bad code, and restore the old.

I've honestly never had more fun programming! Smalltalk has actually made programming more fun than it already was. It allows me to iterate the code so fast! The speed at which I can try an idea, see what's wrong, switch gears, or continue molding until it's right is so ridiculously fast, that it's fun. It's been stated that programming isn't fun. Problem solving and code design are fun. Programming in Smalltalk is just that - all the time. It's fun.

22 February, 2007

Vista Ready!

Well, it's been a while since I updated. A lot of things have gone into the engine, and I'm continually tweaking some things. But some co-workers are starting to gain interest in not only what I'm doing, but Smalltalk as well. So, I decided to compile a To-Go version of what I have so far and bring it in for all to see...

I'm not too excited about Windows Vista, but boy did everything just work out of the box. Instead of "To-Go," it should be called "Just Works!" It ran wonderfully on Windows Vista, both 32- and 64-bit versions. So, there's one worry for the future alleviated. I think I owe that more to Microsoft and their obsessive desire for backwards compatibility, but it's nice to see that Dolphin integrates so well with the OS that entire new versions of the OS don't appear to negatively impact it.

Seeing the little asteroids game running at over 1200 FPS and watching people try it out and have a little fun (it's still a very incomplete demo) was good. In my spare time away from work and the engine I've been typing up a very comprehensive post that will be a very large summary of all my experiences with Smalltalk and Object-Oriented Programming [in Smalltalk]. It will be a kind of "The Good, the Bad, and the Ugly." Stay tuned.

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.