/ Low Level

Making a Bullet physics wrapper for DartVM

I wanted to make clustered 3d physics simulation in Dart but there were no physics engines or wrappers for any other APIs, my options were running the project in chromium and using emscripten to compile some C/C++ physics library and interface with it through dart's javascript interface, use some FFI library, or write my own native extension

Since this this is meant to be a server I'd like to stay away from chromium, right now there are no FFI libraries for DartVM that work well with C++ so my only option is a native extension.

The article here is a great introduction: https://www.dartlang.org/articles/dart-vm/native-extensions

This API isn't safe for C++ though, Dart_PropagateError uses C long jumps that don't properly unwind the stack. To make sure I don't leak anything I wrote a utility to convert these errors into C++ exceptions:

struct HandleException {
    explicit HandleException(Dart_Handle handle) : handle(handle) {}
    Dart_Handle handle;
};

static Dart_Handle handleError(Dart_Handle handle) {
    if (Dart_IsError(handle)) throw HandleException(handle);
    return handle;
}

template<void code(Dart_NativeArguments arguments)> void safeHandle(Dart_NativeArguments arguments) {
    try {
        code(arguments);
    } catch (HandleException& handle) {
        Dart_PropagateError(handle.handle);
    }
}

In your ResolveName you wrap your functions like so:

if (strcmp("foo", cname) == 0) result = safeHandle<foo>;

Catch dart errors like you normally would with handleError:

handleError(Dart_ListSetAt(out, 0, Dart_NewDouble(origin.x())));

On the dart side we have classes which act as an interface to an underlying C++ functions, holding a pointer to a struct:

import 'dart-ext:phys';

class World {
  int _p;

  World() {
    _p = _n_construct();
  }

  int _n_construct() native "world_construct";
}

In order to make it easy to make constructors I made the following helper template:

template<typename T, void destruct(T*)> T* constructWeak(Dart_NativeArguments arguments) {
    auto s = new T();
    Dart_NewWeakPersistentHandle(
        handleError(Dart_GetNativeArgument(arguments, 0)),
        static_cast<T*>(s),
        sizeof(s),
        [](
            void* isolate_callback_data,
            Dart_WeakPersistentHandle handle,
            void* peer
        ){
            destruct(static_cast<T*>(peer));
        }
    );
    Dart_SetReturnValue(arguments, Dart_NewInteger(reinterpret_cast<int64_t>(s)));
    return s;
}

void d_world_destruct(WorldState* state) {
    delete state->dynamicsWorld;
    delete state;
}

void d_world_construct(Dart_NativeArguments arguments) {
    constructWeak<WorldState, d_world_destruct>(arguments);
}

Everything else is handled in the native extensions article, I've implemented enough of the Bullet API to do the hello world demo here: http://www.bulletphysics.org/mediawiki-1.5.8/index.php/Hello_World

void main() {
  var w = new World();
  w.setGravity(new Vector3(0.0, -10.0, 0.0));

  var planeShape = new StaticPlaneShape(new Vector3(0.0, 1.0, 0.0));
  var planeBody = new RigidBody(shape: planeShape, mass: 0.0, restitution: 0.9);
  w.addRigidBody(planeBody);

  var ballShape = new SphereShape(1.0);
  var ballMotionState = new MotionState(new Vector3(0.0, 30.0, 0.0));
  var ballBody = new RigidBody(shape: ballShape, motionState: ballMotionState, mass: 1.0, restitution: 0.5);
  w.addRigidBody(ballBody);

  for (int i = 0; i < 300; i++) {
    w.step(1 / 60, 10);
    print("${ballMotionState.pos.y}");
  }
}

And it works!

Full dart code here: https://gist.github.com/PixelToast/25bafdba5dc3a2182ce199886c423e1a
C++: https://gist.github.com/PixelToast/6150a51af3ae6eff127aba3ecc726736

Making a Bullet physics wrapper for DartVM
Share this