Playing with the Emscripten port of Box2D

Some time ago I had the idea of porting the concept of a great old game called Mindrover to the web, as an excuse to do something with my LiteGraph.js library (a javascript to create modular graphs similar to PD).

Motorclub, using graphs and physics

Mindrover is a game where you design your vehicle to fulfill some challenges. You cannot directly control the vehicle during the challenge, instead you must add sensors and thrusters around the chasis of the vehicle and wire them to react according to your strategy. A very interesting and fun game. Sadly it seems that the mechanics of the game havent caught up with more developers.

The only constraint to port this game to the web was that Mindrover uses physics to compute the movement of the vehicles. I thought about simplifying it to 2D physics using a library like Box2D.js but still I didnt know what the performance was going to be.

So last weekend I tried to put all the pieces together and do a simple demo just to see how feasible it would be.

For any real-time application’s programmer performance is always a big concern, and when you are constrained by a scripting language as Javascript the burden becomes heavier. So the main problem here was if Box2D.js was going to be able to deliver the performance required.

I’ve seen many demos of Box2D that look quite good, but they are always in a very narrow scope and you never know if they could be running for an hour or the memory leaks are going to devour the browser.

Integrating the Box2D.js version was easy, but sadly the most famous version of Box2D for the web is a port of the Actionscript version, which is a port of the C++ version. That doesn’t mean it will be bad by definition, but I knew that on the long run it could become a problem (bugs not resolved, optimizations on the C++ version not reaching the js version).

So after having a running version of my game I thought about switching to Kripken emscripten version of Box2D. I though I could be a nice experiment to work with a javascript library that comes straight from C++.

What is Emscripten?

Emscripten is a ‘transpiler’ that using the LLVM allows to transform C++ code to Javascript, something that some years ago would seem impossible. You give it a C++ code that do not rely in OS calls or thirth party libraries, and it generates an equivalent Javascript code.

Internally what it does is reduce all the actions of the C++ code to numerical operations (which is what assembler is about) and apply them using his own memory HEAP, allocated using typed arrays in Javascript.

So when the library is parsed in the browser, it allocates an ArrayBuffer of few megabytes for the HEAP, and every action performed by a function of the library modifies that array. And that amount of memory is fixed during the compilation of the code, independently of how you use the library in your web.

The library internally do not use objects, instead it used numbers that behave like pointers, with the address inside the HEAP array where the instance is allocated.

And because it is not constantly creating objects and uses exactly the amount of memory needed for every action, it is known to generate code that runs very fast. Also because of the simplicity of the actions, browsers can optimize heavily the code, till the point where Mozilla has achieved close-to-native speeds (check the project ASM.js).

Interoperability

So when we want to integrate our existing javascript code with a library that comes from Emscripten we just include that script and all the library is contained in an object that behaves like a namespace.

So how do we interact with that code if it is not using regular javascript objects?

From our code we can instantiate any class from the C++ library using the regular new operator in Javascript:

var point = new Box2D.b2Vec2(0,0);

But keep in mind that the content of the resulting object won’t be as any regular Javascript object. Instead if we use our debuging tools we will see that the object only contains one number (‘a’: the address of the real instance in the HEAP), a function that behaves like a constructor (‘c’) and the __proto__ pointing to the object that contains all the methods from the class.

Check the content of an instance from Box2D

Check the content of an instance from Box2D

These methods will take that address and operate on the values in that region of the HEAP memory using the address as an offset.

That means that under no circunstances we can pass to any C++ function a type that it is not a Number or it is not an instance from the same library. So no arrays, objects or functions, even passing strings require a function that transfers them to the HEAP.

If we insert a new property inside an object it won’t crash but we wont see it in the future when we expect it, mainly because objects are not stored as we are used to, they are destroyed when no functions are using it, because the state of the instance remains in the HEAP.

What about accesing attributes from the class that were public and didn’t have setters or getters?
Well, Emscripten generates automatically getters and setters for all public attributes, you can call them like this:

var x = myobject.get_x();
myobject.set_y(10);

And what about functions that expect arrays of some sort (something like a vector of points)?
That is more tricky, there are some functions in the main namespace that allow you to allocate memory and pass it to functions like a regular pointer, but you need to be aware of the memory management.

The same with functions returning pointers, you just get a number instead of an object, and to get the object you need to call the wrapPointer function that constructs the javascript object extracting the info from the HEAP.

var point = Box2D.wrapPointer( pointPtr, Box2D.b2Vec2 );

Memory management

So if the library works internally as C++, how does the garbage collector of Javascript knows when an object reference allocated in the HEAP is no longer in use so it can free it?
Well, it doesn’t, which means that unless you are very careful with your memory footprint you are going to see this error very often:

Assertion: Cannot enlarge memory arrays in asm.js. Either (1) compile with -s TOTAL_MEMORY=X with X higher than the current value, or (2) set Module.TOTAL_MEMORY before the program runs."

Assertion: Cannot enlarge memory arrays in asm.js…”

This happens when the library tries to allocate more memory and the HEAP is full, then you have two options: finding the memory leaks or increasing the amount of memory allocated by the HEAP on startup, sadly thats only possible during compilation, so you will need to download CLANG, LLVM and Emscripten to do so.

And about memory leaks, be careful, the library itself comes with some Javascript helper functions that had memory leaks, and after 2 minutes the library was crashing. It took me some time to find the error (copyVec2 and other helpers create copies).

So remember to call the destroy function after you are not going to use an instance (only if you created that instance):

Box2D.destroy(myvec);

Callbacks

What about callbacks? Can we overwrite an internal function?
Yes, there are methods that allow you to overwrite the Virtual Functions Table of any instance, it is not as straightforward as we are used to on Javascript, but it can be done. Here is one example where I create a Callback instance (it has to be instantiated), and replace one default call by my own call:

	var myRaycastCallback = new Box2D.b2RayCastCallback();
    Box2D.customizeVTable(myRaycastCallback, [{
    original: Box2D.b2RayCastCallback.prototype.ReportFixture,
    replacement: World.prototype._raycast_func   // <-- this is our callback    
    }]);
	this._raycastCallback = myRaycastCallback;

Performance

So after all this work I can say that the performance is very good. I have tested it with 1000 balls and the framerate is not being affected. I’m glad I took the effort to switch to the emscripten version. And the good thing is that the github is very active. I have reported several bugs I found and it seems they are being fixed.

If you want to check the performance by yourself try the demo of my upcoming web-experiment: Motorclub, it is not finished but it is advancing steadily.

2 Responses to “Playing with the Emscripten port of Box2D”

  1. Motions-Media JavaScript: Emscripten erste Versuche unter OS X | Motions-Media Says:

    […] wie naiverweise Gedacht ;-) Nach einigen Recherchieren bin ich auf diesen Blogeintrag “Playing with the Emscripten port of Box2D” gesto├čen, der die Eigenheiten vom Emscripten kompilierten Box2D JavaScript Code genauer […]

  2. Manideep Says:

    Iam also working with kripken’s version.I wanted to access user data using (GetUserData) but it simply returns a single digit number eveytime.can you please explain me how to fix it .

Leave a Reply


7 − three =