Wednesday, December 28, 2011

QuickStart Engine v0.26 Preview, Nuclex GUI

For a long time now I've wanted a single GUI in the QuickStart Engine's demo, to make things easier to learn, and over the last few weeks I've been thinking that if I am going to go through the trouble of setting up a GUI for the demo that I might as well setup the GUI such that the user could put it in their own games. However programming a full featured GUI is a very large task, the Nuclex GUI framework alone has almost as many code files as the QuickStart Engine! There was really no need to write my own GUI so I decided to find a GUI framework suitable to be used in C#, XNA, and games, and I believe I've found that with the Nuclex GUI framework.

Here's a screenshot of a simple draggable window in the game with a couple of buttons.

Before this is released I'll want to expose simple ways of connecting the GUI to a game (for example, letting buttons send game messages might be handy), and I would also like to be able to control the transparency of the window. I would like to just include the Nuclex binary files (.dlls) in the project rather than include the Nuclex GUI sourcecode, but it looks like I might have to make some changes to get the transparency stuff that I want.

Thursday, December 15, 2011

QuickStart Game Engine v0.25 Preview: Buoyancy/Density Physics

I'm currently working on v0.25 of the QuickStart Game Engine, which will include a handful of performance enhancements, but most of the work has gone into a new component called WaterVolumePhysicsComponent. This component lets you describe a volumetric region in which water physics will be applied to any dynamic physics body, this means that water will now apply drag to anything within it, it will apply a weight to objects as they leave the water (because they're still "wet"), and it will take into account the density differences between the water and the physics body, allowing less dense entities to float, and denser entities to sink. The density differences between the body and water will also determine if the entity just barely sits near the top of the water, or if it's incredibly light it will float almost entirely on top of the water.

In previous versions of the engine there has been a yellow sphere that could be fired by pressing spacebar, in the new demo there will be two new spheres, a blue one fired by pressing Left Ctrl, and a red one fired by pressing Left Shift. The blue sphere will be extremely light, letting it rise very quickly out of the water and float almost entirely on top of the water, the yellow sphere will be medium density which is slightly less dense than water, letting it float to the top but not sit as high above the water as the blue sphere, and the red sphere will be very heavy and dense, letting it sink to the bottom of the water.

Density is really all that matters in terms of buoyancy in the water, but it also affects the amount of force and momentum an object has; All 3 spheres are the same size, but different densities, so each sphere weighs much differently than another. If you fire a blue sphere at one of the wooden crates in the demo, it doesn't have enough weight to move the crate almost at all, but the yellow sphere can give it a small nudge because it's a higher weight, and the red sphere can knock the crates around pretty good because they're much heavier than the crates. It is fun to fire the different spheres at things and watch how they act differently in the water.




I expect version 0.25 to be released in the next week or two.

Wednesday, December 7, 2011

XNA 4.0 == Me pulling my hair out

XNA 4.0 has been out over a year now, but I've only just recently had the time to use it. Shawn Hargreaves from the XNA Development Team explained how a lot of things would be broken by XNA 4.0 (although these were all good things in their opinion), and boy he wasn't kidding. As a result of the changes, here's what I've gone through in my game engine trying to convert it from XNA 3.1 to XNA 4.0. Here's a link with a summary of the breaking changes.

1.) Clipping planes are no longer supported within XNA. Clipping planes were supported directly by DX9 hardware, but not DX10 hardware, so in an effort to be forward looking, support was removed from XNA 4.0. I had to put all clipping plane calculations into my shaders. This means every single mesh that could be rendered in a scene with water (pretty much everything) had to have clipping plane stuff put into the shaders. Annoyance factor (6 out of 10). Read more here.

3.) Point-sprites are no longer supported, also because they're not supported by DX10. This affects particle systems, which often used point-sprites to represent particles. Using a point sprite meant 1 vertex per particle, but without a point sprite you need at least 4 vertices to represent a square polygon (quad). This meant having to add an index buffer to the particle emitters, and changing the way particles are created and updated. It also has performance implications, non-rotating particles render a bit slower on average than they used to, but rotating particles actually perform better, so it's not a total loss.
Annoyance factor (4 out of 10). Read more here.

3.) RenderTarget2D was changed so that it derives from Texture2D and you can no longer call .GetTexture() on it, additionally the clearing of render targets was changed which forced me to shift around some code. Annoyance factor (2 out of 10). Read more here.

4.) Number of primitives that can be drawn in a single draw call has been limited to 1,045,575. As part of my visual debugging I had a way to render a small line for each vertex of the terrain heightfield, however on a map that is 1024x1024, plus a few other objects on screen, that is enough to push the vertex count past the new limit. This one actually isn't that annoying for me, other than the fact I now have to fix it, but apparently some DX10 cards don't allow more than this per draw call so it's probably best that I fixed this anyway. Annoyance factor (2 out of 10).

5.) The quality of SpriteFonts has been decreased. It wasn't really a performance problem in the past, so I'm assuming this was done for performance reasons with Windows Phone 7. Read more here for a comparison of XNA 3.1, and XNA 4.0. Additionally the linked article provides a font processor you can use if you would like to maintain the high quality sprite fonts. Annoyance factor (1 out of 10), annoying that quality needlessly drops in my engine, but at least I didn't have to do any work to get it running properly.

6.) Here's the one that gets me the most. In an effort to unify hardware requirements for games, XNA now forces all games to run in one of two graphics profiles, called 'Reach' and 'HiDef'. The problem is that 'HiDef' is only DX10 and higher, and while 'Reach' supports DX9, it had to make sure it supported almost all DX9, so all kinds of stuff you could do in DX9 with XNA 3.1 is now gone. So I now have three choices with my game engine (that I can think of).
  • I can use the 'Reach' requirement only for the engine, and I lose support for many graphics techniques that have been used for 6+ years, and lose features that I've had working in the engine for years.
  • I can use the 'HiDef' requirement only, and drop support for all DX9 hardware (about 40% of the GPUs out there at this time). This seems ridiculous to me knowing that everything in my engine runs fine on about 80% of DX9 GPUs.
  • I can try and use both of the requirement types, which means I have to duplicate all of the game engine's assets so it can cover both sets of assets (one in each type of graphics profile). This puts a huge burden on anyone making a game using the engine that wants to also support both formats.
All of these options are pretty bad IMO. Here are the problems I'm having with the new 'Reach' format they've imposed.
  • They dropped support for most texture formats that you would need to do self-shadowing (meshes casting shadows on to other meshes). I have to entirely re-write my self-shadowing implementation to not use depth shadow maps if I want to support the 'Reach' graphics profile. Read more here.
  • They also dropped support for texture sizes larger than 2048x2048, which many DX9 cards support. This means that shadow quality based on standard depth shadow mapping will be cut to 1/4th of what it could be in XNA 3.1.
  • They dropped support for 32-bit index buffers, which means that for large terrains I now have to render it in smaller chunks. The sweet spot I had found for most machines was 512x512 chunks for terrain, which limited how many frustum against terrain axis-aligned bounding box checks I had to do, and limited the amount of draw calls that were being made. The largest that can be done with 16-bit index buffers is 128x128 chunks. That means if my camera previous had four 512x512 chunks in view, I had four draw calls, and now I would have up to 64 128x128 chunks in view. In reality it would probably be less than 64 chunks because the smaller chunks would give more granularity to the frustum checks, but overall I would have many more frustum checks, putting more work on the CPU, and more draw calls but potentially less geometry, which depending on the situation could put more or less work on the GPU.
  • They dropped support for non-power-of-two texture sizes, which means the quality of the water reflection and refractions is either going to drop, or it will be higher than it needs to be, hurting performance.
There are likely other restrictions I haven't run into yet, but I'm sure others running into problems are also bothered by this. I'll admit it has the one major upside, and that is no longer having to worry about something working on a developer's PC and not on an end-user's PC. You either meet the requirements of the graphics profile or you don't, that simple. Sadly I believe they set the requirements for the 'Reach' profile as low as they did for Window Phone 7 development, at the expense of killing features for a large percentage of DX9 users. Honestly I'm not surprised by this, it's somewhat standard for Microsoft to make a change that benefits them, and tell everyone else to deal with it. This will make Windows Phone 7 development easier, give people more reasons to upgrade to DX10 or DX11 (both Microsoft proprietary formats), and those newer GPUs give customers more reasons to upgrade to Windows 7 or the upcoming Windows 8. I do feel that Microsoft is slowly trying to pull XNA away from PC development, they're continuing to restrict the ability of developers to use XNA to create a PC-only game.

Anyway I'm going to mull over things for another day or so before I decide whether to rework a handful of features to try and get things working on the 'Reach' profile, or if I just abandon DX9 support all together, which would be painful now but would matter little within the next couple of years as DX9 becomes a distant memory. Luckily my engine is open-source and not making me any money, so I don't have to worry about angering any potential paying customers by telling them that if they use the engine that their game can't run on DX9 hardware.

Annoyance factor (9 out of 10)!

Read more here about the 'Reach' vs 'HiDef' changes in XNA.

Tuesday, December 6, 2011

QuickStart Engine v0.24 coming soon

I've been hard at work on the next version of the QuickStart Engine, trying to get some much needed features into the engine while I still have some free time. I predict I'll have this next version checked in within the next few days.

Here's my changelist so far:
  • Messages now have a new member called 'protocol'. This gives the message properties so that it can not return after being handled by a single source, but also continue on to other components. It also lets the sender and handler know the intent of the message, for example, a SetPosition message has 'Broadcast' type, which means it is going to be broadcasting a change from the sender of the message to any component that is listening. In contrast, a GetPosition message has 'Request' type, which means only a single component should handle the message, and the handler is expected to return new information in the message. And finally there is the 'Accumulate' method, which allows the user to send the message to multiple components, and each one will have a chance to make changes or add to the data.
  • ViewMatrix, ProjectionMatrix, and ViewFrustum data members in BaseEntity were moved to the CameraComponent class. This will save on memory by not having these exist on every entity, and also will remove clutter from the BaseEntity class. This did cause some changes to the variables passed through various functions, mostly in the GraphicsSystem class.
  • When using the QSGame.QueueMessage method message protocol is enforced, to prevent the user from sending a request message, which would fail because request messages must immediately return results to the caller.
  • Changed the default physics deactivation values for the engine, added constants for this that can be changed based on the game and scale used. This will result in a better framerate when there are lots of dynamic physics objects in a scene.
  • Entities and components now receive a call to a new function called 'AddedToScene', which is called whenever the entity is added to a scene. This allows the entity and components to do things that normally required a game message to be sent, which couldn't be done until an entity was in the scene.
  • LightComponents no longer need to have InitializeLightDirection() called manually on them to properly rotate the light, this is now done automatically within the component.
  • Entities with SkyComponents no longer need to be manually attached to the camera, they will now handle this on their own.
  • GeometricPrimitiveType enum uses 'Box' now instead of 'Cube', to match the ShapeType enum.
  • Terrain (which was a class derived from BaseEntity) is now TerrainComponent and is derived from BaseComponent. This makes it easier to load Terrain through the new loading method (XML templates).
  • Constant movement component now allows for a constant direction movement, not just sine-wave type of movements.
  • The current render camera is now notified of any changes to graphics settings.
Bug fixes:
  • Light direction shader parameter now has a correct .W value of 1.0 rather than 0.0
  • Cameras will now automatically assume the aspect ratio of the viewport/window rather than defaulting to a specific preset value (unless you explicitly define one).

Features:
  • Entities and Components can now be loaded entirely from XML definition files. This is a large step towards supporting a level editor that can save out entire scenes in a compact format. In the mean time it means that designer types can create entities through XML rather than C#.
  • Multi-sampling anti-aliasing should work once again. Edit your settings.xml and set "IsMultiSampling" to true to use it, but be aware on PC it will generally cut the framerate in half.
  • Texturing and normal mapping now work properly. Demo has been setup with a couple of textured and normal mapped entities.
  • Ability to create physics box and sphere shapes based on the vertices in a model. This allows you take a model and wrap it in box or sphere physics. Previous this only worked with TriangleMesh shapes which are static so their uses are limited.
  • The full component list stored in BaseEntity is now a dictionary with a 'key' of ComponentType. This allows programmers to easily get a component from an Entity for direct access as an alternative to creating and sending game messages.
  • New physics class for Terrain, called TerrainPhysicsComponent. This allowed us to move all heightfield specific physics out of the PhysicsComponent and into its own class. This also makes it easier to load terrain.
Here's a sample screenshot showing texturing works. And every entity in this scene is now loaded almost entirely from XML files rather than code.