Archive for August, 2005

Progress report

Monday, August 29th, 2005

This weekend I finished the fundamental properties of the particle editor. This includes an interface to the GUI system and of course the ability to display particle.

I have a model viewer working as well, which I am going to convert and expand to a material editor.

Save and load isn’t implemented for either one yet because it would be pointless to implement it without knowing the specs of what I need yet.

Fortunately, it’s been 10X easier and faster to write my second editor, the material editor, than the first one since all the GUI elements are already debugged and working. So it may be done as soon as this week.

In other news, Novodex didn’t respond to me. I guess they don’t want people offering them business?

Newton revisited

Thursday, August 18th, 2005

The primary way Newton is used is to use basic primitives and place them as an overlay with the 3D model. The primitives are triangles, cylinders, boxes, and similar. You can also create a convex mesh but the documentation said this is much slower and more memory intensive.

What I was originally looking for was a physics library that just worked with any arbitrary mesh.

Once I found out Newton can’t do that I had 3 unappealing options to choose from.
1. Write my own physics editor, that would let designers create a physics model using primitives and materials.
2. Force all ship designs to be convex and accept the memory and speed hit
3. Write my own physics

I could always switch libraries to something more powerful of course. Novodex is the next step up but they are not free. I contacted them but if they ask more than a few hundred I can’t use it. Considering it is one of those libraries that don’t show the price I’m assuming it’s a “If you have to ask, you can’t afford it.”

Out of the three options I think #1 is the only thing that can achieve my requirements for both gameplay and design. I was really bummed out at first since this puts the schedule back a week but at least I discovered this early on.

If I’m lucky Novodex will get back to me with an offer I can use. I’m pretty sure a library that powerful would have a built-in editor into 3DS Max which will be far more than anything I come up with.

Physics Engines

Wednesday, August 17th, 2005

I expected to get a lot done today but I’ve been sick so progress is pretty slow. Anyway, I’ve been looking at physics engines. I found 3 right away: ODE, Tokamak, and Newton Dynamics.

ODE was my first pick but the included projects wouldn’t compile. Faced with potentially several hours of getting it to work, I checked around and it didn’t seem like anyone was using it. The project has not been updated for a year and a half. So as much as I like open source I moved on to Tokamak.

Tokamak looked very promising from the webpage. But on download they only offer DLLs.

Newton Dynamics looked competent and the projects compile. The documentation is about what you’d expect for a free library, if you had low expectations. The samples are interesting but much less impressive than what I’ve seen in commercial libraries. This isn’t necessarily a failing of the engine though. I like that in the documentation the author points out the same principle that I follow: an API is supposed to be a black box. He demonstrates his principle in the distribution – there is only one header file and you have your choice of DLLs or static libraries.

As usual it took a significant amount of trouble to get my behemoth of a solution compiling. Total time spent was only about an hour though, which is far better than certain other libraries.

When I feel better I’ll be back to try out some physics in action.

Open letter to API authors

Wednesday, August 17th, 2005

When people download your API, they don’t care about your API. They care about what it can do for them in the context of getting their game done. This means that they don’t want to have to read or change the source to compile. They don’t want to have to search Google for a single minute to get around compiler or linker errors. They don’t even want to compile the binaries. They want to add a few header files, a binary, and compile straight away in any configuration. If any special settings are necessary, they want those settings to be immediately and obviously apparent available in the manual. The settings should be as clear as possible, with screenshots and exact names when appropriate. It should work the first time and by work I mean do what the user thinks it should do, not what you think it should do. Lastly, it should not force them to change a single line of code in their program. They should add your code, not modify their code to fit the way you think code should be designed.

You think people don’t mind checking the source? In RakNet I’ve had people bitterly report problems that could have been resolved in 30 seconds by looking at the source. Let me be clear: When people complain about problems in MY api you know it’s obscenely simple stuff because I hide the complexity. You, unless you are the author of Irrlicht, probably do not. I’ve had people complain about not being able to compile in Dev CPP. I, who had never used it in my life, was able to compile my library in 10 minutes. From that point on I included a Dev CPP library in future builds. When I forget to update the library, people complain although the mistakes are trivial to fix, such as a file that no longer exists. People DO NOT like to spend time resolving problems getting your API to work, nor should they.

Given the kind of user I just described, imagine giving one of them Open AL and telling them to use it in source code format. There is no function level API documentation. There are no compiler instructions. It won’t compile unless you include the exact specific files, with no way to know which files they are other than trial and error. You then have to change the code in 3 places, trace through the source to resolve a crash, set a preprocessor definition, and manually call DLLMain code, either by modifying the source or writing a new file to do it. Lastly, you have to resolve a DirectX GUID dependency by including dxguid.lib, something not clear by from the errors that come up.

Don’t even bother writing an API if you are not going to make it user-friendly. If you’re going to cost your end-user time to use your library, they will just use something else.

OpenAL resolved

Wednesday, August 17th, 2005

I resolved the bugs with OpenAL
– They initialize global variables in DLL main – which isn’t called if you use a library or source.
– They include mutually exclusive cpp and c versions of 3 of the same files. All the cpp ones do is call the C ones in some #define so not only was it an pointless thing to do but made it so if you included both it wouldn’t compile with very strange errors.
– They changed it so you can no longer check for errors after querying the device but before creating the context. I think this is actually a bug, since querying the device is something that should potentially return errors.

I’m honestly curious as to why people knowingly release APIs in complex configurations that cannot compile in other configuations. It could be that they don’t know, but I think this must be something people complain about a lot. It could be that they think people won’t mind fixing it. Possible, but it’s non-trivial. I had to create a new file for example to call the DLL main contents in a constructor and destructor. I imagine novice users would complain continuously and give up shortly thereafter. It could be they don’t care. Maybe they don’t have professional pride in their work because it is open source.

One good thing about Microsoft is the projects they release actually load and build in different configurations.

Documentation? Who needs it?

Tuesday, August 16th, 2005

So here I am, doing what I usually do on my game. You get two guesses:
1. Adding features
2. Screwing around with compiler settings, trying to get third party libraries to work

If you guessed 1, you haven’t read any other posts on this blog.

So this time it’s Open AL. Back with version 1.0 I got it working quickly and with a minimum of hassle. I updated to 1.1 it’s like they purposely made it hard to compile. ONE API has FIVE projects, two of which are DLLs and 3 of which are static libraries. There’s no documentation on why there are 5 projects or what they do but who needs it when you have such descriptive names as “ALc”, “ALu”, and “ALut”?

After like an hour I got the damn thing compiling to a library, only to find out that it crashes every time I run it somewhere in assembly code. So I give up on libraries and just try to compile the source. Burn past about 100 warnings, get it compiling, and still crash in the same spot.

I’m still working on it. I’m just happy there is only one more third party library to deal with: Newton Physics. Hopefully that won’t be too bad. I wish more people took a lesson from the Irrlicht author and actually designed libraries in a meaningful robust fashion and include documentation.

Irrlicht is well-written

Tuesday, August 16th, 2005

Irrlicht is the first library I’ve ever used where
1. I feel all features are useful
2. I’m able to mod it without a headache
3. I can use the library directly, without feeling like I need to make my own wrappers.

With no other graphics library would I ever consider using their input library. Originally I was going to find something cross platform too. But for the heck of it I took a look at what Irrlicht does and it’s actually quite simple, sensible, yet does everything I need. It doesn’t force me to use strange design architecture and ties in well with their whole system of gui elements, cross platform capabilities, and event notification.

I was able to mod the file loader quite easily. Everything I needed was straightforward, in a single file. When I was looking at Torque before there were so many files that did so many things I got depressed just thinking about it.

Lastly, all the functions I’ve seen so far are powerful and simple. I remember when I used Ogre one of the first things I did out of the tutorial was to make a wrapper for the camera, since the camera was too low level, with many unnecessary functions that still somehow forced you to use a certain design paradigm. Sort of like MFC…

The author’s code is readable, clean, and well-documented. No Hungarian notation at all 🙂

Good job!

State design

Monday, August 15th, 2005

I’ve been thinking about a good state design system lately and how to address common problems in other games.

The problem in most other games is that states are designed to be modular, but don’t turn out to be, both in functions and in data.

Functionally, a game may have an options state, and a game state, and may later decide to show the options state while running the game state. If this is not defined in advance, the likely fix is just to call the render function of the options state from the game state. It works, but it’s poor design that can easily cause bugs. For example, the render function may rely on data setup by the enter function of the state. If not now, then maybe later when someone adds it and didn’t know about that dependency.

The same holds true for data in non-obvious ways. When I was working for nFusion we had to access game-specific data from the main menu screen, in order to determine if the continue button should show up or not.

You could just make the data global, or essentially global, such as putting it in the “Game” or “Application” class. However, this is bad design. You want to make data accessible to exactly the classes that need it, no more and no less. One solution is to put the data into a higher level shared class. For example, at my job we have an AI class and various controllers that interact with it. CONTROLLER SPECIFIC data sometimes needs to be shared between controllers that were designed to be independent. This generally goes in the AI class, which is bad design. We now have this huge AI class with a ton of data members, half of which serve some special purpose.

The solution I came up with is pretty simple but I think solves these problems with a minimum of complexity:

The application class contains a state manager
The state manager contains a stack of states, which are instantiated or deleted as needed.
States are unique in the state manager. No more than one instance of a particular state can run at the same time
States are independent and contain implementation functions and capability functions.
States refer to each other through enumerations, rather than pointers.
When a state manager gets an event (keypress, render, update), it goes to the state manager, which then processes it to each state in reverse order. For each of these, a state can trap an event so it does not progress to higher level states.
Data that is shared between states is held in a reference counted pointer.

How this works is easiest to show in an example:
Game states, calls state manager to create the main menu

The main menu does not already exist. It is created and put on top of the stack.

Query, update, and render calls to go the state manager, which sends the events to the main menu, which handles the events.

The user presses options. The main menu state tells the state manager to create the options state. As it does not already exist, it is created and put on top of the stack.

Since events are processed in reverse order, the main menu state renders and updates first. However, the main menu state queries the state manager and finds it is not at the top of the stack. Therefore, it renders a dimmed version of the background. All events are passed through to the options screen except the keypress “alt-z” which plays a main menu specific easter egg sound.

The options screen updates as usual.

Now the user presses esc. The options screen interprets this as “Remove myself from the state manager” and the user is back at the main menu.

The user presses “Start game” which tells the state manager to remove the main menu from the stack and create the game state.

In the game state, the user now brings up customize ship menu (which was also available from the main menu). The game continues to run in the background fully, but keypresses and mouse presses are not processed. The user then brings up the options screen while the customize ship menu is open.

The customize ship menu is not designed to run unless it has primary focus (top of stack). Therefore, the allow render and allow update calls return false. The options screen shows up over the game screen. The user presses esc, and as before the options screen is removed. Since the customize ship menu is next on the stack, it shows up again and none of the user’s changes were lost.

The user presses esc again, and goes back to the game.

Shared data will be in singletons that are referenced counted and delete themselves when they are no longer used. States will get a pointer to the singleton when they are created, and release the pointer on free.

Next steps in technical investigation

Monday, August 15th, 2005

I finally have 3D graphics appearing in both IE and Firefox. It takes some setup by the user. Once I pay the fee (IE) and provide an installer (Firefox) this should be easier.

Now that I have 3d graphics appearing in the webpage it’s time to test out other major, risky features:

Input
Sound
Level editor

I’ll look at these over the coming weeks but I don’t think any of them will be a serious problem.

Some time wasted, some progress made

Saturday, August 13th, 2005

Last night, with a helpful download link from someone on the Games-L mailling list, I got a Mozilla plugin working in about an hour. I was pretty happy about that, because the same task with Active X took a week. I spent another hour trying to figure out how to get the data in the SRC tag into the C++ code but got nowhere. Thinking this should be something easy, I ask around in some online lists and go watch Battlestar Galactica.

This morning I check my email, expecting to find numerous relies about how stupid I am and pointing out some obvious answer. However, aside from spam there was nothing there. So I get back to work (it’s 8AM or so). My initial guess was that you were passed the file data in the startup code. This is not an unreasonable assumption in my opinion. I pursue this guess for about an hour but just can’t find the file data anywhere. I browse the web, find someone elses’ open source plugin, figure out how they downloaded the file, and painfully converted that to work with what I had. I set it up as a synchronous download, so I just get the whole file in one function call. It’s 11:00 AM now. As the final step, I decide to try out asynchronous download and add a progress bar. I change my download to asynch and suddenly I get two asynch reads rather than one. It turns out the original file was downloading asynch the whole time. Great…

I’m done dealing with the Mozilla plugin at this point. My next step is to get the custom LZMA pack that I wrote and convert it from file->file to memory->memory. This is harder than it sounds, because the LZMA author decided to implement his own version of cross-platform COM. So rather than the simple step of changing a few fopen lines, I now have to implement 2 custom COM classes as a memory stream class and painfully debug them. This was a risky stage in development due to the difficulty and reliance on 3rd party code. I was lucky that it worked without having to go too level because I would have given up and used Winzip instead rather than try to debug COM. Once again I’m thankful for open source libraries. This would have been impossible to accomplish otherwise.

Now that it works I have 3 different ways to launch the game. The Mozilla plugin downloads the data and starts a thread. ActiveX, for IE, gets the data from a resource and starts a thread. The EXE launcher just loads the regular data files from disk and runs in the default thread. They all run the same game code so in theory, though not very well in practice, I should be able to work from one launcher and have the other two automatically work.

Solution with firefox launcher

The next step is to finish up my resource manager, so fopen calls to Irrlicht go to that instead. If and when that is done I can finally see models in the browser.