#include "lua_bullet.h"

#include <QDebug>

#include <btBulletDynamicsCommon.h>

#include <BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h>
#include <BulletCollision/Gimpact/btGImpactShape.h>
#include <BulletDynamics/Vehicle/btRaycastVehicle.h>

#include <luabind/adopt_policy.hpp>
#include <luabind/luabind.hpp>
#include <luabind/operator.hpp>
#include <luabind/wrapper_base.hpp>

#define LuaClassNonDeletable(in_class)                                         \
  namespace luabind {                                                          \
  namespace detail {                                                           \
  template <> struct delete_s<in_class> {                                      \
    static void apply(void *) {}                                               \
  };                                                                           \
  template <> struct destruct_only_s<in_class> {                               \
    static void apply(void *) {}                                               \
  };                                                                           \
  }                                                                            \
  }

LuaClassNonDeletable(btDefaultMotionState) LuaClassNonDeletable(btMotionState)
    LuaClassNonDeletable(btCollisionObject) LuaClassNonDeletable(btRigidBody)
        LuaClassNonDeletable(btConcaveShape)

            struct btMotionState_wrap : public btMotionState,
                                        luabind::wrap_base {
  btMotionState_wrap(const btTransform &, const btTransform &) {}
  btMotionState_wrap(const btTransform &) {}

  virtual void getWorldTransform(btTransform &worldTrans) const {
    // qDebug() << "btMotionState_wrap::getWorldTransform()";
    luabind::call_member<void>(this, "getWorldTransform", worldTrans);
    /*
                                                                                          lua_State* L = m_self.state();
                                                                                                  m_self.get(L);
                                                                                                  if( ! lua_isnil( L, -1 ) ) {
                                                                                                  } else {
                                                                                                      qDebug() << "getWorldTransform missing on the Lua side";
                                                                                                  }
                                                                                                  lua_pop( L, 1 ); */
  }

  virtual void setWorldTransform(const btTransform &worldTrans) {
    // qDebug() << "btMotionState_wrap::setWorldTransform()";
    luabind::call_member<void>(this, "setWorldTransform", worldTrans);
    /*
                                                                                          lua_State* L = m_self.state();
                                                                                                  m_self.get(L);
                                                                                                  if( ! lua_isnil( L, -1 ) )
                                                                                                  else
                                                                                                      qDebug() << "setWorldTransform missing on the Lua side";
                                                                                                  lua_pop( L, 1 );*/
  }
};

struct btDefaultMotionState_wrap : public btDefaultMotionState,
                                   btMotionState_wrap {
  btDefaultMotionState_wrap(const btTransform &startTrans,
                            const btTransform &centerOfMassOffset)
      : btDefaultMotionState(startTrans, centerOfMassOffset),
        btMotionState_wrap(startTrans, centerOfMassOffset) {
    // qDebug() << "btDefaultMotionState_wrap()";
  }
  btDefaultMotionState_wrap(const btTransform &startTrans)
      : btDefaultMotionState(startTrans), btMotionState_wrap(startTrans) {
    // qDebug() << "btDefaultMotionState_wrap()";
  }
};

LuaBullet::LuaBullet(QObject *parent) : QObject(parent) {}

void LuaBullet::luaBind(lua_State *s) {
  using namespace luabind;

  // https://pybullet.org/Bullet/BulletFull/

  module(
      s) // https://pybullet.org/Bullet/BulletFull/classbtCollisionShape.html
      [class_<btCollisionShape>("btCollisionShape")
           .property("userPointer", &btCollisionShape::getUserPointer,
                     &btCollisionShape::setUserPointer)
           .def("isPolyhedral", &btCollisionShape::isPolyhedral)
           .def("isConvex2d", &btCollisionShape::isConvex2d)
           .def("isConvex", &btCollisionShape::isConvex)
           .def("isNonMoving", &btCollisionShape::isNonMoving)
           .def("isConcave", &btCollisionShape::isConcave)
           .def("isCompound", &btCollisionShape::isCompound)
           .def("isSoftBody", &btCollisionShape::isSoftBody)
           .def("isInfinite", &btCollisionShape::isInfinite)
           .def("setLocalScaling", &btCollisionShape::setLocalScaling)
           .def("getLocalScaling", &btCollisionShape::getLocalScaling)
           .def("calculateLocalInertia",
                &btCollisionShape::calculateLocalInertia)
           .def("getName", &btCollisionShape::getName)
           .def("getShapeType", &btCollisionShape::getShapeType)
           .def("setMargin", &btCollisionShape::setMargin)
           .def("getMargin", &btCollisionShape::getMargin)
           .def("setUserPointer", &btCollisionShape::setUserPointer)
           .def("getUserPointer", &btCollisionShape::getUserPointer)
           .def("calculateSerializeBufferSize",
                &btCollisionShape::calculateSerializeBufferSize)
           .def("serialize", &btCollisionShape::serialize)
           .def("serializeSingleShape",
                &btCollisionShape::serializeSingleShape)];

  // TODO
  // btStridingMeshInterface
  // btBroadphaseProxy

  // https://pybullet.org/Bullet/BulletFull/classbtMotionState.html
  module(s)[class_<btMotionState, btMotionState *, btMotionState_wrap>(
             "btMotionState")
             .def("getWorldTransform", &btMotionState_wrap::getWorldTransform)
             .def("setWorldTransform", &btMotionState_wrap::setWorldTransform)];

  // https://pybullet.org/Bullet/BulletFull/structbtDefaultMotionState.html
  module(s)[class_<btDefaultMotionState, btDefaultMotionState *,
                   btDefaultMotionState_wrap, btMotionState>(
                "btDefaultMotionState")
                .def(constructor<const btTransform &, const btTransform &>())
                .def(constructor<const btTransform &>(), adopt(result))];

  // BULLET SHAPE CLASSES

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCompoundShape.html
      [class_<btCompoundShape, btCollisionShape>("btCompoundShape")
           .def(constructor<bool>(), adopt(result))
           .def("addChildShape", &btCompoundShape::addChildShape)
           .def("removeChildShape", &btCompoundShape::removeChildShape)
           .def("removeChildShapeByIndex",
                &btCompoundShape::removeChildShapeByIndex)
           .def("getNumChildShapes", &btCompoundShape::getNumChildShapes)
           .def("getChildShape",
                (btCollisionShape * (btCompoundShape::*)(int)) &
                    btCompoundShape::getChildShape)
           .def("getChildTransform", (btTransform & (btCompoundShape::*)(int)) &
                                         btCompoundShape::getChildTransform)
           .def("updateChildTransform", &btCompoundShape::updateChildTransform)
           .def("getChildList", &btCompoundShape::getChildList)
           .def("getDynamicAabbTree", (btDbvt * (btCompoundShape::*)(void)) &
                                          btCompoundShape::getDynamicAabbTree)
           .def("createAabbTreeFromChildren",
                &btCompoundShape::createAabbTreeFromChildren)
           .def("calculatePrincipalAxisTransform",
                &btCompoundShape::calculatePrincipalAxisTransform)
           .def("getUpdateRevision", &btCompoundShape::getUpdateRevision)];

  module(s) // http://bulletphysics.com/Bullet/BulletFull/classbtConcaveShape.html
      [class_<btConcaveShape, btCollisionShape>("btConcaveShape")
           .property("margin", &btConcaveShape::getMargin,
                     &btConcaveShape::setMargin)

           .def("getMargin", &btConcaveShape::getMargin)
           .def("setMargin", &btConcaveShape::setMargin)

           .def("processAllTriangles", &btConcaveShape::processAllTriangles)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtEmptyShape.html
      [class_<btEmptyShape, btConcaveShape>("btEmptyShape")
           .def("getMargin", &btEmptyShape::getMargin)
           .def("setMargin", &btEmptyShape::setMargin)
           .property("margin", &btEmptyShape::getMargin,
                     &btEmptyShape::setMargin)

           .def("processAllTriangles", &btEmptyShape::processAllTriangles)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtGImpactShapeInterface.html
      [class_<btGImpactShapeInterface, btConcaveShape>(
           "btGImpactShapeInterface")
           .def("updateBound", &btGImpactShapeInterface::updateBound)
           .def("getAABB", &btGImpactShapeInterface::getAabb)
           .property("aabb", &btGImpactShapeInterface::getAabb)
           .def("getLocalBox", &btGImpactShapeInterface::getLocalBox)
           .property("localBox", &btGImpactShapeInterface::getLocalBox)
           .def("getBoxSet", &btGImpactShapeInterface::getBoxSet)
           .property("boxSet", &btGImpactShapeInterface::getBoxSet)
           .def("getHasBoxSet", &btGImpactShapeInterface::hasBoxSet)
           .property("hasBoxSet", &btGImpactShapeInterface::hasBoxSet)

       // XXX
  ];

  module(s) // http://bulletphysics.org/Bullet/BulletFull/classbtGImpactMeshShape.html
      [class_<btGImpactMeshShape, btGImpactShapeInterface>("btGImpactMeshShape")
           .def(constructor<btStridingMeshInterface *>(), adopt(result))

           .property("margin", &btGImpactMeshShape::getMargin,
                     &btGImpactMeshShape::setMargin)
           .def("getMargin", &btGImpactMeshShape::getMargin)
           .def("setMargin", &btGImpactMeshShape::setMargin)

           .property("meshInterface",
                     (btStridingMeshInterface * (btGImpactMeshShape::*)()) &
                         btGImpactMeshShape::getMeshInterface)
           .def("getMeshInterface",
                (btStridingMeshInterface * (btGImpactMeshShape::*)()) &
                    btGImpactMeshShape::getMeshInterface)

           .def("updateBound", &btGImpactMeshShape::updateBound)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConvexShape.html
      [class_<btConvexShape, btCollisionShape>("btConvexShape")
           .def("localGetSupportVertexWithoutMarginNonVirtual",
                &btConvexShape::localGetSupportVertexWithoutMarginNonVirtual)
           .def("localGetSupportVertexNonVirtual",
                &btConvexShape::localGetSupportVertexNonVirtual)
           .def("getMarginNonVirtual", &btConvexShape::getMarginNonVirtual)
           .def("getAabbNonVirtual", &btConvexShape::getAabbNonVirtual)
           .def("getAabb", &btConvexShape::getAabb)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConvexInternalShape.html
      [class_<btConvexInternalShape, btConvexShape>("btConvexInternalShape")
           .def("getImplicitShapeDimensions",
                &btConvexInternalShape::getImplicitShapeDimensions)
           .def("setImplicitShapeDimensions",
                &btConvexInternalShape::setImplicitShapeDimensions)
           .def("setSafeMargin",
                (void(btConvexInternalShape::*)(btScalar, btScalar)) &
                    btConvexInternalShape::setSafeMargin)
           .def("getAabb", &btConvexInternalShape::getAabb)
           .def("getLocalScalingNV", &btConvexInternalShape::getLocalScalingNV)
           .def("getMarginNV", &btConvexInternalShape::getMarginNV)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCapsuleShape.html
      [class_<btCapsuleShape, btConvexInternalShape>("btCapsuleShape")
           .def(constructor<btScalar, btScalar>(), adopt(result))
           .property("upAxis", &btCapsuleShape::getUpAxis)
           .def("getUpAxis", &btCapsuleShape::getUpAxis)
           .property("radius", &btCapsuleShape::getRadius)
           .def("getRadius", &btCapsuleShape::getRadius)
           .property("halfHeight", &btCapsuleShape::getHalfHeight)
           .def("getHalfHeight", &btCapsuleShape::getHalfHeight)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCapsuleShapeX.html
      [class_<btCapsuleShapeX, btCapsuleShape>("btCapsuleShapeX")
           .def(constructor<btScalar, btScalar>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCapsuleShapeZ.html
      [class_<btCapsuleShapeZ, btCapsuleShape>("btCapsuleShapeZ")
           .def(constructor<btScalar, btScalar>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConeShape.html
      [class_<btConeShape, btConvexInternalShape>("btConeShape")
           .def(constructor<btScalar, btScalar>(), adopt(result))
           .def("getRadius", &btConeShape::getRadius)
           .def("setRadius", &btConeShape::setRadius)
           .property("radius", &btConeShape::getRadius, &btConeShape::setRadius)
           .def("getHeight", &btConeShape::getHeight)
           .def("setHeight", &btConeShape::setHeight)
           .property("height", &btConeShape::getHeight, &btConeShape::setHeight)
           .def("setConeUpIndex", &btConeShape::setConeUpIndex)
           .def("getConeUpIndex", &btConeShape::getConeUpIndex)
           .def("setLocalScaling", &btConeShape::setLocalScaling)
           .def("getLocalScaling", &btConeShape::getLocalScaling)
           .def("calculateLocalInertia", &btConeShape::calculateLocalInertia)
           .def("setMargin", &btConeShape::setMargin)
           .def("getMargin", &btConeShape::getMargin)
           .def("setImplicitShapeDimensions", &btConeShape::setImplicitShapeDimensions)
           .def("getImplicitShapeDimensions", &btConeShape::getImplicitShapeDimensions)
           .def("getAabb", &btConeShape::getAabb)
           .def("localGetSupportingVertexWithoutMargin", &btConeShape::localGetSupportingVertexWithoutMargin)
           .def("localGetSupportingVertex", &btConeShape::localGetSupportingVertex)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConeShapeX.html
      [class_<btConeShapeX, btConeShape>("btConeShapeX")
           .def(constructor<btScalar, btScalar>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConeShapeZ.html
      [class_<btConeShapeZ, btConeShape>("btConeShapeZ")
           .def(constructor<btScalar, btScalar>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConvexInternalAabbCachingShape.html
      [class_<btConvexInternalAabbCachingShape>(
           "btConvexInternalAabbCachingShape")
           .def("recalcLocalAabb",
                &btConvexInternalAabbCachingShape::recalcLocalAabb)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtMultiSphereShape.html
      [class_<btMultiSphereShape, btConvexInternalAabbCachingShape>(
           "btMultiSphereShape")
           .def(constructor<const btVector3 *, const btScalar *, int>(),
                adopt(result))
           .def("getSphereCount", &btMultiSphereShape::getSphereCount)
           .def("getSpherePosition", &btMultiSphereShape::getSpherePosition)
           .def("getSphereRadius", &btMultiSphereShape::getSphereRadius)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCylinderShape.html
      [class_<btCylinderShape, btConvexInternalShape>("btCylinderShape")
           .def("getHalfExtentsWithMargin",
                &btCylinderShape::getHalfExtentsWithMargin)
           .def("getHalfExtentsWithoutMargin",
                &btCylinderShape::getHalfExtentsWithoutMargin)
           .def("getAabb", &btCylinderShape::getAabb)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCylinderShapeX.html
      [class_<btCylinderShapeX, btCylinderShape>("btCylinderShapeX")
           .def(constructor<const btVector3 &>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCylinderShapeZ.html
      [class_<btCylinderShapeZ, btCylinderShape>("btCylinderShapeZ")
           .def(constructor<const btVector3 &>(), adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtPolyhedralConvexShape.html
      [class_<btPolyhedralConvexShape, btConvexInternalShape>(
          "btPolyhedralConvexShape")
       // TODO .def("getConvexPolyhedron",
       // &btPolyhedralConvexShape::getConvexPolyhedron) needs definition of
       // btConvexPolyhedron not in the headers
  ];

  // not in the headers
  // https://pybullet.org/Bullet/BulletFull/classbtBox2dShape.html

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtBoxShape.html
      [class_<btBoxShape, btPolyhedralConvexShape>("btBoxShape")
           .def(constructor<const btVector3 &>(), adopt(result))
           .def("getHalfExtentsWithMargin",
                &btBoxShape::getHalfExtentsWithMargin)
           .def("getHalfExtentsWithoutMargin",
                &btBoxShape::getHalfExtentsWithoutMargin)
           .def("localGetSupportingVertexWithoutMargin",
                &btBoxShape::localGetSupportingVertexWithoutMargin)
           .def("setImplicitShapeDimensions",
                &btBoxShape::setImplicitShapeDimensions)
           .def("getImplicitShapeDimensions",
                &btBoxShape::getImplicitShapeDimensions)
           .def("setMargin", &btBoxShape::setMargin)
           .def("getMargin", &btBoxShape::getMargin)
           .def("calculateLocalInertia", &btBoxShape::calculateLocalInertia)
           .def("setLocalScaling", &btBoxShape::setLocalScaling)
           .def("getLocalScaling", &btBoxShape::getLocalScaling)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtPolyhedralConvexAabbCachingShape.html
      [class_<btPolyhedralConvexAabbCachingShape, btPolyhedralConvexShape>(
           "btPolyhedralConvexAabbCachingShape")
           .def("getNonvirtualAabb",
                &btPolyhedralConvexAabbCachingShape::getNonvirtualAabb)
           .def("recalcLocalAabb",
                &btPolyhedralConvexAabbCachingShape::recalcLocalAabb)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtBU__Simplex1to4.html
      [class_<btBU_Simplex1to4, btPolyhedralConvexAabbCachingShape>(
           "btBU_Simplex1to4")
           .def(constructor<>(), adopt(result))
           .def(constructor<const btVector3 &>(), adopt(result))
           .def(constructor<const btVector3 &, const btVector3 &>(),
                adopt(result))
           .def(constructor<const btVector3 &, const btVector3 &,
                            const btVector3 &>(),
                adopt(result))
           .def(constructor<const btVector3 &, const btVector3 &,
                            const btVector3 &, const btVector3 &>(),
                adopt(result))
           .def("reset", &btBU_Simplex1to4::reset)
           .def("addVertex", &btBU_Simplex1to4::addVertex)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTetrahedronShapeEx.html
      [class_<btTetrahedronShapeEx, btBU_Simplex1to4>("btTetrahedronShapeEx")
           .def(constructor<>(), adopt(result))
           .def("setVertices", &btTetrahedronShapeEx::setVertices)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConvexHullShape.html
      [class_<btConvexHullShape, btPolyhedralConvexAabbCachingShape>(
           "btConvexHullShape")
           .def(constructor<>(), adopt(result))
           .def(constructor<const btScalar *, int, int>(), adopt(result))
           .def("addPoint", &btConvexHullShape::addPoint)
           .def("getUnscaledPoints", (btVector3 * (btConvexHullShape::*)()) &
                                         btConvexHullShape::getUnscaledPoints)
           .def("getPoints", &btConvexHullShape::getPoints)
           .def("getScaledPoint", &btConvexHullShape::getScaledPoint)
           .def("getNumPoints", &btConvexHullShape::getNumPoints)];

  // not defined in the headers
  // https://pybullet.org/Bullet/BulletFull/classbtConvexPointCloudShape.html

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtStridingMeshInterface.html
      [class_<btStridingMeshInterface>("btStridingMeshInterface")
           .def("calculateAabbBruteForce",
                &btStridingMeshInterface::calculateAabbBruteForce)

           .property("scaling", &btStridingMeshInterface::getScaling,
                     &btStridingMeshInterface::setScaling)
           .def("getScaling", &btStridingMeshInterface::getScaling)
           .def("setScaling", &btStridingMeshInterface::setScaling)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTriangleIndexVertexArray.html
      [class_<btTriangleIndexVertexArray, btStridingMeshInterface>(
           "btTriangleIndexVertexArray")
           .def("getIndexedMeshArray",
                (IndexedMeshArray & (btTriangleIndexVertexArray::*)()) &
                    btTriangleIndexVertexArray::getIndexedMeshArray)
           .def("addaddIndexedMesh",
                &btTriangleIndexVertexArray::addIndexedMesh)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTriangleMesh.html
      [class_<btTriangleMesh, btTriangleIndexVertexArray>("btTriangleMesh")
           .def(constructor<bool, bool>(), adopt(result))
           .def(constructor<bool>(), adopt(result))
           .def(constructor<>(), adopt(result))
           .def("addIndex", &btTriangleMesh::addIndex)
           .def("addTriangle", &btTriangleMesh::addTriangle)
           // not in Bullet on Ubuntu 14.04 .def("addTriangleIndices",
           // &btTriangleMesh::addTriangleIndices)
           .def("findOrAddVertex", &btTriangleMesh::findOrAddVertex)
           .def("getNumTriangles", &btTriangleMesh::getNumTriangles)
           .property("numTriangles", &btTriangleMesh::getNumTriangles)
           .def("getUse32bitIndices", &btTriangleMesh::getUse32bitIndices)
           .property("use32bitIndices", &btTriangleMesh::getUse32bitIndices)
           .def("getUse4componentVertices",
                &btTriangleMesh::getUse4componentVertices)
           .property("use4componentVertices",
                     &btTriangleMesh::getUse4componentVertices)
           .def("preallocateIndices", &btTriangleMesh::preallocateIndices)
           .def("preallocateVertices", &btTriangleMesh::preallocateVertices)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtConvexTriangleMeshShape.html
      [class_<btConvexTriangleMeshShape, btPolyhedralConvexAabbCachingShape>(
           "btConvexTriangleMeshShape")
           .def(constructor<btStridingMeshInterface *, bool>(), adopt(result))
           .def("getMeshInterface",
                (btStridingMeshInterface * (btConvexTriangleMeshShape::*)()) &
                    btConvexTriangleMeshShape::getMeshInterface)
           .def("calculatePrincipalAxisTransform",
                &btConvexTriangleMeshShape::calculatePrincipalAxisTransform)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTriangleShape.html
      [class_<btTriangleShape, btPolyhedralConvexShape>("btTriangleShape")
           .def(constructor<const btVector3 &, const btVector3 &,
                             const btVector3 &>(),
                adopt(result))
           .def("getVertexPtr", (btVector3 & (btTriangleShape::*)(int)) &
                                    btTriangleShape::getVertexPtr)
           .def("calcNormal", &btTriangleShape::calcNormal)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTriangleShapeEx.html
      [class_<btTriangleShapeEx, btTriangleShape>("btTriangleShapeEx")
           .def(constructor<>(), adopt(result))
           .def(constructor<const btVector3 &, const btVector3 &,
                            const btVector3 &>(),
                adopt(result))
           .def(constructor<const btTriangleShapeEx>(), adopt(result))
           .def("applyTransform", &btTriangleShapeEx::applyTransform)
           .def("buildTriPlane", &btTriangleShapeEx::buildTriPlane)
           .def("overlap_test_conservative",
                &btTriangleShapeEx::overlap_test_conservative)];

  // not defined in the headers
  // https://pybullet.org/Bullet/BulletFull/classbtSoftClusterCollisionShape.html

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtSphereShape.html
      [class_<btSphereShape, btConvexInternalShape>("btSphereShape")
           .def(constructor<btScalar>(), adopt(result))
           .def("getRadius", &btSphereShape::getRadius)
           .property("radius", &btSphereShape::getRadius)
           .def("setUnscaledRadius", &btSphereShape::setUnscaledRadius)
           .property("unscaledRadius", &btSphereShape::setUnscaledRadius)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtUniformScalingShape.html
      [class_<btUniformScalingShape, btConvexShape>("btUniformScalingShape")
           .def(constructor<btConvexShape *, btScalar>(), adopt(result))
           .def("getUniformScalingFactor",
                &btUniformScalingShape::getUniformScalingFactor)
           .def("getChildShape",
                (btConvexShape * (btUniformScalingShape::*)()) &
                    btUniformScalingShape::getChildShape)
           .def("getAabb", &btUniformScalingShape::getAabb)];

  // BULLET GEOMETRY CLASSES

  module(s)[class_<btVector3>("btVector3") // https://pybullet.org/Bullet/BulletFull/classbtVector3.html
                .def(constructor<>(), adopt(result))
                .def(constructor<btScalar, btScalar, btScalar>(), adopt(result))
                .def(const_self + const_self)
                .def(const_self - const_self)
                .def(const_self * other<btScalar>())
                .def(const_self / other<btScalar>())
                .def(const_self == const_self)
                .property("x", &btVector3::getX, &btVector3::setX)
                .property("y", &btVector3::getY, &btVector3::setY)
                .property("z", &btVector3::getZ, &btVector3::setZ)
                .def("getX", &btVector3::getX)
                .def("getY", &btVector3::getY)
                .def("getZ", &btVector3::getZ)
                .def("setX", &btVector3::setX)
                .def("setY", &btVector3::setY)
                .def("setZ", &btVector3::setZ)
                .def("absolute", &btVector3::absolute)
                .def("angle", &btVector3::angle)
                .def("closestAxis", &btVector3::closestAxis)
                .def("cross", &btVector3::cross)
                .def("distance", &btVector3::distance)
                .def("distance2", &btVector3::distance2)
                .def("dot", &btVector3::dot)
                .def("furthestAxis", &btVector3::furthestAxis)
                .def("fuzzyZero", &btVector3::fuzzyZero)
                .def("isZero", &btVector3::isZero)
                .def("length", &btVector3::length)
                .def("length2", &btVector3::length2)
                .def("lerp", &btVector3::lerp)
                .def("maxAxis", &btVector3::maxAxis)
                .def("minAxis", &btVector3::minAxis)
                .def("normalize", &btVector3::normalize)
                .def("normalized", &btVector3::normalized)
                .def("rotate", &btVector3::rotate)
                .def("setZero", &btVector3::setZero)
                .def("triple", &btVector3::triple)
                .def(tostring(const_self))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtAABB.html
      [class_<btAABB>("btAABB")
           .def(constructor<>(), adopt(result))
           .def(constructor<btVector3, btVector3, btVector3>(), adopt(result))
           .def(constructor<btVector3, btVector3, btVector3, btScalar>(),
                adopt(result))
           .def(constructor<btAABB &>(), adopt(result))
           .def(constructor<btAABB &, btScalar>(), adopt(result))
           .def("invalidate", &btAABB::invalidate)
           .def("merge", &btAABB::merge)
       // XXX
  ];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtVector4.html
      [class_<btVector4, btVector3>("btVector4")
                .def(constructor<>(), adopt(result))
                .def(constructor<const btScalar &, const btScalar &,
                                 const btScalar &, const btScalar &>(),
                     adopt(result))
                .def("absolute4", &btVector4::absolute4)
                .def("getW", &btVector4::getW)
                .def("maxAxis4", &btVector4::maxAxis4)
                .def("minAxis4", &btVector4::minAxis4)
                .def("closestAxis4", &btVector4::closestAxis4)
                .def("setValue", &btVector4::setValue)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtQuaternion.html
      [class_<btQuaternion>("btQuaternion")
                .def(constructor<>(), adopt(result))
                .def(constructor<const btVector3 &, btScalar>(), adopt(result))
                .def(constructor<btScalar, btScalar, btScalar, btScalar>(),
                     adopt(result))
                .def("angle", &btQuaternion::angle)
                .def("dot", &btQuaternion::dot)
                .def("farthest", &btQuaternion::farthest)
                .def("getAngle", &btQuaternion::getAngle)
                .def("getAxis", &btQuaternion::getAxis)
                .def("getIdentity", &btQuaternion::getIdentity)
                .def("getW", &btQuaternion::getW)
                .def("getX", &btQuaternion::getX)
                .def("getY", &btQuaternion::getY)
                .def("getZ", &btQuaternion::getZ)
                .def("inverse", &btQuaternion::inverse)
                .def("length", &btQuaternion::length)
                .def("length2", &btQuaternion::length2)
                .def("nearest", &btQuaternion::nearest)
                .def("normalize", &btQuaternion::normalize)
                .def("normalized", &btQuaternion::normalized)
                .def("setEuler", &btQuaternion::setEuler)
                .def("setEulerZYX", &btQuaternion::setEulerZYX)
                .def("setMax", &btQuaternion::setMax)
                .def("setMin", &btQuaternion::setMin)
                .def("setRotation", &btQuaternion::setRotation)
                .def("setW", &btQuaternion::setW)
                .def("setX", &btQuaternion::setX)
                .def("setY", &btQuaternion::setY)
                .def("setZ", &btQuaternion::setZ)
                .def("slerp", &btQuaternion::slerp)
                .def("w", &btQuaternion::w)
                .def("x", &btQuaternion::x)
                .def("y", &btQuaternion::y)
                .def("z", &btQuaternion::z)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtCollisionObject.html
      [class_<btCollisionObject>("btCollisionObject")
       .def(constructor<>(), adopt(result))
           .def("mergesSimulationIslands",
                &btCollisionObject::mergesSimulationIslands)
           .def("getAnisotropicFriction",
                &btCollisionObject::getAnisotropicFriction)
           .def("setAnisotropicFriction",
                &btCollisionObject::setAnisotropicFriction)
           .def("hasAnisotropicFriction",
                &btCollisionObject::hasAnisotropicFriction)
           .def("setContactProcessingThreshold",
                &btCollisionObject::setContactProcessingThreshold)
           .def("isStaticObject", &btCollisionObject::isStaticObject)
           .def("isKinematicObject",
                &btCollisionObject::isStaticOrKinematicObject)
           .def("hasContactResponse", &btCollisionObject::hasContactResponse)
           .def("getCollisionShape",
                (btCollisionShape * (btCollisionObject::*)()) &
                    btCollisionObject::getCollisionShape)
           // not in the headers .def("getRootCollisionShape",
           // (btCollisionShape
           // *(btCollisionObject::*)())&btCollisionObject::getRootCollisionShape)
           .def("getActivationState", &btCollisionObject::getActivationState)
           .def("setActivationState", &btCollisionObject::setActivationState)
           .def("setDeactivationTime", &btCollisionObject::setDeactivationTime)
           .def("getDeactivationTime", &btCollisionObject::getDeactivationTime)
           .def("forceActivationState",
                &btCollisionObject::forceActivationState)
           .def("activate", &btCollisionObject::activate)
           .def("isActive", &btCollisionObject::isActive)
           .def("setRestitution", &btCollisionObject::setRestitution)
           .def("getRestitution", &btCollisionObject::getRestitution)
           .def("setFriction", &btCollisionObject::setFriction)
           .def("getFriction", &btCollisionObject::getFriction)
           .def("getWorldTransform", (btTransform & (btCollisionObject::*)()) &
                                         btCollisionObject::getWorldTransform)
           .def("setWorldTransform", &btCollisionObject::setWorldTransform)
           .def("getBroadphaseHandle",
                (btBroadphaseProxy * (btCollisionObject::*)()) &
                    btCollisionObject::getBroadphaseHandle)
           .def("getInterpolationWorldTransform",
                (btTransform & (btCollisionObject::*)()) &
                    btCollisionObject::getInterpolationWorldTransform)
           .def("setInterpolationWorldTransform",
                &btCollisionObject::setInterpolationWorldTransform)
           .def("setInterpolationLinearVelocity",
                &btCollisionObject::setInterpolationLinearVelocity)
           .def("setInterpolationAngularVelocity",
                &btCollisionObject::setInterpolationAngularVelocity)
           .def("getInterpolationLinearVelocity",
                &btCollisionObject::getInterpolationLinearVelocity)
           .def("getInterpolationAngularVelocity",
                &btCollisionObject::getInterpolationAngularVelocity)
           .def("getIslandTag", &btCollisionObject::getIslandTag)
           .def("setIslandTag", &btCollisionObject::setIslandTag)
           .def("getCompanionId", &btCollisionObject::getCompanionId)
           .def("setCompanionId", &btCollisionObject::setCompanionId)
           .def("getHitFraction", &btCollisionObject::getHitFraction)
           .def("setHitFraction", &btCollisionObject::setHitFraction)
           .def("getCollisionFlags", &btCollisionObject::setCollisionFlags)
           .def("setCollisionFlags", &btCollisionObject::getCollisionFlags)
           .def("getCcdSweptSphereRadius",
                &btCollisionObject::getCcdSweptSphereRadius)
           .def("setCcdSweptSphereRadius",
                &btCollisionObject::setCcdSweptSphereRadius)
           .def("getCcdMotionThreshold",
                &btCollisionObject::getCcdMotionThreshold)
           .def("getCcdSquareMotionThreshold",
                &btCollisionObject::getCcdSquareMotionThreshold)
           .def("setCcdMotionThreshold",
                &btCollisionObject::setCcdMotionThreshold)
           .def("getUserPointer", &btCollisionObject::getUserPointer)
           .def("setUserPointer", &btCollisionObject::setUserPointer)
           .def("checkCollideWith", &btCollisionObject::checkCollideWith)];

  // btRigidBodyConstructionInfo

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtRigidBody.html
      [class_<btRigidBody::btRigidBodyConstructionInfo>(
                "btRigidBodyConstructionInfo")
                .def(constructor<btScalar, btMotionState *, btCollisionShape *,
                                 const btVector3 &>(),
                     adopt(result))];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtRigidBody.html
      [class_<btRigidBody, btCollisionObject>("btRigidBody")
           .def(constructor<const btRigidBody::btRigidBodyConstructionInfo &>())
           .def(constructor<btScalar, btMotionState *, btCollisionShape *,
                            const btVector3 &>())
           .def("proceedToTransform", &btRigidBody::proceedToTransform)
           .def("predictIntegratedTransform",
                &btRigidBody::predictIntegratedTransform)
           .def("saveKinematicState", &btRigidBody::saveKinematicState)
           .def("applyGravity", &btRigidBody::applyGravity)
           .def("setGravity", &btRigidBody::setGravity)
           .def("getGravity", &btRigidBody::getGravity)
           .def("setDamping", &btRigidBody::setDamping)
           .def("getLinearDamping", &btRigidBody::getLinearDamping)
           .def("getAngularDamping", &btRigidBody::getAngularDamping)
           .def("getLinearSleepingThreshold",
                &btRigidBody::getLinearSleepingThreshold)
           .def("getAngularSleepingThreshold",
                &btRigidBody::getAngularSleepingThreshold)
           .def("applyDamping", &btRigidBody::applyDamping)
           .def("getCollisionShape", (btCollisionShape * (btRigidBody::*)()) &
                                         btRigidBody::getCollisionShape)
           .def("setMassProps", &btRigidBody::setMassProps)
           .def("getLinearFactor", &btRigidBody::getLinearFactor)
           .def("setLinearFactor", &btRigidBody::setLinearFactor)
           .def("getInvMass", &btRigidBody::getInvMass)
           .def("getInvInertiaTensorWorld",
                &btRigidBody::getInvInertiaTensorWorld)
           .def("integrateVelocities", &btRigidBody::integrateVelocities)
           .def("setCenterOfMassTransform",
                &btRigidBody::setCenterOfMassTransform)
           .def("applyCentralForce", &btRigidBody::applyCentralForce)
           .def("getTotalForce", &btRigidBody::getTotalForce)
           .def("getTotalTorque", &btRigidBody::getTotalTorque)
           .def("getInvInertiaDiagLocal", &btRigidBody::getInvInertiaDiagLocal)
           .def("setInvInertiaDiagLocal", &btRigidBody::setInvInertiaDiagLocal)
           .def("setSleepingThresholds", &btRigidBody::setSleepingThresholds)
           .def("applyTorque", &btRigidBody::applyTorque)
           .def("applyForce", &btRigidBody::applyForce)
           .def("applyCentralImpulse", &btRigidBody::applyCentralImpulse)
           .def("applyTorqueImpulse", &btRigidBody::applyTorqueImpulse)
           .def("applyImpulse", &btRigidBody::applyImpulse)
           .def("clearForces", &btRigidBody::clearForces)
           .def("updateInertiaTensor", &btRigidBody::updateInertiaTensor)
           .def("getCenterOfMassPosition",
                &btRigidBody::getCenterOfMassPosition)
           .def("getOrientation", &btRigidBody::getOrientation)
           .def("getCenterOfMassTransform",
                &btRigidBody::getCenterOfMassTransform)
           .def("getLinearVelocity", &btRigidBody::getLinearVelocity)
           .def("getAngularVelocity", &btRigidBody::getAngularVelocity)
           .def("setLinearVelocity", &btRigidBody::setLinearVelocity)
           .def("setAngularVelocity", &btRigidBody::setAngularVelocity)
           .def("getVelocityInLocalPoint",
                &btRigidBody::getVelocityInLocalPoint)
           .def("translate", &btRigidBody::translate)
           .def("getAabb", &btRigidBody::getAabb)
           .def("computeImpulseDenominator",
                &btRigidBody::computeImpulseDenominator)
           .def("computeAngularImpulseDenominator",
                &btRigidBody::computeAngularImpulseDenominator)
           .def("updateDeactivation", &btRigidBody::updateDeactivation)
           .def("wantsSleeping", &btRigidBody::wantsSleeping)
           .def("getBroadphaseProxy",
                (btBroadphaseProxy * (btRigidBody::*)(void)) &
                    btRigidBody::getBroadphaseProxy)
           .def("setNewBroadphaseProxy", &btRigidBody::setNewBroadphaseProxy)
           .def("getMotionState", (btMotionState * (btRigidBody::*)(void)) &
                                      btRigidBody::getMotionState)
           .def("setMotionState", &btRigidBody::setMotionState)
           .def("setAngularFactor", (void(btRigidBody::*)(const btVector3 &)) &
                                        btRigidBody::setAngularFactor)
           .def("setAngularFactor", (void(btRigidBody::*)(btScalar)) &
                                        btRigidBody::setAngularFactor)
           .def("getAngularFactor", &btRigidBody::getAngularFactor)
           .def("isInWorld", &btRigidBody::isInWorld)
           .def("checkCollideWithOverride",
                &btRigidBody::checkCollideWithOverride)
           .def("addConstraintRef", &btRigidBody::addConstraintRef)
           .def("removeConstraintRef", &btRigidBody::removeConstraintRef)
           .def("getConstraintRef", &btRigidBody::getConstraintRef)
           .def("getNumConstraintRefs", &btRigidBody::getNumConstraintRefs)
           .def("setFlags", &btRigidBody::setFlags)
           .def("getFlags", &btRigidBody::getFlags)
       // not in the headers .def("getDeltaLinearVelocity",
       // &btRigidBody::getDeltaLinearVelocity) not in the headers
       // .def("getDeltaAngularVelocity", &btRigidBody::getDeltaAngularVelocity)
       // not in the headers .def("getPushVelocity",
       // &btRigidBody::getPushVelocity) not in the headers
       // .def("getTurnVelocity", &btRigidBody::getTurnVelocity)
  ];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtTransform.html
      [class_<btTransform>("btTransform")
                .def(constructor<>())
                .def(constructor<const btQuaternion &, const btVector3 &>())
                .def("getIdentity", &btTransform::getIdentity)
                .def("getOpenGLMatrix", &btTransform::getOpenGLMatrix)
                .def("getRotation", &btTransform::getRotation)
                .def("inverse", &btTransform::inverse)
                .def("inverseTimes", &btTransform::inverseTimes)
                .def("invXform", &btTransform::invXform)
                .def("mult", &btTransform::mult)
                .def("setBasis", &btTransform::setBasis)
                .def("setFromOpenGLMatrix", &btTransform::setFromOpenGLMatrix)
                .def("setIdentity", &btTransform::setIdentity)
                .def("setOrigin", &btTransform::setOrigin)
                .def("setRotation", &btTransform::setRotation)];

  // BULLET CONSTRAINT CLASSES

  module(s)[class_<btTypedConstraint>("btTypedConstraint")];

  module(s)[class_<btPoint2PointConstraint, btTypedConstraint>(
                "btPoint2PointConstraint")
                .def(constructor<btRigidBody &, btRigidBody &,
                                 const btVector3 &, const btVector3 &>())
                .def("setParam", &btPoint2PointConstraint::setParam)];

  module(
      s)[class_<btHingeConstraint, btTypedConstraint>("btHingeConstraint")
             .def(constructor<btRigidBody &, btRigidBody &, const btVector3 &,
                              const btVector3 &, const btVector3 &,
                              const btVector3 &>())
             .def(constructor<btRigidBody &, btRigidBody &, const btTransform &,
                              const btTransform &>())
             .def("setAxis", &btHingeConstraint::setAxis)
             .def("setLimit", &btHingeConstraint::setLimit)
             .def("setParam", &btHingeConstraint::setParam)
             .def("enableAngularMotor", &btHingeConstraint::enableAngularMotor)
             .def("getHingeAngle", (btScalar(btHingeConstraint::*)()) &
                                       btHingeConstraint::getHingeAngle)
             .def("getHingeAngle",
                  (btScalar(btHingeConstraint::*)(const btTransform &,
                                                  const btTransform &)) &
                      btHingeConstraint::getHingeAngle)];

  module(s) // https://pybullet.org/Bullet/BulletFull/classbtHingeAccumulatedAngleConstraint.html
      [class_<btHingeAccumulatedAngleConstraint, btHingeConstraint>(
             "btHingeAccumulatedAngleConstraint")
             .def(constructor<btRigidBody &, btRigidBody &, const btVector3 &,
                              const btVector3 &, const btVector3 &,
                              const btVector3 &, bool>())
             .def(constructor<btRigidBody &, btRigidBody &, const btTransform &,
                              const btTransform &, bool>())
             .def("setAccumulatedHingeAngle",
                  &btHingeAccumulatedAngleConstraint::setAccumulatedHingeAngle)
             .def(
                 "getAccumulatedHingeAngle",
                 &btHingeAccumulatedAngleConstraint::getAccumulatedHingeAngle)];

  module(s)
      [class_<btSliderConstraint, btTypedConstraint>("btSliderConstraint")
           .def(constructor<btRigidBody &, btRigidBody &, const btTransform &,
                            const btTransform &, bool>())
           .def("setLowerLinLimit", &btSliderConstraint::setLowerLinLimit)
           .def("setUpperLinLimit", &btSliderConstraint::setUpperLinLimit)
           .def("setLowerAngLimit", &btSliderConstraint::setLowerAngLimit)
           .def("setUpperAngLimit", &btSliderConstraint::setUpperAngLimit)
           .def("setSoftnessDirLin", &btSliderConstraint::setSoftnessDirLin)
           .def("setRestitutionDirLin",
                &btSliderConstraint::setRestitutionDirLin)
           .def("setDampingDirLin", &btSliderConstraint::setDampingDirLin)
           .def("setSoftnessDirAng", &btSliderConstraint::setSoftnessDirAng)
           .def("setRestitutionDirAng",
                &btSliderConstraint::setRestitutionDirAng)
           .def("setDampingDirAng", &btSliderConstraint::setDampingDirAng)
           .def("setSoftnessLimLin", &btSliderConstraint::setSoftnessLimLin)
           .def("setRestitutionLimLin",
                &btSliderConstraint::setRestitutionLimLin)
           .def("setDampingLimLin", &btSliderConstraint::setDampingLimLin)
           .def("setSoftnessLimAng", &btSliderConstraint::setSoftnessLimAng)
           .def("setRestitutionLimAng",
                &btSliderConstraint::setRestitutionLimAng)
           .def("setDampingLimAng", &btSliderConstraint::setDampingLimAng)
           .def("setSoftnessOrthoLin", &btSliderConstraint::setSoftnessOrthoLin)
           .def("setRestitutionOrthoLin",
                &btSliderConstraint::setRestitutionOrthoLin)
           .def("setDampingOrthoLin", &btSliderConstraint::setDampingOrthoLin)
           .def("setSoftnessOrthoAng", &btSliderConstraint::setSoftnessOrthoAng)
           .def("setRestitutionOrthoAng",
                &btSliderConstraint::setRestitutionOrthoAng)
           .def("setDampingOrthoAng", &btSliderConstraint::setDampingOrthoAng)
           .def("setParam", &btSliderConstraint::setParam)];

  module(
      s)[class_<btGeneric6DofConstraint, btTypedConstraint>(
             "btGeneric6DofConstraint")
             .def(constructor<btRigidBody &, btRigidBody &, const btTransform &,
                              const btTransform &, bool>())
             .def("setLinearUpperLimit",
                  &btGeneric6DofConstraint::setLinearUpperLimit)
             .def("setLinearLowerLimit",
                  &btGeneric6DofConstraint::setLinearLowerLimit)
             .def("setLimit", &btGeneric6DofConstraint::setLimit)
             .def("setAxis", &btGeneric6DofConstraint::setAxis)
             .def("setParam", &btGeneric6DofConstraint::setParam)];

  module(
      s)[class_<btGeneric6DofSpringConstraint, btTypedConstraint>(
             "btGeneric6DofSpringConstraint")
             .def(constructor<btRigidBody &, btRigidBody &, const btTransform &,
                              const btTransform &, bool>())
             .def("enableSpring", &btGeneric6DofSpringConstraint::enableSpring)
             .def("setStiffness", &btGeneric6DofSpringConstraint::setStiffness)
             .def("setDamping", &btGeneric6DofSpringConstraint::setDamping)
             .def("setAxis", &btGeneric6DofSpringConstraint::setAxis)
             .def("setEquilibriumPoint",
                  (void(btGeneric6DofSpringConstraint::*)()) &
                      btGeneric6DofSpringConstraint::setEquilibriumPoint)
             .def("setEquilibriumPoint",
                  (void(btGeneric6DofSpringConstraint::*)(int)) &
                      btGeneric6DofSpringConstraint::setEquilibriumPoint)
             .def("setEquilibriumPoint",
                  (void(btGeneric6DofSpringConstraint::*)(int, btScalar)) &
                      btGeneric6DofSpringConstraint::setEquilibriumPoint)];

  module(
      s)[class_<btUniversalConstraint, btTypedConstraint>(
             "btUniversalConstraint")
             .def(constructor<btRigidBody &, btRigidBody &, const btVector3 &,
                              const btVector3 &, const btVector3 &>())
             .def("setAxis", &btUniversalConstraint::setAxis)
             .def("setUpperLimit", &btHingeConstraint::setLimit)
             .def("setLowerLimit", &btHingeConstraint::setParam)];

  module(s)[class_<btVehicleRaycaster>("btVehicleRaycaster")];

  module(s)[class_<btDefaultVehicleRaycaster, btVehicleRaycaster>(
      "btDefaultVehicleRaycaster")];

  module(
      s)[class_<btRaycastVehicle::btVehicleTuning>("btVehicleTuning")
             .def(constructor<>())
             .def_readwrite(
                 "suspensionStiffness",
                 &btRaycastVehicle::btVehicleTuning::m_suspensionStiffness)
             .def_readwrite(
                 "suspensionCompression",
                 &btRaycastVehicle::btVehicleTuning::m_suspensionCompression)
             .def_readwrite(
                 "suspensionDamping",
                 &btRaycastVehicle::btVehicleTuning::m_suspensionDamping)
             .def_readwrite(
                 "maxSuspensionTravelCm",
                 &btRaycastVehicle::btVehicleTuning::m_maxSuspensionTravelCm)
             .def_readwrite("frictionSlip",
                            &btRaycastVehicle::btVehicleTuning::m_frictionSlip)
             .def_readwrite(
                 "maxSuspensionForce",
                 &btRaycastVehicle::btVehicleTuning::m_maxSuspensionForce)];

  module(s)[class_<btWheelInfo>("btWheelInfo")];

  module(
      s)[class_<btRaycastVehicle>("btRaycastVehicle")
             .def(constructor<const btRaycastVehicle::btVehicleTuning &,
                              btRigidBody *, btVehicleRaycaster *>())
             .def("setCoordinateSystem", &btRaycastVehicle::setCoordinateSystem)
             .def("addWheel", &btRaycastVehicle::addWheel)
             .def("applyEngineForce", &btRaycastVehicle::applyEngineForce)
             .def("updateWheelTransform",
                  &btRaycastVehicle::updateWheelTransform)
             .def("updateVehicle", &btRaycastVehicle::updateVehicle)];
}
