Renewed LambdaCube, Bullet bindings and Stunts example

After many long hours of labour, I’m happy to announce the new release of the LambdaCube 3D engine on Hackage! Almost two years passed since the previous one, and the project spent the majority of that time in dormancy. The most important changes are the following (mostly straight from the latest HCAR):
  • removed dependency on the high-level OpenGL bindings: from now on, the library only builds on OpenGLRaw, and the OpenGL specific code is limited to the GL render system module, which we plan to move into a separate package;
  • switched to the vect library (from Vec), which was created for 3D applications from the get-go;
  • dropped fgl dependency for scene graph handling, and switched to a simpler and much more efficient solution based on bytestring-trie;
  • simplified support for procedurally created content through vector vertex buffers, which subsumes user-supplied loaders for any format as a special case;
  • introduced the LCM (LambdaCube Monad) abstraction, which hides the management of the world state and generally simplifies the engine code;
  • more efficient scene management with frustum culling;
  • added support for light sources;
  • identified the public interface and documented it (the rest is only exposed for the sake of library implementers).

Besides the engine, we updated the bindings for the Bullet physics library as well, which covers a big portion of the existing functionality in its present state. This is a raw binding that exposes a C style interface.

We also set out to create a complex example that people can immediately start playing with. This is a modern remake of the classic racing game Stunts, available on Hackage under the same name. The example serves two primary purposes: it is a test case for the 3D engine and the physics binding as well as a starting point for future users of the library. We made sure that everything compiles and works fine on the three major platforms supported by GHC. The quickest way to see the example in action is to try the Windows executable, which is also handled fine by Wine. Fortunately, the compilation process is less painful than one would expect (even on Windows!), so those who want to start hacking on it right away should feel encouraged to do so; we provided a starter guide to make the first steps easier. For the even lazier ones, here’s a taste of the example:

Plans for the future

One of the original design goals was to create an engine that can handle Ogre3D content out of the box. Unfortunately, this proved to be a bad decision, since we ended up with a lot of fixed-function legacy right away, and the implementation in its current form is rather wasteful of resources due to its naivety, especially with respect to the choice of data structures.

The next version will definitely get rid of all the Ogre3D specific functionality. Our plan is to create a small and efficient core package that allows the programmer to easily set up the rendering pipeline and manage mesh hierarchies. We are targeting the OpenGL 3.3 core profile, so the engine will build exclusively on the programmable pipeline. The current idea is to define a simple DSL for describing pipelines that’s similar to GPipe in its basic philosophy, but not embedded in Haskell, which allows us to have full control over its structure. The engine would provide an API to build pipelines (allocating buffer objects and managing shader programs) out of these descriptions and to feed them with content (textures and primitive streams resulting from the flattening of the scene), while taking care of caching and optimising context switches. All this functionality would be wrapped in a declarative interface, naturally.

While it would be possible to create separate packages to support existing formats (e.g. Ogre3D or COLLADA), we have something much more exciting in mind: integration with Blender. Blender can load content in several formats and present it in a basic form, reducing everything to raw vertex and index buffers, and the data can be accessed from Haskell code through Thrift. It is also possible to wrap LambdaCube in a rendering plugin that would display content inside Blender, thereby giving us an integrated content authoring solution. Some of this actually works already, but it’s not ready yet for public consumption.

By the way, Csaba will be present on this year’s CamHac, so if you’re one of the attendants, feel free to bombard him with questions and ideas!


  1. It looks fantastic!

    Great work.

  2. I can't get bullet working...

    In file included from cbits/Bullet.cpp:2:0:

    fatal error: GLDebugDrawer.h: No such file or directory
    compilation terminated.

  3. Just fixed this problem in bullet-0.2.2.

  4. labdacube-engine is alive! This is very exciting. I especially like the part "simplified support for procedurally created content", because I plan to do this. Loading into Blender also sounds great.

  5. I was disappointed after I downloaded lambdacube to look around few months ago. I hope you'll go into direction of proper abstraction and not Ogre copy because if you boil it down Ogre is:
    - set of rendering plugins
    - scene managers
    - handling of annoying stuff like texture format, shader options, "material" state and so on

    Its design is "OO" but extremely coupled. I found that scene managers are extremely bloated and try to sell you an engine when you asked for rendering library. Even though Source/HL2 engine is also relatively strictly coupled it at least has IRenderable/ICollideable/INetworkable.

    One big LambdaCubeMonad is potential trouble I think. I have not designed a big game in Haskell yet (like a big networked FPS) but putting stuff right into 1 big monad smells a bit too much with C++ or failed ports(turbinado).

    Have you benchmarked vect library? The usual question when it comes to every basic math ops library in games is performance.

    Blender integration might be nice for exotic uses but that's it. COLLADA has much bigger chance of interop with packages where most content gets done: 3ds and Maya. Blender's handling of .3ds is bad and .max isn't handled at all.

  6. The current state of the library is not representative of the future. In a nutshell, this project started out as a learning exercise for Csaba, and the basic structure (which was largely inspired by Ogre) hasn’t changed since then. We already concluded in our internal discussions that practically none of this code will be kept for the next version.

    By ‘big monad’ I assume you mean a big world state. Sure, we’re not in disagreement about that, and avoiding monolithic blobs is definitely a design aspect we’re not neglecting. The LCM monad itself does a bit more: besides keeping track of the state, it also provides a facility to escape computations early, which was needed by internal code; it helped us cut down on the indentation levels quite aggressively.

    As for vect, it was created specifically for 3D rendering purposes (AFAIK it was first used in demos), and it is a well-maintained package by an experienced developer, so if performance becomes a problem, it can be addressed promptly.

    Finally, the Blender story is not the end of the world. There’s nothing stopping you from creating a LambdaCube-COLLADA interop package. In fact, the core engine will be designed with such extensibility in mind (as mentioned in the post, this is pretty much the same as allowing procedural content in general). However, Blender is useful for gaining access to a lot of existing content with very little effort, which makes it at least a logical short term solution regardless of its warts.

  7. Looks like bullet needs a dep on c2hs. This work looks fantastic!

  8. Very cool, really looking forward to a pure functional graphics engine. Keep up the work! I think supporting the Ogre format is a good decision because it's very widespread.

  9. Aidan, to my knowledge, you cannot depend on a package that only exposes an executable, because Cabal doesn’t realise that it’s already in place, so it will be reinstalled every time you install yours.

    As for purity, we certainly have some pure transformations (e.g. scene graph flattening), but it’s still far from ideal. The redesigned engine is going to be a lot more functional in spirit and API.

  10. I checked vect lib properly and it looks really nice. When I was looking at lib list I was doing it hastily and confused it with some other library that had even less than Data.Tensor. Good choice with vect.

  11. Outstanding. Don't give up.

  12. Need to fix links for LambdaCube!