From 2fa0047f4600ef95d32e864dd7c54e99e27265fe Mon Sep 17 00:00:00 2001
From: sanine <sanine.not@pm.me>
Date: Fri, 24 Feb 2023 04:06:36 -0600
Subject: refactor: bind (almost) all ode functions

---
 src/ode/CMakeLists.txt |    6 +-
 src/ode/body.c         |  821 ++++++++++++++++++++
 src/ode/geom.c         | 1109 +++++++++++++++++++++++++++
 src/ode/joint.c        | 1987 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/ode/ode_bindings.c |  563 --------------
 src/ode/ode_bindings.h |  414 +++++++++-
 src/ode/setup.c        |   73 ++
 src/ode/world.c        |  250 ++++++
 8 files changed, 4658 insertions(+), 565 deletions(-)
 create mode 100644 src/ode/body.c
 create mode 100644 src/ode/geom.c
 create mode 100644 src/ode/joint.c
 delete mode 100644 src/ode/ode_bindings.c
 create mode 100644 src/ode/setup.c
 create mode 100644 src/ode/world.c

(limited to 'src/ode')

diff --git a/src/ode/CMakeLists.txt b/src/ode/CMakeLists.txt
index 83d517a..f11573f 100644
--- a/src/ode/CMakeLists.txt
+++ b/src/ode/CMakeLists.txt
@@ -1,7 +1,11 @@
 project(honey_engine)
 
 target_sources(honey PUBLIC
-	${CMAKE_CURRENT_LIST_DIR}/ode_bindings.c
+	${CMAKE_CURRENT_LIST_DIR}/setup.c
+	${CMAKE_CURRENT_LIST_DIR}/world.c
+	${CMAKE_CURRENT_LIST_DIR}/body.c
+	${CMAKE_CURRENT_LIST_DIR}/joint.c
+	${CMAKE_CURRENT_LIST_DIR}/geom.c
 )
 
 
diff --git a/src/ode/body.c b/src/ode/body.c
new file mode 100644
index 0000000..f543b34
--- /dev/null
+++ b/src/ode/body.c
@@ -0,0 +1,821 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <ode/ode.h>
+#include "ode_bindings.h"
+
+
+struct body_data_t {
+	lua_State *L;
+	int callback_ref;
+};
+
+struct body_t {
+	dBodyID id;
+	struct body_data_t data;
+};
+
+
+void ode_push_body(lua_State *L, dBodyID bb)
+{
+	struct body_t *b = lua_newuserdata(L, sizeof(struct body_t));
+	b->id = bb;
+	b->data.L = L;
+	b->data.callback_ref = LUA_NOREF;
+	dBodySetData(b->id, &(b->data));
+	luaL_getmetatable(L, ode_body_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+int dBodyCreate_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dBodyID b = dBodyCreate(*w);
+	ode_push_body(L, b);
+	return 1;
+}
+
+
+int dBodyDestroy_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodyDestroy(*b);
+	return 0;
+}
+
+
+int dBodySetPosition_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetPosition(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodySetRotation_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dMatrix3 R;
+	R[0] = luaL_checknumber(L, 2);
+	R[1] = luaL_checknumber(L, 3);
+	R[2] = luaL_checknumber(L, 4);
+
+	R[4] = luaL_checknumber(L, 5);
+	R[5] = luaL_checknumber(L, 6);
+	R[6] = luaL_checknumber(L, 7);
+
+	R[8] = luaL_checknumber(L, 8);
+	R[9] = luaL_checknumber(L, 9);
+	R[10] = luaL_checknumber(L, 10);
+
+	dBodySetRotation(*b, R);
+	return 0;
+}
+
+
+int dBodySetQuaternion_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dQuaternion q;
+	q[0] = luaL_checknumber(L, 2);
+	q[1] = luaL_checknumber(L, 3);
+	q[2] = luaL_checknumber(L, 4);
+	q[3] = luaL_checknumber(L, 5);
+	dBodySetQuaternion(*b, q);
+	return 0;
+}
+
+
+int dBodySetLinearVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetLinearVel(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodySetAngularVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetAngularVel(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodyGetPosition_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetPosition(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodyGetRotation_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetRotation(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodyGetQuaternion_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetQuaternion(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodyGetLinearVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetLinearVel(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodyGetAngularVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetAngularVel(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodySetMass_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dMass *mass = luaL_checkudata(L, 2, ode_mass_tname);
+	dBodySetMass(*b, mass);
+	return 0;
+}
+
+
+int dBodyGetMass_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dMass * mass = luaL_checkudata(L, 2, ode_mass_tname);
+	dBodyGetMass(*b, mass);
+	return 0;
+}
+
+
+int dBodyAddForce_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dBodyAddForce(*b, fx, fy, fz);
+	return 0;
+}
+
+
+int dBodyAddTorque_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dBodyAddTorque(*b, fx, fy, fz);
+	return 0;
+}
+
+
+int dBodyAddRelForce_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dBodyAddRelForce(*b, fx, fy, fz);
+	return 0;
+}
+
+
+int dBodyAddRelTorque_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dBodyAddRelTorque(*b, fx, fy, fz);
+	return 0;
+}
+
+
+int dBodyAddForceAtPos_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dReal px = luaL_checkinteger(L, 5);
+	dReal py = luaL_checkinteger(L, 6);
+	dReal pz = luaL_checkinteger(L, 7);
+	dBodyAddForceAtPos(*b, fx, fy, fz, px, py, pz);
+	return 0;
+}
+
+
+int dBodyAddForceAtRelPos_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dReal px = luaL_checkinteger(L, 5);
+	dReal py = luaL_checkinteger(L, 6);
+	dReal pz = luaL_checkinteger(L, 7);
+	dBodyAddForceAtRelPos(*b, fx, fy, fz, px, py, pz);
+	return 0;
+}
+
+
+int dBodyAddRelForceAtPos_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dReal px = luaL_checkinteger(L, 5);
+	dReal py = luaL_checkinteger(L, 6);
+	dReal pz = luaL_checkinteger(L, 7);
+	dBodyAddRelForceAtPos(*b, fx, fy, fz, px, py, pz);
+	return 0;
+}
+
+
+int dBodyAddRelForceAtRelPos_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal fx = luaL_checkinteger(L, 2);
+	dReal fy = luaL_checkinteger(L, 3);
+	dReal fz = luaL_checkinteger(L, 4);
+	dReal px = luaL_checkinteger(L, 5);
+	dReal py = luaL_checkinteger(L, 6);
+	dReal pz = luaL_checkinteger(L, 7);
+	dBodyAddRelForceAtRelPos(*b, fx, fy, fz, px, py, pz);
+	return 0;
+}
+
+
+int dBodyGetForce_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetForce(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodyGetTorque_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	const dReal * bind_result = dBodyGetTorque(*b);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dBodySetForce_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetForce(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodySetTorque_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetTorque(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodySetDynamic_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodySetDynamic(*b);
+	return 0;
+}
+
+
+int dBodySetKinematic_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodySetKinematic(*b);
+	return 0;
+}
+
+
+int dBodyIsKinematic_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyIsKinematic(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetRelPointPos_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyGetRelPointPos(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyGetRelPointVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyGetRelPointVel(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyGetPointVel_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyGetPointVel(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyGetPosRelPoint_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyGetPosRelPoint(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyVectorToWorld_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyVectorToWorld(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyVectorFromWorld_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal px = luaL_checkinteger(L, 2);
+	dReal py = luaL_checkinteger(L, 3);
+	dReal pz = luaL_checkinteger(L, 4);
+	dVector3 result;
+	dBodyVectorFromWorld(*b, px, py, pz, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyEnable_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodyEnable(*b);
+	return 0;
+}
+
+
+int dBodyDisable_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodyDisable(*b);
+	return 0;
+}
+
+
+int dBodyIsEnabled_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyIsEnabled(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableFlag_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int do_auto_disable = lua_toboolean(L, 2);
+	dBodySetAutoDisableFlag(*b, do_auto_disable);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableFlag_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetAutoDisableFlag(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableLinearThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal linear_threshold = luaL_checkinteger(L, 2);
+	dBodySetAutoDisableLinearThreshold(*b, linear_threshold);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableLinearThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetAutoDisableLinearThreshold(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableAngularThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal angular_threshold = luaL_checkinteger(L, 2);
+	dBodySetAutoDisableAngularThreshold(*b, angular_threshold);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableAngularThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetAutoDisableAngularThreshold(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableSteps_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int steps = luaL_checkinteger(L, 2);
+	dBodySetAutoDisableSteps(*b, steps);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableSteps_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetAutoDisableSteps(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableTime_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal time = luaL_checkinteger(L, 2);
+	dBodySetAutoDisableTime(*b, time);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableTime_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetAutoDisableTime(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableAverageSamplesCount_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	unsigned int average_samples_count = luaL_checkinteger(L, 2);
+	dBodySetAutoDisableAverageSamplesCount(*b, average_samples_count);
+	return 0;
+}
+
+
+int dBodyGetAutoDisableAverageSamplesCount_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetAutoDisableAverageSamplesCount(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetAutoDisableDefaults_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodySetAutoDisableDefaults(*b);
+	return 0;
+}
+
+
+static void moved_cb(dBodyID b)
+{
+	struct body_data_t *data = dBodyGetData(b);
+	lua_State *L = data->L;
+	int ref = data->callback_ref;
+	lua_rawgeti(L, LUA_REGISTRYINDEX, ref);
+	lua_call(L, 0, 0);
+}
+
+int dBodySetMovedCallback_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	luaL_checktype(L, 2, LUA_TFUNCTION);
+	int callback = 2;
+
+	struct body_data_t *data = dBodyGetData(*b);
+	lua_pushvalue(L, callback);
+	data->callback_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+	dBodySetMovedCallback(*b, moved_cb);
+	return 0;
+}
+
+
+int dBodyGetLinearDamping_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetLinearDamping(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetAngularDamping_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetAngularDamping(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetLinearDamping_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal scale = luaL_checkinteger(L, 2);
+	dBodySetLinearDamping(*b, scale);
+	return 0;
+}
+
+
+int dBodySetAngularDamping_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal scale = luaL_checkinteger(L, 2);
+	dBodySetAngularDamping(*b, scale);
+	return 0;
+}
+
+
+int dBodySetDamping_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal linear_scale = luaL_checkinteger(L, 2);
+	dReal angular_scale = luaL_checkinteger(L, 3);
+	dBodySetDamping(*b, linear_scale, angular_scale);
+	return 0;
+}
+
+
+int dBodyGetLinearDampingThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetLinearDampingThreshold(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetAngularDampingThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetAngularDampingThreshold(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetLinearDampingThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal threshold = luaL_checkinteger(L, 2);
+	dBodySetLinearDampingThreshold(*b, threshold);
+	return 0;
+}
+
+
+int dBodySetAngularDampingThreshold_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal threshold = luaL_checkinteger(L, 2);
+	dBodySetAngularDampingThreshold(*b, threshold);
+	return 0;
+}
+
+
+int dBodySetDampingDefaults_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dBodySetDampingDefaults(*b);
+	return 0;
+}
+
+
+int dBodyGetMaxAngularSpeed_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal bind_result = dBodyGetMaxAngularSpeed(*b);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetMaxAngularSpeed_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal max_speed = luaL_checkinteger(L, 2);
+	dBodySetMaxAngularSpeed(*b, max_speed);
+	return 0;
+}
+
+
+int dBodySetFiniteRotationMode_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int mode = luaL_checkinteger(L, 2);
+	dBodySetFiniteRotationMode(*b, mode);
+	return 0;
+}
+
+
+int dBodyGetFiniteRotationMode_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetFiniteRotationMode(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetFiniteRotationAxis_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dBodySetFiniteRotationAxis(*b, x, y, z);
+	return 0;
+}
+
+
+int dBodyGetFiniteRotationAxis_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dVector3 result;
+	dBodyGetFiniteRotationAxis(*b, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dBodyGetNumJoints_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetNumJoints(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetJoint_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int index = luaL_checkinteger(L, 2);
+	dJointID bind_result = dBodyGetJoint(*b, index);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetWorld_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dWorldID bind_result = dBodyGetWorld(*b);
+	ode_push_world(L, bind_result);
+	return 1;
+}
+
+
+int dBodySetGravityMode_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int mode = lua_toboolean(L, 2);
+	dBodySetGravityMode(*b, mode);
+	return 0;
+}
+
+
+int dBodyGetGravityMode_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	int bind_result = dBodyGetGravityMode(*b);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetFirstGeom_bind(lua_State *L)
+{
+	dBodyID *b = luaL_checkudata(L, 1, ode_body_tname);
+	dGeomID bind_result = dBodyGetFirstGeom(*b);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dBodyGetNextGeom_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomID bind_result = dBodyGetNextGeom(*g);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
diff --git a/src/ode/geom.c b/src/ode/geom.c
new file mode 100644
index 0000000..b7694ad
--- /dev/null
+++ b/src/ode/geom.c
@@ -0,0 +1,1109 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <ode/ode.h>
+#include "ode_bindings.h"
+
+
+void ode_push_geom(lua_State *L, dGeomID g)
+{
+	dGeomID *gu = lua_newuserdata(L, sizeof(dGeomID));
+	*gu = g;
+	luaL_getmetatable(L, ode_geom_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+void ode_push_space(lua_State *L, dSpaceID s)
+{
+	dSpaceID *su = lua_newuserdata(L, sizeof(dSpaceID));
+	*su = s;
+	luaL_getmetatable(L, ode_space_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+void ode_push_contactgeom(lua_State *L, dContactGeom cg)
+{
+	dContactGeom *cgu = lua_newuserdata(L, sizeof(dContactGeom));
+	*cgu = cg;
+}
+
+
+int dGeomDestroy_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomDestroy(*g);
+	return 0;
+}
+
+
+int dGeomSetBody_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dBodyID *b = luaL_checkudata(L, 2, ode_body_tname);
+	dGeomSetBody(*g, *b);
+	return 0;
+}
+
+
+int dGeomGetBody_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dBodyID bind_result = dGeomGetBody(*g);
+	ode_push_body(L, bind_result);
+	return 1;
+}
+
+
+int dGeomSetPosition_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dGeomSetPosition(*g, x, y, z);
+	return 0;
+}
+
+
+int dGeomSetRotation_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dMatrix3 R;
+	R[0] = luaL_checknumber(L, 2);
+	R[1] = luaL_checknumber(L, 3);
+	R[2] = luaL_checknumber(L, 4);
+	
+	R[4] = luaL_checknumber(L, 5);
+	R[5] = luaL_checknumber(L, 6);
+	R[6] = luaL_checknumber(L, 7);
+
+	R[8] = luaL_checknumber(L, 8);
+	R[9] = luaL_checknumber(L, 9);
+	R[10] = luaL_checknumber(L, 10);
+	dGeomSetRotation(*g, R);
+	return 0;
+}
+
+
+int dGeomSetQuaternion_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dQuaternion q;
+	q[0] = luaL_checknumber(L, 2);
+	q[1] = luaL_checknumber(L, 3);
+	q[2] = luaL_checknumber(L, 4);
+	q[3] = luaL_checknumber(L, 5);
+	dGeomSetQuaternion(*g, q);
+	return 0;
+}
+
+
+int dGeomGetPosition_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	const dReal * bind_result = dGeomGetPosition(*g);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dGeomGetRotation_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	const dReal * bind_result = dGeomGetRotation(*g);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	lua_pushnumber(L, bind_result[4]);
+	lua_pushnumber(L, bind_result[5]);
+	lua_pushnumber(L, bind_result[6]);
+	lua_pushnumber(L, bind_result[8]);
+	lua_pushnumber(L, bind_result[9]);
+	lua_pushnumber(L, bind_result[10]);
+	return 9;
+}
+
+
+int dGeomGetQuaternion_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dQuaternion result;
+	dGeomGetQuaternion(*g, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	lua_pushnumber(L, result[3]);
+	return 4;
+}
+
+
+int dGeomSetOffsetPosition_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dGeomSetOffsetPosition(*g, x, y, z);
+	return 0;
+}
+
+
+int dGeomSetOffsetRotation_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dMatrix3 R;
+	R[0] = luaL_checknumber(L, 2);
+	R[1] = luaL_checknumber(L, 3);
+	R[2] = luaL_checknumber(L, 4);
+	R[4] = luaL_checknumber(L, 5);
+	R[5] = luaL_checknumber(L, 6);
+	R[6] = luaL_checknumber(L, 7);
+	R[8] = luaL_checknumber(L, 8);
+	R[9] = luaL_checknumber(L, 9);
+	R[10] = luaL_checknumber(L, 10);
+	dGeomSetOffsetRotation(*g, R);
+	return 0;
+}
+
+
+int dGeomSetOffsetQuaternion_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dQuaternion Q;
+	Q[0] = luaL_checknumber(L, 2);
+	Q[1] = luaL_checknumber(L, 3);
+	Q[2] = luaL_checknumber(L, 4);
+	Q[3] = luaL_checknumber(L, 5);
+	dGeomSetOffsetQuaternion(*g, Q);
+	return 0;
+}
+
+
+int dGeomSetOffsetWorldPosition_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dGeomSetOffsetWorldPosition(*g, x, y, z);
+	return 0;
+}
+
+
+int dGeomSetOffsetWorldRotation_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dMatrix3 R;
+	R[0] = luaL_checknumber(L, 2);
+	R[1] = luaL_checknumber(L, 3);
+	R[2] = luaL_checknumber(L, 4);
+	R[4] = luaL_checknumber(L, 5);
+	R[5] = luaL_checknumber(L, 6);
+	R[6] = luaL_checknumber(L, 7);
+	R[8] = luaL_checknumber(L, 8);
+	R[9] = luaL_checknumber(L, 9);
+	R[10] = luaL_checknumber(L, 10);
+	dGeomSetOffsetWorldRotation(*g, R);
+	return 0;
+}
+
+
+int dGeomSetOffsetWorldQuaternion_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dQuaternion Q;
+	Q[0] = luaL_checknumber(L, 2);
+	Q[1] = luaL_checknumber(L, 3);
+	Q[2] = luaL_checknumber(L, 4);
+	Q[3] = luaL_checknumber(L, 5);
+	dGeomSetOffsetWorldQuaternion(*g, Q);
+	return 0;
+}
+
+
+int dGeomGetOffsetPosition_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	const dReal * bind_result = dGeomGetOffsetPosition(*g);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	return 3;
+}
+
+
+int dGeomGetOffsetRotation_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	const dReal * bind_result = dGeomGetOffsetRotation(*g);
+	lua_pushnumber(L, bind_result[0]);
+	lua_pushnumber(L, bind_result[1]);
+	lua_pushnumber(L, bind_result[2]);
+	lua_pushnumber(L, bind_result[4]);
+	lua_pushnumber(L, bind_result[5]);
+	lua_pushnumber(L, bind_result[6]);
+	lua_pushnumber(L, bind_result[8]);
+	lua_pushnumber(L, bind_result[9]);
+	lua_pushnumber(L, bind_result[10]);
+	return 9;
+}
+
+
+int dGeomGetOffsetQuaternion_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dQuaternion result;
+	dGeomGetOffsetQuaternion(*g, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	lua_pushnumber(L, result[3]);
+	return 4;
+}
+
+
+int dGeomClearOffset_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomClearOffset(*g);
+	return 0;
+}
+
+
+int dGeomGetAABB_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal aabb[6];
+	dGeomGetAABB(*g, aabb);
+	lua_pushnumber(L, aabb[0]);
+	lua_pushnumber(L, aabb[1]);
+	lua_pushnumber(L, aabb[2]);
+	lua_pushnumber(L, aabb[3]);
+	lua_pushnumber(L, aabb[4]);
+	lua_pushnumber(L, aabb[5]);
+	return 6;
+}
+
+
+int dGeomIsSpace_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int bind_result = dGeomIsSpace(*g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dGeomGetSpace_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dSpaceID bind_result = dGeomGetSpace(*g);
+	ode_push_space(L, bind_result);
+	return 1;
+}
+
+
+int dGeomGetClass_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int bind_result = dGeomGetClass(*g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dGeomSetCategoryBits_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	unsigned long bits = luaL_checkinteger(L, 2);
+	dGeomSetCategoryBits(*g, bits);
+	return 0;
+}
+
+
+int dGeomSetCollideBits_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	unsigned long bits = luaL_checkinteger(L, 2);
+	dGeomSetCollideBits(*g, bits);
+	return 0;
+}
+
+
+int dGeomGetCategoryBits_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	unsigned long bind_result = dGeomGetCategoryBits(*g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dGeomGetCollideBits_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	unsigned long bind_result = dGeomGetCollideBits(*g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dGeomEnable_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomEnable(*g);
+	return 0;
+}
+
+
+int dGeomDisable_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomDisable(*g);
+	return 0;
+}
+
+
+int dGeomIsEnabled_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int bind_result = dGeomIsEnabled(*g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dCollide_bind(lua_State *L)
+{
+	dGeomID *o1 = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomID *o2 = luaL_checkudata(L, 2, ode_geom_tname);
+	int flags = luaL_checkinteger(L, 3);
+	size_t count = flags & 0xff; /* lower 16 bits for flags are the number of contacts requested */
+	dContactGeom *contacts = malloc(count * sizeof(dContactGeom));
+	if (contacts == NULL) {
+		return luaL_error(L, "failed to allocate %lu bytes for contacts buffer", count * sizeof(dContactGeom));
+	}
+	count = dCollide(*o1, *o2, flags, contacts, sizeof(dContactGeom));
+	
+	lua_createtable(L, count, 0);
+	int tbl = lua_gettop(L);
+	for (int i=0; i<count; i++) {
+		ode_push_contactgeom(L, contacts[i]);
+		lua_rawseti(L, tbl, i+1);
+	}
+	return 1;
+}
+
+
+struct near_data_t {
+	lua_State *L;
+	int ref;
+};
+
+static void near(void *data, dGeomID o1, dGeomID o2)
+{
+	struct near_data_t *d = data;
+	lua_State *L = d->L;
+
+	lua_rawgeti(L, LUA_REGISTRYINDEX, d->ref);
+	ode_push_geom(L, o1);
+	ode_push_geom(L, o2);
+	lua_call(L, 2, 0);
+}
+
+int dSpaceCollide_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	luaL_checktype(L, 2, LUA_TFUNCTION);
+	lua_pushvalue(L, 2);
+	int ref = luaL_ref(L, LUA_REGISTRYINDEX);
+	struct near_data_t data = { L, ref };
+	dSpaceCollide(*space, &data, near);
+	luaL_unref(L, LUA_REGISTRYINDEX, ref);
+	return 0;
+}
+
+
+int dSpaceCollide2_bind(lua_State *L)
+{
+	dGeomID *o1 = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomID *o2 = luaL_checkudata(L, 2, ode_geom_tname);
+	luaL_checktype(L, 3, LUA_TFUNCTION);
+	lua_pushvalue(L, 3);
+	int ref = luaL_ref(L, LUA_REGISTRYINDEX);
+	struct near_data_t data = { L, ref };
+	dSpaceCollide2(*o1, *o2, &data, near);
+	luaL_unref(L, LUA_REGISTRYINDEX, ref);
+	return 0;
+}
+
+
+int dSimpleSpaceCreate_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dSpaceID bind_result = dSimpleSpaceCreate(*space);
+	ode_push_space(L, bind_result);
+	return 1;
+}
+
+
+int dHashSpaceCreate_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dSpaceID bind_result = dHashSpaceCreate(*space);
+	ode_push_space(L, bind_result);
+	return 1;
+}
+
+
+int dQuadTreeSpaceCreate_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dVector3 Center;
+	Center[0] = luaL_checknumber(L, 2);
+	Center[1] = luaL_checknumber(L, 3);
+	Center[2] = luaL_checknumber(L, 4);
+	dVector3 Extents;
+	Extents[0] = luaL_checknumber(L, 5);
+	Extents[1] = luaL_checknumber(L, 6);
+	Extents[2] = luaL_checknumber(L, 7);
+	int Depth = luaL_checkinteger(L, 8);
+	dSpaceID bind_result = dQuadTreeSpaceCreate(*space, Center, Extents, Depth);
+	ode_push_space(L, bind_result);
+	return 1;
+}
+
+
+int dSpaceDestroy_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	dSpaceDestroy(*s);
+	return 0;
+}
+
+
+int dHashSpaceSetLevels_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int minlevel = luaL_checkinteger(L, 2);
+	int maxlevel = luaL_checkinteger(L, 3);
+	dHashSpaceSetLevels(*space, minlevel, maxlevel);
+	return 0;
+}
+
+
+int dHashSpaceGetLevels_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int minlevel, maxlevel;
+	dHashSpaceGetLevels(*space, &minlevel, &maxlevel);
+	lua_pushinteger(L, minlevel);
+	lua_pushinteger(L, maxlevel);
+	return 2;
+}
+
+
+int dSpaceSetCleanup_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int mode = luaL_checkinteger(L, 2);
+	dSpaceSetCleanup(*space, mode);
+	return 0;
+}
+
+
+int dSpaceGetCleanup_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int bind_result = dSpaceGetCleanup(*space);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dSpaceSetSublevel_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int sublevel = luaL_checkinteger(L, 2);
+	dSpaceSetSublevel(*space, sublevel);
+	return 0;
+}
+
+
+int dSpaceGetSublevel_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	int bind_result = dSpaceGetSublevel(*space);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dSpaceAdd_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	dGeomID *g = luaL_checkudata(L, 2, ode_geom_tname);
+	dSpaceAdd(*s, *g);
+	return 0;
+}
+
+
+int dSpaceRemove_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	dGeomID *g = luaL_checkudata(L, 2, ode_geom_tname);
+	dSpaceRemove(*s, *g);
+	return 0;
+}
+
+
+int dSpaceQuery_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	dGeomID *g = luaL_checkudata(L, 2, ode_geom_tname);
+	int bind_result = dSpaceQuery(*s, *g);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dSpaceGetNumGeoms_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	int bind_result = dSpaceGetNumGeoms(*s);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dSpaceGetGeom_bind(lua_State *L)
+{
+	dSpaceID *s = luaL_checkudata(L, 1, ode_space_tname);
+	int i = luaL_checkinteger(L, 2);
+	dGeomID bind_result = dSpaceGetGeom(*s, i);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dCreateSphere_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dGeomID bind_result = dCreateSphere(*space, radius);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomSphereSetRadius_bind(lua_State *L)
+{
+	dGeomID *sphere = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dGeomSphereSetRadius(*sphere, radius);
+	return 0;
+}
+
+
+int dGeomSphereGetRadius_bind(lua_State *L)
+{
+	dGeomID *sphere = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal bind_result = dGeomSphereGetRadius(*sphere);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dGeomSpherePointDepth_bind(lua_State *L)
+{
+	dGeomID *sphere = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal bind_result = dGeomSpherePointDepth(*sphere, x, y, z);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dCreateBox_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal lx = luaL_checknumber(L, 2);
+	dReal ly = luaL_checknumber(L, 3);
+	dReal lz = luaL_checknumber(L, 4);
+	dGeomID bind_result = dCreateBox(*space, lx, ly, lz);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomBoxSetLengths_bind(lua_State *L)
+{
+	dGeomID *box = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal lx = luaL_checknumber(L, 2);
+	dReal ly = luaL_checknumber(L, 3);
+	dReal lz = luaL_checknumber(L, 4);
+	dGeomBoxSetLengths(*box, lx, ly, lz);
+	return 0;
+}
+
+
+int dGeomBoxGetLengths_bind(lua_State *L)
+{
+	dGeomID *box = luaL_checkudata(L, 1, ode_geom_tname);
+	dVector3 result;
+	dGeomBoxGetLengths(*box, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dGeomBoxPointDepth_bind(lua_State *L)
+{
+	dGeomID *box = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal bind_result = dGeomBoxPointDepth(*box, x, y, z);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dCreatePlane_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal a = luaL_checknumber(L, 2);
+	dReal b = luaL_checknumber(L, 3);
+	dReal c = luaL_checknumber(L, 4);
+	dReal d = luaL_checknumber(L, 5);
+	dGeomID bind_result = dCreatePlane(*space, a, b, c, d);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomPlaneSetParams_bind(lua_State *L)
+{
+	dGeomID *plane = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal a = luaL_checknumber(L, 2);
+	dReal b = luaL_checknumber(L, 3);
+	dReal c = luaL_checknumber(L, 4);
+	dReal d = luaL_checknumber(L, 5);
+	dGeomPlaneSetParams(*plane, a, b, c, d);
+	return 0;
+}
+
+
+int dGeomPlaneGetParams_bind(lua_State *L)
+{
+	dGeomID *plane = luaL_checkudata(L, 1, ode_geom_tname);
+	dVector4 result;
+	dGeomPlaneGetParams(*plane, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	lua_pushnumber(L, result[3]);
+	return 4;
+}
+
+
+int dGeomPlanePointDepth_bind(lua_State *L)
+{
+	dGeomID *plane = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal bind_result = dGeomPlanePointDepth(*plane, x, y, z);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dCreateCapsule_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dReal length = luaL_checknumber(L, 3);
+	dGeomID bind_result = dCreateCapsule(*space, radius, length);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomCapsuleSetParams_bind(lua_State *L)
+{
+	dGeomID *capsule = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dReal length = luaL_checknumber(L, 3);
+	dGeomCapsuleSetParams(*capsule, radius, length);
+	return 0;
+}
+
+
+int dGeomCapsuleGetParams_bind(lua_State *L)
+{
+	dGeomID *capsule = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal radius, length;
+	dGeomCapsuleGetParams(*capsule, &radius, &length);
+	lua_pushnumber(L, radius);
+	lua_pushnumber(L, length);
+	return 2;
+}
+
+
+int dGeomCapsulePointDepth_bind(lua_State *L)
+{
+	dGeomID *capsule = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal bind_result = dGeomCapsulePointDepth(*capsule, x, y, z);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dCreateCylinder_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dReal length = luaL_checknumber(L, 3);
+	dGeomID bind_result = dCreateCylinder(*space, radius, length);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomCylinderSetParams_bind(lua_State *L)
+{
+	dGeomID *cylinder = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dReal length = luaL_checknumber(L, 3);
+	dGeomCylinderSetParams(*cylinder, radius, length);
+	return 0;
+}
+
+
+int dGeomCylinderGetParams_bind(lua_State *L)
+{
+	dGeomID *cylinder = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal radius, length;
+	dGeomCylinderGetParams(*cylinder, &radius, &length);
+	lua_pushnumber(L, radius);
+	lua_pushnumber(L, length);
+	return 2;
+}
+
+
+int dCreateRay_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dReal length = luaL_checknumber(L, 2);
+	dGeomID bind_result = dCreateRay(*space, length);
+	ode_push_geom(L, bind_result);
+	return 1;
+}
+
+
+int dGeomRaySetLength_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal length = luaL_checknumber(L, 2);
+	dGeomRaySetLength(*ray, length);
+	return 0;
+}
+
+
+int dGeomRayGetLength_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal bind_result = dGeomRayGetLength(*ray);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dGeomRaySet_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	dReal px = luaL_checknumber(L, 2);
+	dReal py = luaL_checknumber(L, 3);
+	dReal pz = luaL_checknumber(L, 4);
+	dReal dx = luaL_checknumber(L, 5);
+	dReal dy = luaL_checknumber(L, 6);
+	dReal dz = luaL_checknumber(L, 7);
+	dGeomRaySet(*ray, px, py, pz, dx, dy, dz);
+	return 0;
+}
+
+
+int dGeomRayGet_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	dVector3 start;
+	dVector3 dir;
+	dGeomRayGet(*ray, start, dir);
+	lua_pushnumber(L, start[0]);
+	lua_pushnumber(L, start[1]);
+	lua_pushnumber(L, start[2]);
+	lua_pushnumber(L, dir[0]);
+	lua_pushnumber(L, dir[1]);
+	lua_pushnumber(L, dir[2]);
+	return 6;
+}
+
+
+int dGeomRaySetParams_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	int FirstContact = luaL_checkinteger(L, 2);
+	int BackfaceCull = luaL_checkinteger(L, 3);
+	dGeomRaySetParams(*ray, FirstContact, BackfaceCull);
+	return 0;
+}
+
+
+int dGeomRayGetParams_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	int FirstContact, BackfaceCull;
+	dGeomRayGetParams(*ray, &FirstContact, &BackfaceCull);
+	lua_pushnumber(L, FirstContact);
+	lua_pushnumber(L, BackfaceCull);
+	return 2;
+}
+
+
+int dGeomRaySetClosestHit_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	int ClosestHit = luaL_checkinteger(L, 2);
+	dGeomRaySetClosestHit(*ray, ClosestHit);
+	return 0;
+}
+
+
+int dGeomRayGetClosestHit_bind(lua_State *L)
+{
+	dGeomID *ray = luaL_checkudata(L, 1, ode_geom_tname);
+	int bind_result = dGeomRayGetClosestHit(*ray);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+/*int dGeomTriMeshDataCreate_bind(lua_State *L)
+{
+	dTriMeshDataID bind_result = dGeomTriMeshDataCreate();
+	/* push result /
+	return /* count /;
+}
+
+
+int dGeomTriMeshDataDestroy_bind(lua_State *L)
+{
+	dTriMeshDataID g = get: dTriMeshDataID
+	dGeomTriMeshDataDestroy(*g);
+	return 0;
+}
+
+
+int dGeomTriMeshDataBuild_bind(lua_State *L)
+{
+	dTriMeshDataID g = get: dTriMeshDataID
+	const void * Vertices = get: const void *
+	int VertexStride = luaL_checkinteger(L, 3);
+	int VertexCount = luaL_checkinteger(L, 4);
+	const void * Indices = get: const void *
+	int IndexCount = luaL_checkinteger(L, 6);
+	int TriStride = luaL_checkinteger(L, 7);
+	const void * Normals = get: const void *
+	dGeomTriMeshDataBuild(*g, Vertices, VertexStride, VertexCount, Indices, IndexCount, TriStride, Normals);
+	return 0;
+}
+
+
+int dGeomTriMeshDataBuildSimple_bind(lua_State *L)
+{
+	dTriMeshDataID g = get: dTriMeshDataID
+	const dVector3 * Vertices = get: const dVector3 *
+	int VertexCount = luaL_checkinteger(L, 3);
+	const int * Indices = get: const int *
+	int IndexCount = luaL_checkinteger(L, 5);
+	dGeomTriMeshDataBuildSimple(*g, Vertices, VertexCount, Indices, IndexCount);
+	return 0;
+}
+
+
+int dCreateTriMesh_bind(lua_State *L)
+{
+	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+	dTriMeshDataID Data = get: dTriMeshDataID
+	dTriCallback * Callback = get: dTriCallback *
+	dTriArrayCallback * ArrayCallback = get: dTriArrayCallback *
+	dTriRayCallback * RayCallback = get: dTriRayCallback *
+	dGeomID *bind_result = dCreateTriMesh(*space, Data, Callback, ArrayCallback, RayCallback);
+	/* push result /
+	return /* count /;
+}
+
+
+int dGeomTriMeshSetData_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dTriMeshDataID Data = get: dTriMeshDataID
+	dGeomTriMeshSetData(*g, Data);
+	return 0;
+}
+
+
+int dGeomTriMeshClearTCCache_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	dGeomTriMeshClearTCCache(*g);
+	return 0;
+}
+
+
+int dGeomTriMeshGetTriangle_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int Index = luaL_checkinteger(L, 2);
+	dVector3 * v0 = get: dVector3 *
+	dVector3 * v1 = get: dVector3 *
+	dVector3 * v2 = get: dVector3 *
+	dGeomTriMeshGetTriangle(*g, Index, v0, v1, v2);
+	return 0;
+}
+
+
+int dGeomTriMeshGetPoint_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int Index = luaL_checkinteger(L, 2);
+	dReal u = luaL_checknumber(L, 3);
+	dReal v = luaL_checknumber(L, 4);
+	dVector3 Out = get: dVector3
+	dGeomTriMeshGetPoint(*g, Index, u, v, Out);
+	return 0;
+}
+
+
+int dGeomTriMeshEnableTC_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int geomClass = luaL_checkinteger(L, 2);
+	int enable = luaL_checkinteger(L, 3);
+	dGeomTriMeshEnableTC(*g, geomClass, enable);
+	return 0;
+}
+
+
+int dGeomTriMeshIsTCEnabled_bind(lua_State *L)
+{
+	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+	int geomClass = luaL_checkinteger(L, 2);
+	int bind_result = dGeomTriMeshIsTCEnabled(*g, geomClass);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}*/
+
+
+//int dGeomHeightfieldDataCreate_bind(lua_State *L)
+//{
+//	dHeightfieldDataID bind_result = dGeomHeightfieldDataCreate();
+//	/* push result */
+//	return /* count */;
+//}
+//
+//
+//int dGeomHeightfieldDataDestroy_bind(lua_State *L)
+//{
+//	dHeightfieldDataID d = get: dHeightfieldDataID
+//	dGeomHeightfieldDataDestroy(d);
+//	return 0;
+//}
+//
+//
+//int dGeomHeightfieldDataBuildDouble_bind(lua_State *L)
+//{
+//	dHeightfieldDataID d = get: dHeightfieldDataID
+//	const double * pHeightData = get: const double *
+//	int bCopyHeightData = luaL_checkinteger(L, 3);
+//	dReal width = luaL_checknumber(L, 4);
+//	dReal depth = luaL_checknumber(L, 5);
+//	int widthSamples = luaL_checkinteger(L, 6);
+//	int depthSamples = luaL_checkinteger(L, 7);
+//	dReal scale = luaL_checknumber(L, 8);
+//	dReal offset = luaL_checknumber(L, 9);
+//	dReal thickness = luaL_checknumber(L, 10);
+//	int bWrap = luaL_checkinteger(L, 11);
+//	dGeomHeightfieldDataBuildDouble(d, pHeightData, bCopyHeightData, width, depth, widthSamples, depthSamples, scale, offset, thickness, bWrap);
+//	return 0;
+//}
+//
+//
+//int dGeomHeightfieldDataBuildCallback_bind(lua_State *L)
+//{
+//	dHeightfieldDataID d = get: dHeightfieldDataID
+//	void * pUserData = get: void *
+//	dHeightfieldGetHeight * pCallback = get: dHeightfieldGetHeight *
+//	dReal width = luaL_checknumber(L, 4);
+//	dReal depth = luaL_checknumber(L, 5);
+//	int widthSamples = luaL_checkinteger(L, 6);
+//	int depthSamples = luaL_checkinteger(L, 7);
+//	dReal scale = luaL_checknumber(L, 8);
+//	dReal offset = luaL_checknumber(L, 9);
+//	dReal thickness = luaL_checknumber(L, 10);
+//	int bWrap = luaL_checkinteger(L, 11);
+//	dGeomHeightfieldDataBuildCallback(d, pUserData, pCallback, width, depth, widthSamples, depthSamples, scale, offset, thickness, bWrap);
+//	return 0;
+//}
+//
+//
+//int dGeomHeightfieldDataSetBounds_bind(lua_State *L)
+//{
+//	dHeightfieldDataID d = get: dHeightfieldDataID
+//	dReal min_height = luaL_checknumber(L, 2);
+//	dReal max_height = luaL_checknumber(L, 3);
+//	dGeomHeightfieldDataSetBounds(d, min_height, max_height);
+//	return 0;
+//}
+//
+//
+//int dCreateHeightfield_bind(lua_State *L)
+//{
+//	dSpaceID *space = luaL_checkudata(L, 1, ode_space_tname);
+//	dHeightfieldDataID data = get: dHeightfieldDataID
+//	int bPlaceable = luaL_checkinteger(L, 3);
+//	dGeomID *bind_result = dCreateHeightfield(*space, data, bPlaceable);
+//	/* push result */
+//	return /* count */;
+//}
+//
+//
+//int dGeomHeightfieldSetHeightfieldData_bind(lua_State *L)
+//{
+//	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+//	dHeightfieldDataID Data = get: dHeightfieldDataID
+//	dGeomHeightfieldSetHeightfieldData(*g, Data);
+//	return 0;
+//}
+//
+//
+//int dGeomHeightfieldGetHeightfieldData_bind(lua_State *L)
+//{
+//	dGeomID *g = luaL_checkudata(L, 1, ode_geom_tname);
+//	dHeightfieldDataID bind_result = dGeomHeightfieldGetHeightfieldData(*g);
+//	/* push result */
+//	return /* count */;
+//}
+
+
diff --git a/src/ode/joint.c b/src/ode/joint.c
new file mode 100644
index 0000000..6fa79b4
--- /dev/null
+++ b/src/ode/joint.c
@@ -0,0 +1,1987 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <ode/ode.h>
+#include "ode_bindings.h"
+
+
+void ode_push_joint(lua_State *L, dJointID j)
+{
+	dJointID *ju = lua_newuserdata(L, sizeof(dJointID));
+	*ju = j;
+	luaL_getmetatable(L, ode_joint_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+void ode_push_jointgroup(lua_State *L, dJointGroupID jg)
+{
+	dJointGroupID *jgu = lua_newuserdata(L, sizeof(dJointGroupID));
+	*jgu = jg;
+	luaL_getmetatable(L, ode_jointgroup_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+int dJointCreateBall_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateBall(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateHinge_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateHinge(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateSlider_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateSlider(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+static int get_field(lua_State *L, int tbl, const char *key, int type)
+{
+	lua_getfield(L, tbl, key);
+	int actual_type = lua_type(L, -1);
+	if (actual_type != type) {
+		luaL_error(L, 
+			"field \"%s\" must have type %s but is %s instead",
+			key, lua_typename(L, type), lua_typename(L, actual_type)
+		);
+	}
+}
+
+static int parse_surface_params(lua_State *L, struct dSurfaceParameters *surface, int tbl)
+{
+	get_field(L, tbl, "mode", LUA_TNUMBER);
+	surface->mode = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "mu", LUA_TNUMBER);
+	surface->mu = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "mu2", LUA_TNUMBER);
+	surface->mu2 = lua_tointeger(L, -1);
+	
+	get_field(L, tbl, "rho", LUA_TNUMBER);
+	surface->rho = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "rho2", LUA_TNUMBER);
+	surface->rho2 = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "rhoN", LUA_TNUMBER);
+	surface->rhoN = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "bounce", LUA_TNUMBER);
+	surface->bounce = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "bounce_vel", LUA_TNUMBER);
+	surface->bounce_vel = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "soft_erp", LUA_TNUMBER);
+	surface->soft_erp = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "soft_cfm", LUA_TNUMBER);
+	surface->soft_cfm = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "motion1", LUA_TNUMBER);
+	surface->motion1 = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "motion2", LUA_TNUMBER);
+	surface->motion2 = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "motionN", LUA_TNUMBER);
+	surface->motionN = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "slip1", LUA_TNUMBER);
+	surface->slip1 = lua_tointeger(L, -1);
+
+	get_field(L, tbl, "slip2", LUA_TNUMBER);
+	surface->slip2 = lua_tointeger(L, -1);
+
+	lua_pop(L, 15);
+}
+
+static int parse_contact_tbl(lua_State *L, dContact *contact, int tbl)
+{
+	get_field(L, tbl, "surface", LUA_TTABLE);
+	int surface_tbl = lua_gettop(L);
+	parse_surface_params(L, &(contact->surface), surface_tbl);
+	lua_pop(L, 1);
+
+	get_field(L, tbl, "geom", LUA_TUSERDATA);
+	dContactGeom *g = lua_touserdata(L, -1);
+	contact->geom = *g;
+	lua_pop(L, 1);
+
+	get_field(L, tbl, "fdir1", LUA_TTABLE);
+	int fdir_tbl = lua_gettop(L);
+	lua_rawgeti(L, fdir_tbl, 1);
+	contact->fdir1[0] = lua_tonumber(L, -1);
+	lua_rawgeti(L, fdir_tbl, 1);
+	contact->fdir1[1] = lua_tonumber(L, -1);
+	lua_rawgeti(L, fdir_tbl, 1);
+	contact->fdir1[2] = lua_tonumber(L, -1);
+	lua_pop(L, 4);
+}
+
+int dJointCreateContact_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	luaL_checktype(L, 3, LUA_TTABLE);
+	dContact contact;
+	parse_contact_tbl(L, &contact, 3);
+	dJointID bind_result = dJointCreateContact(*w, *g, &contact);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateUniversal_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateUniversal(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateHinge2_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateHinge2(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreatePR_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreatePR(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreatePU_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreatePU(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreatePiston_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreatePiston(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateFixed_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateFixed(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateAMotor_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateAMotor(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateLMotor_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateLMotor(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreatePlane2D_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreatePlane2D(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateDBall_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateDBall(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateDHinge_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateDHinge(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointCreateTransmission_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dJointGroupID *g = luaL_checkudata(L, 2, ode_jointgroup_tname);
+	dJointID bind_result = dJointCreateTransmission(*w, *g);
+	ode_push_joint(L, bind_result);
+	return 1;
+}
+
+
+int dJointDestroy_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dJointDestroy(*j);
+	return 0;
+}
+
+
+int dJointGroupCreate_bind(lua_State *L)
+{
+	int max_size = luaL_checkinteger(L, 1);
+	dJointGroupID bind_result = dJointGroupCreate(max_size);
+	ode_push_jointgroup(L, bind_result);
+	return 1;
+}
+
+
+int dJointGroupDestroy_bind(lua_State *L)
+{
+	dJointGroupID *g = luaL_checkudata(L, 1, ode_jointgroup_tname);
+	dJointGroupDestroy(*g);
+	return 0;
+}
+
+
+int dJointGroupEmpty_bind(lua_State *L)
+{
+	dJointGroupID *g = luaL_checkudata(L, 1, ode_jointgroup_tname);
+	dJointGroupEmpty(*g);
+	return 0;
+}
+
+
+int dJointAttach_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dBodyID *body1 = luaL_checkudata(L, 2, ode_body_tname);
+	dBodyID *body2 = luaL_checkudata(L, 3, ode_body_tname);
+	dJointAttach(*j, *body1, *body2);
+	return 0;
+}
+
+
+int dJointEnable_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dJointEnable(*j);
+	return 0;
+}
+
+
+int dJointDisable_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dJointDisable(*j);
+	return 0;
+}
+
+
+int dJointIsEnabled_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointIsEnabled(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetType_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointGetType(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetBody_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int index = luaL_checkinteger(L, 2);
+	dBodyID bind_result = dJointGetBody(*j, index);
+	ode_push_body(L, bind_result);
+	return 1;
+}
+
+
+int dAreConnected_bind(lua_State *L)
+{
+	dBodyID *b1 = luaL_checkudata(L, 1, ode_body_tname);
+	dBodyID *b2 = luaL_checkudata(L, 2, ode_body_tname);
+	int bind_result = dAreConnected(*b1, *b2);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dAreConnectedExcluding_bind(lua_State *L)
+{
+	dBodyID *b1 = luaL_checkudata(L, 1, ode_body_tname);
+	dBodyID *b2 = luaL_checkudata(L, 2, ode_body_tname);
+	int joint_type = luaL_checkinteger(L, 3);
+	int bind_result = dAreConnectedExcluding(*b1, *b2, joint_type);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetBallAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetBallAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetBallAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetBallAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetBallAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetBallAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetHingeAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetHingeAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetHingeAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetHingeAxis(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetHingeAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHingeAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHingeAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHingeAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHingeAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHingeAxis(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHingeAngle_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetHingeAngle(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetHingeAngleRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetHingeAngleRate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetSliderAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetSliderAxis(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetSliderAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetSliderAxis(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetSliderPosition_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetSliderPosition(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetSliderPositionRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetSliderPositionRate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetUniversalAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetUniversalAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetUniversalAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetUniversalAxis1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetUniversalAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetUniversalAxis2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetUniversalAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetUniversalAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetUniversalAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetUniversalAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetUniversalAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetUniversalAxis1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetUniversalAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetUniversalAxis2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetUniversalAngle1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetUniversalAngle1(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetUniversalAngle2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetUniversalAngle2(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetUniversalAngles_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal angle1, angle2;
+	dJointGetUniversalAngles(*j, &angle1, &angle2);
+	lua_pushnumber(L, angle1);
+	lua_pushnumber(L, angle2);
+	return 2;
+}
+
+
+int dJointGetUniversalAngle1Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetUniversalAngle1Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetUniversalAngle2Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetUniversalAngle2Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetHinge2Anchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetHinge2Anchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetHinge2Axis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetHinge2Axis1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetHinge2Axis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetHinge2Axis2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetHinge2Anchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHinge2Anchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHinge2Anchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHinge2Anchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHinge2Axis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHinge2Axis1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHinge2Axis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetHinge2Axis2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetHinge2Angle1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetHinge2Angle1(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetHinge2Angle1Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetHinge2Angle1Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetHinge2Angle2Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetHinge2Angle2Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetPRAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPRAxis1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPRAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPRAxis1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPRAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPRAxis2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPRAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPRAxis2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPRAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPRAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPRAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPRAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetPRPosition_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPRPosition(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUPosition_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUPosition(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUPositionRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUPositionRate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetPUAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPUAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPUAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPUAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPUAnchorDelta_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal dx = luaL_checknumber(L, 5);
+	dReal dy = luaL_checknumber(L, 6);
+	dReal dz = luaL_checknumber(L, 7);
+	dJointSetPUAnchorDelta(*j, x, y, z, dx, dy, dz);
+	return 0;
+}
+
+
+int dJointSetPUAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPUAxis1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPUAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPUAxis1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPUAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPUAxis2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPUAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPUAxis2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPUAxis3_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPUAxis3(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPUAxis3_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPUAxis3(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPUAxisP_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPUAxisP(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPUAxisP_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPUAxisP(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetPUAngles_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal angle1, angle2;
+	dJointGetPUAngles(*j, &angle1, &angle2);
+	lua_pushnumber(L, angle1);
+	lua_pushnumber(L, angle2);
+	return 2;
+}
+
+
+int dJointGetPUAngle1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUAngle1(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUAngle2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUAngle2(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUAngle1Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUAngle1Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUAngle2Rate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPUAngle2Rate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetPistonAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPistonAnchor(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPistonAnchor_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPistonAnchor(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetPistonAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPistonAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPistonAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetPistonAxis(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetPistonAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetPistonAxis(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetPistonAxisDelta_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dReal dx = luaL_checknumber(L, 5);
+	dReal dy = luaL_checknumber(L, 6);
+	dReal dz = luaL_checknumber(L, 7);
+	dJointSetPistonAxisDelta(*j, x, y, z, dx, dy, dz);
+	return 0;
+}
+
+
+int dJointGetPistonPosition_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPistonPosition(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPistonPositionRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPistonPositionRate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPistonAngle_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPistonAngle(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPistonAngleRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetPistonAngleRate(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointAddPistonForce_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal force = luaL_checknumber(L, 2);
+	dJointAddPistonForce(*j, force);
+	return 0;
+}
+
+
+int dJointSetFixed_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dJointSetFixed(*j);
+	return 0;
+}
+
+
+int dJointSetAMotorMode_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int mode = luaL_checkinteger(L, 2);
+	dJointSetAMotorMode(*j, mode);
+	return 0;
+}
+
+
+int dJointGetAMotorMode_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointGetAMotorMode(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetAMotorNumAxes_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int num = luaL_checkinteger(L, 2);
+	dJointSetAMotorNumAxes(*j, num);
+	return 0;
+}
+
+
+int dJointGetAMotorNumAxes_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointGetAMotorNumAxes(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetAMotorAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	int rel = luaL_checkinteger(L, 3);
+	dReal x = luaL_checknumber(L, 4);
+	dReal y = luaL_checknumber(L, 5);
+	dReal z = luaL_checknumber(L, 6);
+	dJointSetAMotorAxis(*j, anum, rel, x, y, z);
+	return 0;
+}
+
+
+int dJointGetAMotorAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	dVector3 result;
+	dJointGetAMotorAxis(*j, anum, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetAMotorAxisRel_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	int bind_result = dJointGetAMotorAxisRel(*j, anum);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetAMotorAngle_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	dReal angle = luaL_checknumber(L, 3);
+	dJointSetAMotorAngle(*j, anum, angle);
+	return 0;
+}
+
+
+int dJointGetAMotorAngle_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetAMotorAngle(*j, anum);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetAMotorAngleRate_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetAMotorAngleRate(*j, anum);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetLMotorNumAxes_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int num = luaL_checkinteger(L, 2);
+	dJointSetLMotorNumAxes(*j, num);
+	return 0;
+}
+
+
+int dJointGetLMotorNumAxes_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointGetLMotorNumAxes(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetLMotorAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	int rel = luaL_checkinteger(L, 3);
+	dReal x = luaL_checknumber(L, 4);
+	dReal y = luaL_checknumber(L, 5);
+	dReal z = luaL_checknumber(L, 6);
+	dJointSetLMotorAxis(*j, anum, rel, x, y, z);
+	return 0;
+}
+
+
+int dJointGetLMotorAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int anum = luaL_checkinteger(L, 2);
+	dVector3 result;
+	dJointGetLMotorAxis(*j, anum, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetDBallAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetDBallAnchor1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetDBallAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetDBallAnchor2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetDBallAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetDBallAnchor1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetDBallAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetDBallAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetDBallDistance_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetDBallDistance(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetDBallDistance_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal dist = luaL_checknumber(L, 2);
+	dJointSetDBallDistance(*j, dist);
+	return 0;
+}
+
+
+int dJointSetDHingeAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetDHingeAxis(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetDHingeAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetDHingeAxis(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetDHingeAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetDHingeAnchor1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetDHingeAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetDHingeAnchor2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetDHingeAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetDHingeAnchor1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetDHingeAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetDHingeAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetDHingeDistance_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetDHingeDistance(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetTransmissionMode_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int mode = luaL_checkinteger(L, 2);
+	dJointSetTransmissionMode(*j, mode);
+	return 0;
+}
+
+
+int dJointGetTransmissionMode_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int bind_result = dJointGetTransmissionMode(*j);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetTransmissionContactPoint1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionContactPoint1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetTransmissionContactPoint2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionContactPoint2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetTransmissionAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetTransmissionAxis1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetTransmissionAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetTransmissionAxis2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetTransmissionAxis1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionAxis1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetTransmissionAxis2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionAxis2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetTransmissionAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetTransmissionAnchor1(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointSetTransmissionAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetTransmissionAnchor2(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetTransmissionAnchor1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionAnchor1(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetTransmissionAnchor2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionAnchor2(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointSetTransmissionRatio_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal ratio = luaL_checknumber(L, 2);
+	dJointSetTransmissionRatio(*j, ratio);
+	return 0;
+}
+
+
+int dJointGetTransmissionRatio_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionRatio(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetTransmissionAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal x = luaL_checknumber(L, 2);
+	dReal y = luaL_checknumber(L, 3);
+	dReal z = luaL_checknumber(L, 4);
+	dJointSetTransmissionAxis(*j, x, y, z);
+	return 0;
+}
+
+
+int dJointGetTransmissionAxis_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dVector3 result;
+	dJointGetTransmissionAxis(*j, result);
+	lua_pushnumber(L, result[0]);
+	lua_pushnumber(L, result[1]);
+	lua_pushnumber(L, result[2]);
+	return 3;
+}
+
+
+int dJointGetTransmissionAngle1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionAngle1(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetTransmissionAngle2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionAngle2(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetTransmissionRadius1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionRadius1(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetTransmissionRadius2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionRadius2(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetTransmissionRadius1_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dJointSetTransmissionRadius1(*j, radius);
+	return 0;
+}
+
+
+int dJointSetTransmissionRadius2_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal radius = luaL_checknumber(L, 2);
+	dJointSetTransmissionRadius2(*j, radius);
+	return 0;
+}
+
+
+int dJointSetTransmissionBacklash_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal backlash = luaL_checknumber(L, 2);
+	dJointSetTransmissionBacklash(*j, backlash);
+	return 0;
+}
+
+
+int dJointGetTransmissionBacklash_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal bind_result = dJointGetTransmissionBacklash(*j);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointSetHingeParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetHingeParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetSliderParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetSliderParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetHinge2Param_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetHinge2Param(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetUniversalParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetUniversalParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetAMotorParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetAMotorParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetLMotorParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetLMotorParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetPRParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetPRParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetPUParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetPUParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetPistonParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetPistonParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetDBallParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetDBallParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetDHingeParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetDHingeParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointSetTransmissionParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal value = luaL_checknumber(L, 3);
+	dJointSetTransmissionParam(*j, parameter, value);
+	return 0;
+}
+
+
+int dJointGetHingeParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetHingeParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetSliderParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetSliderParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetHinge2Param_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetHinge2Param(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetUniversalParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetUniversalParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetAMotorParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetAMotorParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetLMotorParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetLMotorParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPRParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetPRParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPUParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetPUParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetPistonParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetPistonParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetDBallParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetDBallParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetDHingeParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetDHingeParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointGetTransmissionParam_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	int parameter = luaL_checkinteger(L, 2);
+	dReal bind_result = dJointGetTransmissionParam(*j, parameter);
+	lua_pushnumber(L, bind_result);
+	return 1;
+}
+
+
+int dJointAddHingeTorque_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal torque = luaL_checknumber(L, 2);
+	dJointAddHingeTorque(*j, torque);
+	return 0;
+}
+
+
+int dJointAddUniversalTorques_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal torque1 = luaL_checknumber(L, 2);
+	dReal torque2 = luaL_checknumber(L, 3);
+	dJointAddUniversalTorques(*j, torque1, torque2);
+	return 0;
+}
+
+
+int dJointAddSliderForce_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal force = luaL_checknumber(L, 2);
+	dJointAddSliderForce(*j, force);
+	return 0;
+}
+
+
+int dJointAddHinge2Torques_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal torque1 = luaL_checknumber(L, 2);
+	dReal torque2 = luaL_checknumber(L, 3);
+	dJointAddHinge2Torques(*j, torque1, torque2);
+	return 0;
+}
+
+
+int dJointAddAMotorTorques_bind(lua_State *L)
+{
+	dJointID *j = luaL_checkudata(L, 1, ode_joint_tname);
+	dReal torque0 = luaL_checknumber(L, 2);
+	dReal torque1 = luaL_checknumber(L, 3);
+	dReal torque2 = luaL_checknumber(L, 4);
+	dJointAddAMotorTorques(*j, torque0, torque1, torque2);
+	return 0;
+}
diff --git a/src/ode/ode_bindings.c b/src/ode/ode_bindings.c
deleted file mode 100644
index 116878a..0000000
--- a/src/ode/ode_bindings.c
+++ /dev/null
@@ -1,563 +0,0 @@
-#include <lua.h>
-#include <honeysuckle.h>
-#include <ode/ode.h>
-
-
-/* setup/teardown */
-int init_ode(lua_State *L);
-int close_ode(lua_State *L);
-
-/* world functions */
-int world_create(lua_State *L);
-int world_destroy(lua_State *L);
-int world_set_gravity(lua_State *L);
-int world_get_gravity(lua_State *L);
-int world_set_cfm(lua_State *L);
-int world_quickstep(lua_State *L);
-
-/* space functions */
-int hash_space_create(lua_State *L);
-int space_destroy(lua_State *L);
-int space_collide(lua_State *L);
-
-/* joint group functions */
-int joint_group_create(lua_State *L);
-int joint_group_destroy(lua_State *L);
-int joint_group_empty(lua_State *L);
-
-/* joint functions */
-int joint_create_contact(lua_State *L);
-int joint_attach(lua_State *L);
-
-/* body functions */
-int body_create(lua_State *L);
-int body_set_mass(lua_State *L);
-int body_set_position(lua_State *L);
-int body_get_position(lua_State *L);
-int body_add_force(lua_State *L);
-int body_get_force(lua_State *L);
-int body_set_linear_vel(lua_State *L);
-
-/* geom functions */
-int create_sphere(lua_State *L);
-int create_plane(lua_State *L);
-int geom_get_class(lua_State *L);
-int geom_set_body(lua_State *L);
-int geom_get_body(lua_State *L);
-int collide(lua_State *L);
-
-/* mass functions */
-int mass_create(lua_State *L);
-int mass_set_sphere(lua_State *L);
-
-
-/* contact functions */
-int contact_create(lua_State *L);
-int contact_surface_set_mode(lua_State *L);
-int contact_surface_set_mu(lua_State *L);
-int contact_surface_set_bounce(lua_State *L);
-int contact_surface_set_bounce_vel(lua_State *L);
-int contact_surface_set_soft_cfm(lua_State *L);
-
-
-#define NEW_METATABLE(name) luaL_newmetatable(L, name); lua_pop(L, 1);
-static const char *world_tname = "ode.World";
-static const char *space_tname = "ode.Space";
-static const char *body_tname  = "ode.Body";
-static const char *geom_tname  = "ode.Geom";
-static const char *mass_tname  = "ode.Mass";
-static const char *joint_group_tname = "ode.JointGroup";
-static const char *joint_tname = "ode.Joint";
-static const char *contact_tname = "ode.Contact";
-
-void setup_ode(lua_State *L, int honey_tbl)
-{
-	/* setup metatables */
-	NEW_METATABLE(world_tname);
-	NEW_METATABLE(space_tname);
-	NEW_METATABLE(body_tname);
-	NEW_METATABLE(geom_tname);
-	NEW_METATABLE(mass_tname);
-	NEW_METATABLE(joint_group_tname);
-	NEW_METATABLE(joint_tname);
-	NEW_METATABLE(contact_tname);
-
-
-	/* create main table */
-	hs_create_table(L,
-		hs_str_cfunc("InitODE", init_ode),
-		hs_str_cfunc("CloseODE", close_ode),
-
-		hs_str_cfunc("WorldCreate", world_create),
-		hs_str_cfunc("WorldDestroy", world_destroy),
-		hs_str_cfunc("WorldSetGravity", world_set_gravity),
-		hs_str_cfunc("WorldGetGravity", world_get_gravity),
-		hs_str_cfunc("WorldSetCFM", world_set_cfm),
-		hs_str_cfunc("WorldQuickStep", world_quickstep),
-
-		hs_str_cfunc("HashSpaceCreate", hash_space_create),
-		hs_str_cfunc("SpaceDestroy", space_destroy),
-		hs_str_cfunc("SpaceCollide", space_collide),
-
-		hs_str_cfunc("JointGroupCreate", joint_group_create),
-		hs_str_cfunc("JointGroupDestroy", joint_group_destroy),
-		hs_str_cfunc("JointGroupEmpty", joint_group_empty),
-
-		hs_str_cfunc("JointCreateContact", joint_create_contact),
-		hs_str_cfunc("JointAttach", joint_attach),
-
-		hs_str_cfunc("BodyCreate", body_create),
-		hs_str_cfunc("BodySetMass", body_set_mass),
-		hs_str_cfunc("BodySetPosition", body_set_position),
-		hs_str_cfunc("BodyGetPosition", body_get_position),
-		hs_str_cfunc("BodyAddForce", body_add_force),
-		hs_str_cfunc("BodyGetForce", body_get_force),
-		hs_str_cfunc("BodySetLinearVel", body_set_linear_vel),
-
-		hs_str_cfunc("CreateSphere", create_sphere),
-		hs_str_cfunc("CreatePlane", create_plane),
-		hs_str_cfunc("GeomGetClass", geom_get_class),
-		hs_str_cfunc("GeomSetBody", geom_set_body),
-		hs_str_cfunc("GeomGetBody", geom_get_body),
-		hs_str_cfunc("Collide", collide),
-
-		hs_str_cfunc("MassCreate", mass_create),
-		hs_str_cfunc("MassSetSphere", mass_set_sphere),
-
-		hs_str_cfunc("ContactCreate", contact_create),
-		hs_str_cfunc("ContactSurfaceSetMode", contact_surface_set_mode),
-		hs_str_cfunc("ContactSurfaceSetMu", contact_surface_set_mu),
-		hs_str_cfunc("ContactSurfaceSetBounce", contact_surface_set_bounce),
-		hs_str_cfunc("ContactSurfaceSetBounceVel", contact_surface_set_bounce_vel),
-		hs_str_cfunc("ContactSurfaceSetSoftCFM", contact_surface_set_soft_cfm),
-
-		/* contact surface mode enum */
-		hs_str_int("ContactBounce", dContactBounce),
-		hs_str_int("ContactSoftCFM", dContactSoftCFM),
-
-		/* helpful */
-		hs_str_num("Infinity", dInfinity),
-	);
-
-	lua_setfield(L, honey_tbl, "ode");
-}
-
-
-/* --===== setup/teardown =====-- */
-
-int init_ode(lua_State *L)
-{
-	dInitODE();
-	return 0;
-}
-
-
-int close_ode(lua_State *L)
-{
-	dCloseODE();
-	return 0;
-}
-
-
-/* --===== world functions =====-- */
-
-int world_create(lua_State *L)
-{
-	dWorldID *world = lua_newuserdata(L, sizeof(dWorldID *));
-	*world = dWorldCreate();
-	luaL_getmetatable(L, world_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int world_destroy(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	dWorldDestroy(*world);
-	return 0;
-}
-
-
-int world_set_gravity(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	double gx = luaL_checknumber(L, 2);
-	double gy = luaL_checknumber(L, 3);
-	double gz = luaL_checknumber(L, 4);
-	dWorldSetGravity(*world, gx, gy, gz);
-	return 0;
-}
-
-
-int world_get_gravity(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	dVector3 result;
-	dWorldGetGravity(*world, result);
-	lua_pushnumber(L, result[0]);
-	lua_pushnumber(L, result[1]);
-	lua_pushnumber(L, result[2]);
-	return 3;
-}
-
-
-int world_set_cfm(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	double cfm = luaL_checknumber(L, 2);
-	dWorldSetCFM(*world, cfm);
-	return 0;
-}
-
-
-int world_quickstep(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	double stepsize = luaL_checknumber(L, 2);
-	dWorldQuickStep(*world, stepsize);
-	return 0;
-}
-
-
-/* --===== space functions =====-- */
-
-int hash_space_create(lua_State *L)
-{
-	dSpaceID *space = lua_newuserdata(L, sizeof(dSpaceID *));
-	*space = dHashSpaceCreate(NULL);
-	luaL_getmetatable(L, space_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int space_destroy(lua_State *L)
-{
-	dSpaceID *space = luaL_checkudata(L, 1, space_tname);
-	dSpaceDestroy(*space);
-	return 0;
-}
-
-
-static void near_callback(void *data, dGeomID o1, dGeomID o2)
-{
-	lua_State *L = data;
-	lua_pushvalue(L, 2); /* user callback should be at stack index 2 */
-
-	dGeomID *ptr1 = lua_newuserdata(L, sizeof(dGeomID *));
-	*ptr1 = o1;
-	luaL_getmetatable(L, geom_tname);
-	lua_setmetatable(L, -2);
-
-	dGeomID *ptr2 = lua_newuserdata(L, sizeof(dGeomID *));
-	*ptr2 = o2;
-	luaL_getmetatable(L, geom_tname);
-	lua_setmetatable(L, -2);
-
-	lua_call(L, 2, 0);
-}
-
-int space_collide(lua_State *L)
-{
-	dSpaceID *space = luaL_checkudata(L, 1, space_tname);
-	luaL_argcheck(L, lua_type(L, 2) == LUA_TFUNCTION, 2, "");
-	dSpaceCollide(*space, L, near_callback);
-	return 0;
-}
-
-
-/* --===== joint group functions =====-- */
-
-int joint_group_create(lua_State *L)
-{
-	dJointGroupID *group = lua_newuserdata(L, sizeof(dJointGroupID *));
-	*group = dJointGroupCreate(0);
-	luaL_getmetatable(L, joint_group_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int joint_group_destroy(lua_State *L)
-{
-	dJointGroupID *group = luaL_checkudata(L, 1, joint_group_tname);
-	dJointGroupDestroy(*group);
-	return 0;
-}
-
-
-int joint_group_empty(lua_State *L)
-{
-	dJointGroupID *group = luaL_checkudata(L, 1, joint_group_tname);
-	dJointGroupEmpty(*group);
-	return 0;
-}
-
-
-/* --===== joint functions =====-- */
-
-int joint_create_contact(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-	dJointGroupID group = NULL;
-	if (lua_type(L, 2) != LUA_TNIL) {
-		dJointGroupID *ptr = luaL_checkudata(L, 2, joint_group_tname);
-		group = *ptr;
-	}
-	dContact *contact = luaL_checkudata(L, 3, contact_tname);
-
-	dJointID *joint = lua_newuserdata(L, sizeof(dJointID *));
-	*joint = dJointCreateContact(*world, group, contact);
-	luaL_getmetatable(L, joint_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int joint_attach(lua_State *L)
-{
-	dJointID *joint = luaL_checkudata(L, 1, joint_tname);
-	dBodyID *body1 = luaL_checkudata(L, 2, body_tname);
-	dBodyID *body2 = luaL_checkudata(L, 3, body_tname);
-
-	dJointAttach(*joint, *body1, *body2);
-	return 0;
-}
-
-
-
-
-/* --===== body functions =====-- */
-
-int body_create(lua_State *L)
-{
-	dWorldID *world = luaL_checkudata(L, 1, world_tname);
-
-	dBodyID *body = lua_newuserdata(L, sizeof(dBodyID *));
-	*body = dBodyCreate(*world);
-	luaL_getmetatable(L, body_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int body_set_mass(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	dMass *mass = luaL_checkudata(L, 2, mass_tname);
-
-	dBodySetMass(*body, mass);
-	return 0;
-}
-
-
-int body_set_position(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	double x = luaL_checknumber(L, 2);
-	double y = luaL_checknumber(L, 3);
-	double z = luaL_checknumber(L, 4);
-
-	dBodySetPosition(*body, x, y, z);
-	return 0;
-}
-
-
-int body_get_position(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	const dReal *pos = dBodyGetPosition(*body);
-
-	lua_pushnumber(L, pos[0]);
-	lua_pushnumber(L, pos[1]);
-	lua_pushnumber(L, pos[2]);
-	return 3;
-}
-
-
-int body_add_force(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	double fx = luaL_checknumber(L, 2);
-	double fy = luaL_checknumber(L, 3);
-	double fz = luaL_checknumber(L, 4);
-
-	dBodyAddForce(*body, fx, fy, fz);
-	return 0;
-}
-
-
-int body_get_force(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	
-	const dReal *f = dBodyGetForce(*body);
-	lua_pushnumber(L, f[0]);
-	lua_pushnumber(L, f[1]);
-	lua_pushnumber(L, f[2]);
-	return 3;
-}
-
-
-int body_set_linear_vel(lua_State *L)
-{
-	dBodyID *body = luaL_checkudata(L, 1, body_tname);
-	double vx = luaL_checknumber(L, 2);
-	double vy = luaL_checknumber(L, 3);
-	double vz = luaL_checknumber(L, 4);
-
-	dBodySetLinearVel(*body, vx, vy, vz);
-	return 0;
-}
-
-
-/* --===== geom functions =====-- */
-
-int create_sphere(lua_State *L)
-{
-	dSpaceID *space = luaL_checkudata(L, 1, space_tname);
-	double radius = luaL_checknumber(L, 2);
-
-	dGeomID *geom = lua_newuserdata(L, sizeof(dGeomID *));
-	*geom = dCreateSphere(*space, radius);
-	luaL_getmetatable(L, geom_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int create_plane(lua_State *L)
-{
-	dSpaceID *space = luaL_checkudata(L, 1, space_tname);
-	double a = luaL_checknumber(L, 2);
-	double b = luaL_checknumber(L, 3);
-	double c = luaL_checknumber(L, 4);
-	double d = luaL_checknumber(L, 5);
-
-	dGeomID *geom = lua_newuserdata(L, sizeof(dGeomID *));
-	*geom = dCreatePlane(*space, a, b, c, d);
-	luaL_getmetatable(L, geom_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int geom_get_class(lua_State *L)
-{
-	dGeomID *geom = luaL_checkudata(L, 1, geom_tname);
-	int class = dGeomGetClass(*geom);
-	lua_pushinteger(L, class);
-	return 1;
-}
-
-
-int geom_set_body(lua_State *L)
-{
-	dGeomID *geom = luaL_checkudata(L, 1, geom_tname);
-	dBodyID *body = luaL_checkudata(L, 2, body_tname);
-	dGeomSetBody(*geom, *body);
-	return 0;
-}
-
-
-int geom_get_body(lua_State *L)
-{
-	dGeomID *geom = luaL_checkudata(L, 1, geom_tname);
-
-	dBodyID *body = lua_newuserdata(L, sizeof(dBodyID *));
-	*body = dGeomGetBody(*geom);
-	luaL_getmetatable(L, body_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int collide(lua_State *L)
-{
-	dGeomID *o1 = luaL_checkudata(L, 1, geom_tname);
-	dGeomID *o2 = luaL_checkudata(L, 2, geom_tname);
-	dContact *contact = luaL_checkudata(L, 3, contact_tname);
-
-	int count = dCollide(*o1, *o2, 1, &(contact->geom), sizeof(dContactGeom));
-	lua_pushinteger(L, count);
-	return 1;
-}
-
-
-/* --===== mass functions =====-- */
-
-int mass_create(lua_State *L)
-{
-	lua_newuserdata(L, sizeof(dMass));
-	luaL_getmetatable(L, mass_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int mass_set_sphere(lua_State *L)
-{
-	dMass *mass = luaL_checkudata(L, 1, mass_tname);
-	double density = luaL_checknumber(L, 2);
-	double radius = luaL_checknumber(L, 3);
-
-	dMassSetSphere(mass, density, radius);
-	return 0;
-}
-
-
-/* --===== contact functions =====-- */
-
-int contact_create(lua_State *L)
-{
-	lua_newuserdata(L, sizeof(dContact));
-	luaL_getmetatable(L, contact_tname);
-	lua_setmetatable(L, -2);
-	return 1;
-}
-
-
-int contact_surface_set_mode(lua_State *L)
-{
-	dContact *contact = luaL_checkudata(L, 1, contact_tname);
-	int mode = luaL_checkinteger(L, 2);
-	contact->surface.mode = mode;
-	return 0;
-}
-
-
-int contact_surface_set_mu(lua_State *L)
-{
-	dContact *contact = luaL_checkudata(L, 1, contact_tname);
-	double mu = luaL_checknumber(L, 2);
-	contact->surface.mu = mu;
-	return 0;
-}
-
-
-int contact_surface_set_bounce(lua_State *L)
-{
-	dContact *contact = luaL_checkudata(L, 1, contact_tname);
-	double bounce = luaL_checknumber(L, 2);
-	contact->surface.bounce = bounce;
-	return 0;
-}
-
-
-int contact_surface_set_bounce_vel(lua_State *L)
-{
-	dContact *contact = luaL_checkudata(L, 1, contact_tname);
-	double bounce_vel = luaL_checknumber(L, 2);
-	contact->surface.bounce_vel = bounce_vel;
-	return 0;
-}
-
-
-int contact_surface_set_soft_cfm(lua_State *L)
-{
-	dContact *contact = luaL_checkudata(L, 1, contact_tname);
-	double soft_cfm = luaL_checknumber(L, 2);
-	contact->surface.soft_cfm = soft_cfm;
-	return 0;
-}
diff --git a/src/ode/ode_bindings.h b/src/ode/ode_bindings.h
index ac1cc35..2102ab2 100644
--- a/src/ode/ode_bindings.h
+++ b/src/ode/ode_bindings.h
@@ -3,6 +3,418 @@
 
 #include <lua.h>
 
-void setup_ode(lua_State *L, int honey_tbl);
+
+extern const char *ode_world_tname;
+extern const char *ode_space_tname;
+extern const char *ode_body_tname;
+extern const char *ode_geom_tname;
+extern const char *ode_mass_tname;
+extern const char *ode_joint_group_tname;
+extern const char *ode_joint_tname;
+extern const char *ode_jointgroup_tname;
+extern const char *ode_contact_tname;
+
+
+void ode_push_world(lua_State *L, dWorldID w);
+void ode_push_body(lua_State *L, dBodyID b);
+void ode_push_joint(lua_State *L, dJointID j);
+void ode_push_jointgroup(lua_State *L, dJointGroupID jg);
+void ode_push_geom(lua_State *L, dGeomID g);
+void ode_push_space(lua_State *L, dSpaceID s);
+
+
+#define ODE_FUNCTIONS \
+	/* world */ \
+	X("WorldCreate", dWorldCreate_bind) \
+	X("WorldDestroy", dWorldDestroy_bind) \
+	X("WorldSetGravity", dWorldSetGravity_bind) \
+	X("WorldGetGravity", dWorldGetGravity_bind) \
+	X("WorldSetERP", dWorldSetERP_bind) \
+	X("WorldGetERP", dWorldGetERP_bind) \
+	X("WorldSetCFM", dWorldSetCFM_bind) \
+	X("WorldGetCFM", dWorldGetCFM_bind) \
+	X("WorldSetAutoDisableFlag", dWorldSetAutoDisableFlag_bind) \
+	X("WorldGetAutoDisableFlag", dWorldGetAutoDisableFlag_bind) \
+	X("WorldSetAutoDisableLinearThreshold", dWorldSetAutoDisableLinearThreshold_bind) \
+	X("WorldGetAutoDisableLinearThreshold", dWorldGetAutoDisableLinearThreshold_bind) \
+	X("WorldSetAutoDisableAngularThreshold", dWorldSetAutoDisableAngularThreshold_bind) \
+	X("WorldGetAutoDisableAngularThreshold", dWorldGetAutoDisableAngularThreshold_bind) \
+	X("WorldSetAutoDisableSteps", dWorldSetAutoDisableSteps_bind) \
+	X("WorldGetAutoDisableSteps", dWorldGetAutoDisableSteps_bind) \
+	X("WorldSetAutoDisableTime", dWorldSetAutoDisableTime_bind) \
+	X("WorldGetAutoDisableTime", dWorldGetAutoDisableTime_bind) \
+	X("WorldImpulseToForce", dWorldImpulseToForce_bind) \
+	X("WorldStep", dWorldStep_bind) \
+	X("WorldQuickStep", dWorldQuickStep_bind) \
+	X("WorldSetQuickStepNumIterations", dWorldSetQuickStepNumIterations_bind) \
+	X("WorldGetQuickStepNumIterations", dWorldGetQuickStepNumIterations_bind) \
+	X("WorldSetQuickStepW", dWorldSetQuickStepW_bind) \
+	X("WorldGetQuickStepW", dWorldGetQuickStepW_bind) \
+\
+	/* body */ \
+	X("BodyCreate", dBodyCreate_bind) \
+	X("BodyDestroy", dBodyDestroy_bind) \
+	X("BodySetPosition", dBodySetPosition_bind) \
+	X("BodySetRotation", dBodySetRotation_bind) \
+	X("BodySetQuaternion", dBodySetQuaternion_bind) \
+	X("BodySetLinearVel", dBodySetLinearVel_bind) \
+	X("BodySetAngularVel", dBodySetAngularVel_bind) \
+	X("BodyGetPosition", dBodyGetPosition_bind) \
+	X("BodyGetRotation", dBodyGetRotation_bind) \
+	X("BodyGetQuaternion", dBodyGetQuaternion_bind) \
+	X("BodyGetLinearVel", dBodyGetLinearVel_bind) \
+	X("BodyGetAngularVel", dBodyGetAngularVel_bind) \
+	X("BodySetMass", dBodySetMass_bind) \
+	X("BodyGetMass", dBodyGetMass_bind) \
+	X("BodyAddForce", dBodyAddForce_bind) \
+	X("BodyAddTorque", dBodyAddTorque_bind) \
+	X("BodyAddRelForce", dBodyAddRelForce_bind) \
+	X("BodyAddRelTorque", dBodyAddRelTorque_bind) \
+	X("BodyAddForceAtPos", dBodyAddForceAtPos_bind) \
+	X("BodyAddForceAtRelPos", dBodyAddForceAtRelPos_bind) \
+	X("BodyAddRelForceAtPos", dBodyAddRelForceAtPos_bind) \
+	X("BodyAddRelForceAtRelPos", dBodyAddRelForceAtRelPos_bind) \
+	X("BodyGetForce", dBodyGetForce_bind) \
+	X("BodyGetTorque", dBodyGetTorque_bind) \
+	X("BodySetForce", dBodySetForce_bind) \
+	X("BodySetTorque", dBodySetTorque_bind) \
+	X("BodySetDynamic", dBodySetDynamic_bind) \
+	X("BodySetKinematic", dBodySetKinematic_bind) \
+	X("BodyIsKinematic", dBodyIsKinematic_bind) \
+	X("BodyGetRelPointPos", dBodyGetRelPointPos_bind) \
+	X("BodyGetRelPointVel", dBodyGetRelPointVel_bind) \
+	X("BodyGetPointVel", dBodyGetPointVel_bind) \
+	X("BodyGetPosRelPoint", dBodyGetPosRelPoint_bind) \
+	X("BodyVectorToWorld", dBodyVectorToWorld_bind) \
+	X("BodyVectorFromWorld", dBodyVectorFromWorld_bind) \
+	X("BodyEnable", dBodyEnable_bind) \
+	X("BodyDisable", dBodyDisable_bind) \
+	X("BodyIsEnabled", dBodyIsEnabled_bind) \
+	X("BodySetAutoDisableFlag", dBodySetAutoDisableFlag_bind) \
+	X("BodyGetAutoDisableFlag", dBodyGetAutoDisableFlag_bind) \
+	X("BodySetAutoDisableLinearThreshold", dBodySetAutoDisableLinearThreshold_bind) \
+	X("BodyGetAutoDisableLinearThreshold", dBodyGetAutoDisableLinearThreshold_bind) \
+	X("BodySetAutoDisableAngularThreshold", dBodySetAutoDisableAngularThreshold_bind) \
+	X("BodyGetAutoDisableAngularThreshold", dBodyGetAutoDisableAngularThreshold_bind) \
+	X("BodySetAutoDisableSteps", dBodySetAutoDisableSteps_bind) \
+	X("BodyGetAutoDisableSteps", dBodyGetAutoDisableSteps_bind) \
+	X("BodySetAutoDisableTime", dBodySetAutoDisableTime_bind) \
+	X("BodyGetAutoDisableTime", dBodyGetAutoDisableTime_bind) \
+	X("BodySetAutoDisableAverageSamplesCount", dBodySetAutoDisableAverageSamplesCount_bind) \
+	X("BodyGetAutoDisableAverageSamplesCount", dBodyGetAutoDisableAverageSamplesCount_bind) \
+	X("BodySetAutoDisableDefaults", dBodySetAutoDisableDefaults_bind) \
+	X("BodySetMovedCallback", dBodySetMovedCallback_bind) \
+	X("BodyGetLinearDamping", dBodyGetLinearDamping_bind) \
+	X("BodyGetAngularDamping", dBodyGetAngularDamping_bind) \
+	X("BodySetLinearDamping", dBodySetLinearDamping_bind) \
+	X("BodySetAngularDamping", dBodySetAngularDamping_bind) \
+	X("BodySetDamping", dBodySetDamping_bind) \
+	X("BodyGetLinearDampingThreshold", dBodyGetLinearDampingThreshold_bind) \
+	X("BodyGetAngularDampingThreshold", dBodyGetAngularDampingThreshold_bind) \
+	X("BodySetLinearDampingThreshold", dBodySetLinearDampingThreshold_bind) \
+	X("BodySetAngularDampingThreshold", dBodySetAngularDampingThreshold_bind) \
+	X("BodySetDampingDefaults", dBodySetDampingDefaults_bind) \
+	X("BodyGetMaxAngularSpeed", dBodyGetMaxAngularSpeed_bind) \
+	X("BodySetMaxAngularSpeed", dBodySetMaxAngularSpeed_bind) \
+	X("BodySetFiniteRotationMode", dBodySetFiniteRotationMode_bind) \
+	X("BodyGetFiniteRotationMode", dBodyGetFiniteRotationMode_bind) \
+	X("BodySetFiniteRotationAxis", dBodySetFiniteRotationAxis_bind) \
+	X("BodyGetFiniteRotationAxis", dBodyGetFiniteRotationAxis_bind) \
+	X("BodyGetNumJoints", dBodyGetNumJoints_bind) \
+	X("BodyGetJoint", dBodyGetJoint_bind) \
+	X("BodyGetWorld", dBodyGetWorld_bind) \
+	X("BodySetGravityMode", dBodySetGravityMode_bind) \
+	X("BodyGetGravityMode", dBodyGetGravityMode_bind) \
+	X("BodyGetFirstGeom", dBodyGetFirstGeom_bind) \
+	X("BodyGetNextGeom", dBodyGetNextGeom_bind) \
+\
+	/* joints */ \
+	X("JointCreateBall", dJointCreateBall_bind) \
+	X("JointCreateHinge", dJointCreateHinge_bind) \
+	X("JointCreateSlider", dJointCreateSlider_bind) \
+	X("JointCreateContact", dJointCreateContact_bind) \
+	X("JointCreateUniversal", dJointCreateUniversal_bind) \
+	X("JointCreateHinge2", dJointCreateHinge2_bind) \
+	X("JointCreatePR", dJointCreatePR_bind) \
+	X("JointCreatePU", dJointCreatePU_bind) \
+	X("JointCreatePiston", dJointCreatePiston_bind) \
+	X("JointCreateFixed", dJointCreateFixed_bind) \
+	X("JointCreateAMotor", dJointCreateAMotor_bind) \
+	X("JointCreateLMotor", dJointCreateLMotor_bind) \
+	X("JointCreatePlane2D", dJointCreatePlane2D_bind) \
+	X("JointCreateDBall", dJointCreateDBall_bind) \
+	X("JointCreateDHinge", dJointCreateDHinge_bind) \
+	X("JointCreateTransmission", dJointCreateTransmission_bind) \
+	X("JointDestroy", dJointDestroy_bind) \
+	X("JointGroupCreate", dJointGroupCreate_bind) \
+	X("JointGroupDestroy", dJointGroupDestroy_bind) \
+	X("JointGroupEmpty", dJointGroupEmpty_bind) \
+	X("JointAttach", dJointAttach_bind) \
+	X("JointEnable", dJointEnable_bind) \
+	X("JointDisable", dJointDisable_bind) \
+	X("JointIsEnabled", dJointIsEnabled_bind) \
+	X("JointGetType", dJointGetType_bind) \
+	X("JointGetBody", dJointGetBody_bind) \
+	X("AreConnected", dAreConnected_bind) \
+	X("AreConnectedExcluding", dAreConnectedExcluding_bind) \
+	X("JointSetBallAnchor", dJointSetBallAnchor_bind) \
+	X("JointGetBallAnchor", dJointGetBallAnchor_bind) \
+	X("JointGetBallAnchor2", dJointGetBallAnchor2_bind) \
+	X("JointSetHingeAnchor", dJointSetHingeAnchor_bind) \
+	X("JointSetHingeAxis", dJointSetHingeAxis_bind) \
+	X("JointGetHingeAnchor", dJointGetHingeAnchor_bind) \
+	X("JointGetHingeAnchor2", dJointGetHingeAnchor2_bind) \
+	X("JointGetHingeAxis", dJointGetHingeAxis_bind) \
+	X("JointGetHingeAngle", dJointGetHingeAngle_bind) \
+	X("JointGetHingeAngleRate", dJointGetHingeAngleRate_bind) \
+	X("JointSetSliderAxis", dJointSetSliderAxis_bind) \
+	X("JointGetSliderAxis", dJointGetSliderAxis_bind) \
+	X("JointGetSliderPosition", dJointGetSliderPosition_bind) \
+	X("JointGetSliderPositionRate", dJointGetSliderPositionRate_bind) \
+	X("JointSetUniversalAnchor", dJointSetUniversalAnchor_bind) \
+	X("JointSetUniversalAxis1", dJointSetUniversalAxis1_bind) \
+	X("JointSetUniversalAxis2", dJointSetUniversalAxis2_bind) \
+	X("JointGetUniversalAnchor", dJointGetUniversalAnchor_bind) \
+	X("JointGetUniversalAnchor2", dJointGetUniversalAnchor2_bind) \
+	X("JointGetUniversalAxis1", dJointGetUniversalAxis1_bind) \
+	X("JointGetUniversalAxis2", dJointGetUniversalAxis2_bind) \
+	X("JointGetUniversalAngle1", dJointGetUniversalAngle1_bind) \
+	X("JointGetUniversalAngle2", dJointGetUniversalAngle2_bind) \
+	X("JointGetUniversalAngles", dJointGetUniversalAngles_bind) \
+	X("JointGetUniversalAngle1Rate", dJointGetUniversalAngle1Rate_bind) \
+	X("JointGetUniversalAngle2Rate", dJointGetUniversalAngle2Rate_bind) \
+	X("JointSetHinge2Anchor", dJointSetHinge2Anchor_bind) \
+	X("JointSetHinge2Axis1", dJointSetHinge2Axis1_bind) \
+	X("JointSetHinge2Axis2", dJointSetHinge2Axis2_bind) \
+	X("JointGetHinge2Anchor", dJointGetHinge2Anchor_bind) \
+	X("JointGetHinge2Anchor2", dJointGetHinge2Anchor2_bind) \
+	X("JointGetHinge2Axis1", dJointGetHinge2Axis1_bind) \
+	X("JointGetHinge2Axis2", dJointGetHinge2Axis2_bind) \
+	X("JointGetHinge2Angle1", dJointGetHinge2Angle1_bind) \
+	X("JointGetHinge2Angle1Rate", dJointGetHinge2Angle1Rate_bind) \
+	X("JointGetHinge2Angle2Rate", dJointGetHinge2Angle2Rate_bind) \
+	X("JointSetPRAxis1", dJointSetPRAxis1_bind) \
+	X("JointGetPRAxis1", dJointGetPRAxis1_bind) \
+	X("JointSetPRAxis2", dJointSetPRAxis2_bind) \
+	X("JointGetPRAxis2", dJointGetPRAxis2_bind) \
+	X("JointSetPRAnchor", dJointSetPRAnchor_bind) \
+	X("JointGetPRAnchor", dJointGetPRAnchor_bind) \
+	X("JointGetPRPosition", dJointGetPRPosition_bind) \
+	X("JointGetPUPosition", dJointGetPUPosition_bind) \
+	X("JointGetPUPositionRate", dJointGetPUPositionRate_bind) \
+	X("JointSetPUAnchor", dJointSetPUAnchor_bind) \
+	X("JointGetPUAnchor", dJointGetPUAnchor_bind) \
+	X("JointSetPUAnchorDelta", dJointSetPUAnchorDelta_bind) \
+	X("JointSetPUAxis1", dJointSetPUAxis1_bind) \
+	X("JointGetPUAxis1", dJointGetPUAxis1_bind) \
+	X("JointSetPUAxis2", dJointSetPUAxis2_bind) \
+	X("JointGetPUAxis2", dJointGetPUAxis2_bind) \
+	X("JointSetPUAxis3", dJointSetPUAxis3_bind) \
+	X("JointGetPUAxis3", dJointGetPUAxis3_bind) \
+	X("JointSetPUAxisP", dJointSetPUAxisP_bind) \
+	X("JointGetPUAxisP", dJointGetPUAxisP_bind) \
+	X("JointGetPUAngles", dJointGetPUAngles_bind) \
+	X("JointGetPUAngle1", dJointGetPUAngle1_bind) \
+	X("JointGetPUAngle2", dJointGetPUAngle2_bind) \
+	X("JointGetPUAngle1Rate", dJointGetPUAngle1Rate_bind) \
+	X("JointGetPUAngle2Rate", dJointGetPUAngle2Rate_bind) \
+	X("JointSetPistonAnchor", dJointSetPistonAnchor_bind) \
+	X("JointGetPistonAnchor", dJointGetPistonAnchor_bind) \
+	X("JointGetPistonAnchor2", dJointGetPistonAnchor2_bind) \
+	X("JointSetPistonAxis", dJointSetPistonAxis_bind) \
+	X("JointGetPistonAxis", dJointGetPistonAxis_bind) \
+	X("JointSetPistonAxisDelta", dJointSetPistonAxisDelta_bind) \
+	X("JointGetPistonPosition", dJointGetPistonPosition_bind) \
+	X("JointGetPistonPositionRate", dJointGetPistonPositionRate_bind) \
+	X("JointGetPistonAngle", dJointGetPistonAngle_bind) \
+	X("JointGetPistonAngleRate", dJointGetPistonAngleRate_bind) \
+	X("JointAddPistonForce", dJointAddPistonForce_bind) \
+	X("JointSetFixed", dJointSetFixed_bind) \
+	X("JointSetAMotorMode", dJointSetAMotorMode_bind) \
+	X("JointGetAMotorMode", dJointGetAMotorMode_bind) \
+	X("JointSetAMotorNumAxes", dJointSetAMotorNumAxes_bind) \
+	X("JointGetAMotorNumAxes", dJointGetAMotorNumAxes_bind) \
+	X("JointSetAMotorAxis", dJointSetAMotorAxis_bind) \
+	X("JointGetAMotorAxis", dJointGetAMotorAxis_bind) \
+	X("JointGetAMotorAxisRel", dJointGetAMotorAxisRel_bind) \
+	X("JointSetAMotorAngle", dJointSetAMotorAngle_bind) \
+	X("JointGetAMotorAngle", dJointGetAMotorAngle_bind) \
+	X("JointGetAMotorAngleRate", dJointGetAMotorAngleRate_bind) \
+	X("JointSetLMotorNumAxes", dJointSetLMotorNumAxes_bind) \
+	X("JointGetLMotorNumAxes", dJointGetLMotorNumAxes_bind) \
+	X("JointSetLMotorAxis", dJointSetLMotorAxis_bind) \
+	X("JointGetLMotorAxis", dJointGetLMotorAxis_bind) \
+	X("JointSetDBallAnchor1", dJointSetDBallAnchor1_bind) \
+	X("JointSetDBallAnchor2", dJointSetDBallAnchor2_bind) \
+	X("JointGetDBallAnchor1", dJointGetDBallAnchor1_bind) \
+	X("JointGetDBallAnchor2", dJointGetDBallAnchor2_bind) \
+	X("JointGetDBallDistance", dJointGetDBallDistance_bind) \
+	X("JointSetDBallDistance", dJointSetDBallDistance_bind) \
+	X("JointSetDHingeAxis", dJointSetDHingeAxis_bind) \
+	X("JointGetDHingeAxis", dJointGetDHingeAxis_bind) \
+	X("JointSetDHingeAnchor1", dJointSetDHingeAnchor1_bind) \
+	X("JointSetDHingeAnchor2", dJointSetDHingeAnchor2_bind) \
+	X("JointGetDHingeAnchor1", dJointGetDHingeAnchor1_bind) \
+	X("JointGetDHingeAnchor2", dJointGetDHingeAnchor2_bind) \
+	X("JointGetDHingeDistance", dJointGetDHingeDistance_bind) \
+	X("JointSetTransmissionMode", dJointSetTransmissionMode_bind) \
+	X("JointGetTransmissionMode", dJointGetTransmissionMode_bind) \
+	X("JointGetTransmissionContactPoint1", dJointGetTransmissionContactPoint1_bind) \
+	X("JointGetTransmissionContactPoint2", dJointGetTransmissionContactPoint2_bind) \
+	X("JointSetTransmissionAxis1", dJointSetTransmissionAxis1_bind) \
+	X("JointSetTransmissionAxis2", dJointSetTransmissionAxis2_bind) \
+	X("JointGetTransmissionAxis1", dJointGetTransmissionAxis1_bind) \
+	X("JointGetTransmissionAxis2", dJointGetTransmissionAxis2_bind) \
+	X("JointSetTransmissionAnchor1", dJointSetTransmissionAnchor1_bind) \
+	X("JointSetTransmissionAnchor2", dJointSetTransmissionAnchor2_bind) \
+	X("JointGetTransmissionAnchor1", dJointGetTransmissionAnchor1_bind) \
+	X("JointGetTransmissionAnchor2", dJointGetTransmissionAnchor2_bind) \
+	X("JointSetTransmissionRatio", dJointSetTransmissionRatio_bind) \
+	X("JointGetTransmissionRatio", dJointGetTransmissionRatio_bind) \
+	X("JointSetTransmissionAxis", dJointSetTransmissionAxis_bind) \
+	X("JointGetTransmissionAxis", dJointGetTransmissionAxis_bind) \
+	X("JointGetTransmissionAngle1", dJointGetTransmissionAngle1_bind) \
+	X("JointGetTransmissionAngle2", dJointGetTransmissionAngle2_bind) \
+	X("JointGetTransmissionRadius1", dJointGetTransmissionRadius1_bind) \
+	X("JointGetTransmissionRadius2", dJointGetTransmissionRadius2_bind) \
+	X("JointSetTransmissionRadius1", dJointSetTransmissionRadius1_bind) \
+	X("JointSetTransmissionRadius2", dJointSetTransmissionRadius2_bind) \
+	X("JointSetTransmissionBacklash", dJointSetTransmissionBacklash_bind) \
+	X("JointGetTransmissionBacklash", dJointGetTransmissionBacklash_bind) \
+	X("JointSetHingeParam", dJointSetHingeParam_bind) \
+	X("JointSetSliderParam", dJointSetSliderParam_bind) \
+	X("JointSetHinge2Param", dJointSetHinge2Param_bind) \
+	X("JointSetUniversalParam", dJointSetUniversalParam_bind) \
+	X("JointSetAMotorParam", dJointSetAMotorParam_bind) \
+	X("JointSetLMotorParam", dJointSetLMotorParam_bind) \
+	X("JointSetPRParam", dJointSetPRParam_bind) \
+	X("JointSetPUParam", dJointSetPUParam_bind) \
+	X("JointSetPistonParam", dJointSetPistonParam_bind) \
+	X("JointSetDBallParam", dJointSetDBallParam_bind) \
+	X("JointSetDHingeParam", dJointSetDHingeParam_bind) \
+	X("JointSetTransmissionParam", dJointSetTransmissionParam_bind) \
+	X("JointGetHingeParam", dJointGetHingeParam_bind) \
+	X("JointGetSliderParam", dJointGetSliderParam_bind) \
+	X("JointGetHinge2Param", dJointGetHinge2Param_bind) \
+	X("JointGetUniversalParam", dJointGetUniversalParam_bind) \
+	X("JointGetAMotorParam", dJointGetAMotorParam_bind) \
+	X("JointGetLMotorParam", dJointGetLMotorParam_bind) \
+	X("JointGetPRParam", dJointGetPRParam_bind) \
+	X("JointGetPUParam", dJointGetPUParam_bind) \
+	X("JointGetPistonParam", dJointGetPistonParam_bind) \
+	X("JointGetDBallParam", dJointGetDBallParam_bind) \
+	X("JointGetDHingeParam", dJointGetDHingeParam_bind) \
+	X("JointGetTransmissionParam", dJointGetTransmissionParam_bind) \
+	X("JointAddHingeTorque", dJointAddHingeTorque_bind) \
+	X("JointAddUniversalTorques", dJointAddUniversalTorques_bind) \
+	X("JointAddSliderForce", dJointAddSliderForce_bind) \
+	X("JointAddHinge2Torques", dJointAddHinge2Torques_bind) \
+	X("JointAddAMotorTorques", dJointAddAMotorTorques_bind) \
+\
+	/* geom */ \
+	X("GeomDestroy", dGeomDestroy_bind) \
+	X("GeomSetBody", dGeomSetBody_bind) \
+	X("GeomGetBody", dGeomGetBody_bind) \
+	X("GeomSetPosition", dGeomSetPosition_bind) \
+	X("GeomSetRotation", dGeomSetRotation_bind) \
+	X("GeomSetQuaternion", dGeomSetQuaternion_bind) \
+	X("GeomGetPosition", dGeomGetPosition_bind) \
+	X("GeomGetRotation", dGeomGetRotation_bind) \
+	X("GeomGetQuaternion", dGeomGetQuaternion_bind) \
+	X("GeomSetOffsetPosition", dGeomSetOffsetPosition_bind) \
+	X("GeomSetOffsetRotation", dGeomSetOffsetRotation_bind) \
+	X("GeomSetOffsetQuaternion", dGeomSetOffsetQuaternion_bind) \
+	X("GeomSetOffsetWorldPosition", dGeomSetOffsetWorldPosition_bind) \
+	X("GeomSetOffsetWorldRotation", dGeomSetOffsetWorldRotation_bind) \
+	X("GeomSetOffsetWorldQuaternion", dGeomSetOffsetWorldQuaternion_bind) \
+	X("GeomGetOffsetPosition", dGeomGetOffsetPosition_bind) \
+	X("GeomGetOffsetRotation", dGeomGetOffsetRotation_bind) \
+	X("GeomGetOffsetQuaternion", dGeomGetOffsetQuaternion_bind) \
+	X("GeomClearOffset", dGeomClearOffset_bind) \
+	X("GeomGetAABB", dGeomGetAABB_bind) \
+	X("GeomIsSpace", dGeomIsSpace_bind) \
+	X("GeomGetSpace", dGeomGetSpace_bind) \
+	X("GeomGetClass", dGeomGetClass_bind) \
+	X("GeomSetCategoryBits", dGeomSetCategoryBits_bind) \
+	X("GeomSetCollideBits", dGeomSetCollideBits_bind) \
+	X("GeomGetCategoryBits", dGeomGetCategoryBits_bind) \
+	X("GeomGetCollideBits", dGeomGetCollideBits_bind) \
+	X("GeomEnable", dGeomEnable_bind) \
+	X("GeomDisable", dGeomDisable_bind) \
+	X("GeomIsEnabled", dGeomIsEnabled_bind) \
+	X("Collide", dCollide_bind) \
+	X("SpaceCollide", dSpaceCollide_bind) \
+	X("SpaceCollide2", dSpaceCollide2_bind) \
+	X("SimpleSpaceCreate", dSimpleSpaceCreate_bind) \
+	X("HashSpaceCreate", dHashSpaceCreate_bind) \
+	X("QuadTreeSpaceCreate", dQuadTreeSpaceCreate_bind) \
+	X("SpaceDestroy", dSpaceDestroy_bind) \
+	X("HashSpaceSetLevels", dHashSpaceSetLevels_bind) \
+	X("HashSpaceGetLevels", dHashSpaceGetLevels_bind) \
+	X("SpaceSetCleanup", dSpaceSetCleanup_bind) \
+	X("SpaceGetCleanup", dSpaceGetCleanup_bind) \
+	X("SpaceSetSublevel", dSpaceSetSublevel_bind) \
+	X("SpaceGetSublevel", dSpaceGetSublevel_bind) \
+	X("SpaceAdd", dSpaceAdd_bind) \
+	X("SpaceRemove", dSpaceRemove_bind) \
+	X("SpaceQuery", dSpaceQuery_bind) \
+	X("SpaceGetNumGeoms", dSpaceGetNumGeoms_bind) \
+	X("SpaceGetGeom", dSpaceGetGeom_bind) \
+	X("CreateSphere", dCreateSphere_bind) \
+	X("GeomSphereSetRadius", dGeomSphereSetRadius_bind) \
+	X("GeomSphereGetRadius", dGeomSphereGetRadius_bind) \
+	X("GeomSpherePointDepth", dGeomSpherePointDepth_bind) \
+	X("CreateBox", dCreateBox_bind) \
+	X("GeomBoxSetLengths", dGeomBoxSetLengths_bind) \
+	X("GeomBoxGetLengths", dGeomBoxGetLengths_bind) \
+	X("GeomBoxPointDepth", dGeomBoxPointDepth_bind) \
+	X("CreatePlane", dCreatePlane_bind) \
+	X("GeomPlaneSetParams", dGeomPlaneSetParams_bind) \
+	X("GeomPlaneGetParams", dGeomPlaneGetParams_bind) \
+	X("GeomPlanePointDepth", dGeomPlanePointDepth_bind) \
+	X("CreateCapsule", dCreateCapsule_bind) \
+	X("GeomCapsuleSetParams", dGeomCapsuleSetParams_bind) \
+	X("GeomCapsuleGetParams", dGeomCapsuleGetParams_bind) \
+	X("GeomCapsulePointDepth", dGeomCapsulePointDepth_bind) \
+	X("CreateCylinder", dCreateCylinder_bind) \
+	X("GeomCylinderSetParams", dGeomCylinderSetParams_bind) \
+	X("GeomCylinderGetParams", dGeomCylinderGetParams_bind) \
+	X("CreateRay", dCreateRay_bind) \
+	X("GeomRaySetLength", dGeomRaySetLength_bind) \
+	X("GeomRayGetLength", dGeomRayGetLength_bind) \
+	X("GeomRaySet", dGeomRaySet_bind) \
+	X("GeomRayGet", dGeomRayGet_bind) \
+	X("GeomRaySetParams", dGeomRaySetParams_bind) \
+	X("GeomRayGetParams", dGeomRayGetParams_bind) \
+	X("GeomRaySetClosestHit", dGeomRaySetClosestHit_bind) \
+	X("GeomRayGetClosestHit", dGeomRayGetClosestHit_bind) \
+	X("CreateConvex", dCreateConvex_bind) \
+	X("GeomSetConvex", dGeomSetConvex_bind) \
+	X("GeomTriMeshDataCreate", dGeomTriMeshDataCreate_bind) \
+	X("GeomTriMeshDataDestroy", dGeomTriMeshDataDestroy_bind) \
+	X("GeomTriMeshDataBuild", dGeomTriMeshDataBuild_bind) \
+	X("GeomTriMeshDataBuildSimple", dGeomTriMeshDataBuildSimple_bind) \
+	X("CreateTriMesh", dCreateTriMesh_bind) \
+	X("GeomTriMeshSetData", dGeomTriMeshSetData_bind) \
+	X("GeomTriMeshClearTCCache", dGeomTriMeshClearTCCache_bind) \
+	X("GeomTriMeshGetTriangle", dGeomTriMeshGetTriangle_bind) \
+	X("GeomTriMeshGetPoint", dGeomTriMeshGetPoint_bind) \
+	X("GeomTriMeshEnableTC", dGeomTriMeshEnableTC_bind) \
+	X("GeomTriMeshIsTCEnabled", dGeomTriMeshIsTCEnabled_bind) \
+	X("GeomHeightfieldDataCreate", dGeomHeightfieldDataCreate_bind) \
+	X("GeomHeightfieldDataDestroy", dGeomHeightfieldDataDestroy_bind) \
+	X("GeomHeightfieldDataBuildDouble", dGeomHeightfieldDataBuildDouble_bind) \
+	X("GeomHeightfieldDataBuildCallback", dGeomHeightfieldDataBuildCallback_bind) \
+	X("GeomHeightfieldDataSetBounds", dGeomHeightfieldDataSetBounds_bind) \
+	X("CreateHeightfield", dCreateHeightfield_bind) \
+	X("GeomHeightfieldSetHeightfieldData", dGeomHeightfieldSetHeightfieldData_bind) \
+	X("GeomHeightfieldGetHeightfieldData", dGeomHeightfieldGetHeightfieldData_bind) \
+
+
+
+
+#define X(name, func) int func(lua_State *L);
+ODE_FUNCTIONS
+#undef X
 
 #endif
diff --git a/src/ode/setup.c b/src/ode/setup.c
new file mode 100644
index 0000000..36e37c1
--- /dev/null
+++ b/src/ode/setup.c
@@ -0,0 +1,73 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <ode/ode.h>
+#include "util/util.h"
+#include "ode_bindings.h"
+
+
+/* setup/teardown */
+int init_ode(lua_State *L);
+int close_ode(lua_State *L);
+
+
+#define NEW_METATABLE(name) luaL_newmetatable(L, name); lua_pop(L, 1);
+const char *ode_world_tname = "ode.WorldID";
+const char *ode_space_tname = "ode.SpaceID";
+const char *ode_body_tname  = "ode.BodyID";
+const char *ode_geom_tname  = "ode.GeomID";
+const char *ode_mass_tname  = "ode.Mass";
+const char *ode_joint_tname = "ode.JointID";
+const char *ode_jointgroup_tname = "ode.JointGroupID";
+const char *ode_contact_tname = "ode.Contact";
+
+
+void setup_ode(lua_State *L, int honey_tbl)
+{
+	/* setup metatables */
+	NEW_METATABLE(ode_world_tname);
+	NEW_METATABLE(ode_space_tname);
+	NEW_METATABLE(ode_body_tname);
+	NEW_METATABLE(ode_geom_tname);
+	NEW_METATABLE(ode_mass_tname);
+	NEW_METATABLE(ode_joint_tname);
+	NEW_METATABLE(ode_jointgroup_tname);
+	NEW_METATABLE(ode_contact_tname);
+
+	/* create main table */
+	struct honey_tbl_t ode[] = {
+		H_FUNC("InitODE", init_ode),
+		H_FUNC("CloseODE", close_ode),
+		#define X(name, func) H_FUNC(name, func),
+		ODE_FUNCTIONS
+		#undef X
+		H_END
+	};
+	create_table(L, ode);
+	int ode_tbl = lua_gettop(L);
+
+	/* add empty (normal) joint group */
+	ode_push_jointgroup(L, 0);
+	lua_setfield(L, ode_tbl, "JointGroup0");
+
+	/* add null space */
+	ode_push_space(L, 0);
+	lua_setfield(L, ode_tbl, "Space0");
+
+	lua_setfield(L, honey_tbl, "ode");
+}
+
+
+/* --===== setup/teardown =====-- */
+
+int init_ode(lua_State *L)
+{
+	dInitODE();
+	return 0;
+}
+
+
+int close_ode(lua_State *L)
+{
+	dCloseODE();
+	return 0;
+}
diff --git a/src/ode/world.c b/src/ode/world.c
new file mode 100644
index 0000000..69b5a92
--- /dev/null
+++ b/src/ode/world.c
@@ -0,0 +1,250 @@
+#include <lua.h>
+#include <lauxlib.h>
+#include <ode/ode.h>
+#include "ode_bindings.h"
+
+
+void ode_push_world(lua_State *L, dWorldID w)
+{
+	dWorldID *wu = lua_newuserdata(L, sizeof(dWorldID));
+	*wu = w;
+	luaL_getmetatable(L, ode_world_tname);
+	lua_setmetatable(L, -2);
+}
+
+
+int dWorldCreate_bind(lua_State *L)
+{
+	dWorldID w = lua_newuserdata(L, sizeof(dWorldID));
+	ode_push_world(L, w);
+	return 1;
+}
+
+
+int dWorldDestroy_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dWorldDestroy(*w);
+	return 0;
+}
+
+
+int dWorldSetGravity_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal x = luaL_checkinteger(L, 2);
+	dReal y = luaL_checkinteger(L, 3);
+	dReal z = luaL_checkinteger(L, 4);
+	dWorldSetGravity(*w, x, y, z);
+	return 0;
+}
+
+
+int dWorldGetGravity_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dVector3 gravity;
+	dWorldGetGravity(*w, gravity);
+	lua_pushnumber(L, gravity[0]);
+	lua_pushnumber(L, gravity[1]);
+	lua_pushnumber(L, gravity[2]);
+	return 3;
+}
+
+
+int dWorldSetERP_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal erp = luaL_checkinteger(L, 2);
+	dWorldSetERP(*w, erp);
+	return 0;
+}
+
+
+int dWorldGetERP_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetERP(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetCFM_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal cfm = luaL_checkinteger(L, 2);
+	dWorldSetCFM(*w, cfm);
+	return 0;
+}
+
+
+int dWorldGetCFM_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetCFM(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetAutoDisableFlag_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int do_auto_disable = luaL_checkinteger(L, 2);
+	dWorldSetAutoDisableFlag(*w, do_auto_disable);
+	return 0;
+}
+
+
+int dWorldGetAutoDisableFlag_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int bind_result = dWorldGetAutoDisableFlag(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetAutoDisableLinearThreshold_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal linear_threshold = luaL_checkinteger(L, 2);
+	dWorldSetAutoDisableLinearThreshold(*w, linear_threshold);
+	return 0;
+}
+
+
+int dWorldGetAutoDisableLinearThreshold_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetAutoDisableLinearThreshold(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetAutoDisableAngularThreshold_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal angular_threshold = luaL_checkinteger(L, 2);
+	dWorldSetAutoDisableAngularThreshold(*w, angular_threshold);
+	return 0;
+}
+
+
+int dWorldGetAutoDisableAngularThreshold_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetAutoDisableAngularThreshold(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetAutoDisableSteps_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int steps = luaL_checkinteger(L, 2);
+	dWorldSetAutoDisableSteps(*w, steps);
+	return 0;
+}
+
+
+int dWorldGetAutoDisableSteps_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int bind_result = dWorldGetAutoDisableSteps(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetAutoDisableTime_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal time = luaL_checkinteger(L, 2);
+	dWorldSetAutoDisableTime(*w, time);
+	return 0;
+}
+
+
+int dWorldGetAutoDisableTime_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetAutoDisableTime(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldImpulseToForce_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal stepsize = luaL_checkinteger(L, 2);
+	dReal ix = luaL_checkinteger(L, 3);
+	dReal iy = luaL_checkinteger(L, 4);
+	dReal iz = luaL_checkinteger(L, 5);
+	dVector3 force;
+	dWorldImpulseToForce(*w, stepsize, ix, iy, iz, force);
+	lua_pushnumber(L, force[0]);
+	lua_pushnumber(L, force[1]);
+	lua_pushnumber(L, force[2]);
+	return 3;
+}
+
+
+int dWorldStep_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal stepsize = luaL_checkinteger(L, 2);
+	dWorldStep(*w, stepsize);
+	return 0;
+}
+
+
+int dWorldQuickStep_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal stepsize = luaL_checkinteger(L, 2);
+	dWorldQuickStep(*w, stepsize);
+	return 0;
+}
+
+
+int dWorldSetQuickStepNumIterations_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int num = luaL_checkinteger(L, 2);
+	dWorldSetQuickStepNumIterations(*w, num);
+	return 0;
+}
+
+
+int dWorldGetQuickStepNumIterations_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	int bind_result = dWorldGetQuickStepNumIterations(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
+int dWorldSetQuickStepW_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal over_relaxation = luaL_checkinteger(L, 2);
+	dWorldSetQuickStepW(*w, over_relaxation);
+	return 0;
+}
+
+
+int dWorldGetQuickStepW_bind(lua_State *L)
+{
+	dWorldID *w = luaL_checkudata(L, 1, ode_world_tname);
+	dReal bind_result = dWorldGetQuickStepW(*w);
+	lua_pushinteger(L, bind_result);
+	return 1;
+}
+
+
-- 
cgit v1.2.1