From 3768a30bb20615007e3cb3c42ced9107eda74272 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Thu, 6 Feb 2014 01:13:31 -0800 Subject: [PATCH] added very crude little LuaDemo, to create physics objects using Lua scripts (very preliminary) --- Demos3/AllBullet2Demos/BulletDemoEntries.h | 3 +- Demos3/AllBullet2Demos/premake4.lua | 9 +- .../bullet2/BasicDemo/Bullet2RigidBodyDemo.h | 2 +- Demos3/bullet2/LuaDemo/LuaDemo.cpp | 499 ++++++++++++++++++ Demos3/bullet2/LuaDemo/LuaDemo.h | 29 + btgui/OpenGLWindow/SimpleOpenGL3App.cpp | 40 ++ btgui/OpenGLWindow/SimpleOpenGL3App.h | 1 + data/init_physics.lua | 70 +++ 8 files changed, 649 insertions(+), 4 deletions(-) create mode 100644 Demos3/bullet2/LuaDemo/LuaDemo.cpp create mode 100644 Demos3/bullet2/LuaDemo/LuaDemo.h create mode 100644 data/init_physics.lua diff --git a/Demos3/AllBullet2Demos/BulletDemoEntries.h b/Demos3/AllBullet2Demos/BulletDemoEntries.h index 7ac66ec53..34df5728a 100644 --- a/Demos3/AllBullet2Demos/BulletDemoEntries.h +++ b/Demos3/AllBullet2Demos/BulletDemoEntries.h @@ -9,6 +9,7 @@ #include "../bullet2/FeatherstoneMultiBodyDemo/MultiDofDemo.h" #include "../bullet2/RagdollDemo/RagdollDemo.h" +#include "../bullet2/LuaDemo/LuaDemo.h" struct BulletDemoEntry @@ -27,7 +28,7 @@ static BulletDemoEntry allDemos[]= {"Ragdoll",RagDollDemo::MyCreateFunc}, {"MultiBody1",FeatherstoneDemo1::MyCreateFunc}, {"MultiDofDemo",MultiDofDemo::MyCreateFunc}, - + {"LuaDemo",LuaDemo::MyCreateFunc} }; diff --git a/Demos3/AllBullet2Demos/premake4.lua b/Demos3/AllBullet2Demos/premake4.lua index 486d6f469..dd0cd5a2d 100644 --- a/Demos3/AllBullet2Demos/premake4.lua +++ b/Demos3/AllBullet2Demos/premake4.lua @@ -9,13 +9,14 @@ includedirs { ".", "../../src", - "../../btgui" + "../../btgui", + "../../btgui/lua-5.2.3/src" } initOpenGL() initGlew() - links{"gwen", "OpenGL_Window","OpenGL_TrueTypeFont","BulletSoftBody","BulletDynamics","BulletCollision","LinearMath"} + links{"gwen", "OpenGL_Window","OpenGL_TrueTypeFont","BulletSoftBody","BulletDynamics","BulletCollision","LinearMath","lua-5.2.3"} files { "**.cpp", @@ -32,6 +33,10 @@ "../bullet2/BasicDemo/HingeDemo.h", "../bullet2/RagdollDemo/RagdollDemo.cpp", "../bullet2/RagdollDemo/RagdollDemo.h", + "../bullet2/LuaDemo/LuaDemo.cpp", + "../bullet2/LuaDemo/LuaDemo.h", + + "../../src/Bullet3Common/**.cpp", "../../src/Bullet3Common/**.h", "../../btgui/Timing/b3Clock.cpp", diff --git a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h index 866b1cda4..53ddbb17b 100644 --- a/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h +++ b/Demos3/bullet2/BasicDemo/Bullet2RigidBodyDemo.h @@ -7,7 +7,7 @@ class Bullet2RigidBodyDemo : public BulletDemoInterface { -protected: +public: class btDiscreteDynamicsWorld* m_dynamicsWorld; class btCollisionDispatcher* m_dispatcher; class btBroadphaseInterface* m_bp; diff --git a/Demos3/bullet2/LuaDemo/LuaDemo.cpp b/Demos3/bullet2/LuaDemo/LuaDemo.cpp new file mode 100644 index 000000000..584542796 --- /dev/null +++ b/Demos3/bullet2/LuaDemo/LuaDemo.cpp @@ -0,0 +1,499 @@ +#include "LuaDemo.h" +#include "OpenGLWindow/SimpleOpenGL3App.h" +#include "btBulletDynamicsCommon.h" +#include "LinearMath/btVector3.h" +#include + +#include "BulletDynamics/ConstraintSolver/btNNCGConstraintSolver.h" + +extern "C" { + #include "lua.h" + #include "lualib.h" +#include "lauxlib.h" +} + + +char* sLuaFileName = "init_physics.lua"; + +static const float scaling=0.35f; +static LuaDemo* sLuaDemo = 0; + +static btVector4 colors[4] = +{ + btVector4(1,0,0,1), + btVector4(0,1,0,1), + btVector4(0,1,1,1), + btVector4(1,1,0,1), +}; + +//todo: allow to create solver, broadphase, multiple worlds etc. +static int createDefaultDynamicsWorld(lua_State *L) +{ + sLuaDemo->m_config = new btDefaultCollisionConfiguration; + sLuaDemo->m_dispatcher = new btCollisionDispatcher(sLuaDemo->m_config); + sLuaDemo->m_bp = new btDbvtBroadphase(); + sLuaDemo->m_solver = new btNNCGConstraintSolver(); + sLuaDemo->m_dynamicsWorld = new btDiscreteDynamicsWorld(sLuaDemo->m_dispatcher,sLuaDemo->m_bp,sLuaDemo->m_solver,sLuaDemo->m_config); + lua_pushlightuserdata (L, sLuaDemo->m_dynamicsWorld); + return 1; +} + + +static int deleteDynamicsWorld(lua_State *L) +{ + return 0; +} + +ATTRIBUTE_ALIGNED16(struct) CustomShapeData +{ + btVector3 m_localScaling; + int m_shapeIndex; + + +}; + + +ATTRIBUTE_ALIGNED16(struct) CustomRigidBodyData +{ + int m_graphicsInstanceIndex; +}; + +static int createCubeShape(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc==4) + { + btVector3 halfExtents(1,1,1); + if (!lua_isuserdata(L,1)) + { + std::cerr << "error: first argument to createCubeShape should be world"; + return 0; + } + //expect userdata = sLuaDemo->m_dynamicsWorld + halfExtents = btVector3(lua_tonumber(L,2),lua_tonumber(L,3),lua_tonumber(L,4)); + btCollisionShape* colShape = new btBoxShape(halfExtents); + + CustomShapeData* shapeData = new CustomShapeData(); + shapeData->m_shapeIndex = sLuaDemo->m_glApp->registerCubeShape(); + shapeData->m_localScaling = halfExtents; + + colShape->setUserPointer(shapeData); + lua_pushlightuserdata (L, colShape); + return 1; + } else + { + std::cerr << "Error: invalid number of arguments to createCubeShape, expected 4 (world,halfExtentsX,halfExtentsY,halfExtentsX) but got " << argc; + } + return 0; +} + +static int createSphereShape(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc==2) + { + btVector3 halfExtents(1,1,1); + if (!lua_isuserdata(L,1)) + { + std::cerr << "error: first argument to createSphereShape should be world"; + return 0; + } + //expect userdata = sLuaDemo->m_dynamicsWorld + btScalar radius = lua_tonumber(L,2); + btCollisionShape* colShape = new btSphereShape(radius); + + CustomShapeData* shapeData = new CustomShapeData(); + shapeData->m_shapeIndex = sLuaDemo->m_glApp->registerGraphicsSphereShape(radius,false,100,0.5); + shapeData->m_localScaling = halfExtents; + + colShape->setUserPointer(shapeData); + lua_pushlightuserdata (L, colShape); + return 1; + } else + { + std::cerr << "Error: invalid number of arguments to createSphereShape, expected 2 (world,radius) but got " << argc; + } + return 0; +} + +int luaL_returnlen(lua_State* L, int index) +{ + lua_len(L, index); + int len = lua_tointeger(L,-1); + lua_pop(L, 1); + return len; +} + +btVector3 getLuaVectorArg(lua_State* L, int index) +{ + btVector3 pos(0,0,0); + + int sz = luaL_returnlen(L, index); // get size of table + { + lua_rawgeti(L, index, 1); // push t[i] + pos[0] = lua_tonumber(L,-1); + lua_pop(L, 1); + lua_rawgeti(L, index, 2); // push t[i] + pos[1] = lua_tonumber(L,-1); + lua_pop(L, 1); + lua_rawgeti(L, index, 3); // push t[i] + pos[2] = lua_tonumber(L,-1); + lua_pop(L, 1); + } + return pos; +} + +btQuaternion getLuaQuaternionArg(lua_State* L, int index) +{ + btQuaternion orn(0,0,0,1); + + int sz = luaL_returnlen(L, index); // get size of table + { + lua_rawgeti(L, index, 1); // push t[i] + orn[0] = lua_tonumber(L,-1); + lua_pop(L, 1); + lua_rawgeti(L, index, 2); // push t[i] + orn[1] = lua_tonumber(L,-1); + lua_pop(L, 1); + lua_rawgeti(L, index, 3); // push t[i] + orn[2] = lua_tonumber(L,-1); + lua_pop(L, 1); + lua_rawgeti(L, index, 4); // push t[i] + orn[3] = lua_tonumber(L,-1); + lua_pop(L, 1); + } + return orn; +} + + + + +static int createRigidBody (lua_State *L) +{ + int argc = lua_gettop(L); + if (argc==5) + { + + btTransform startTransform; + startTransform.setIdentity(); + + + if (!lua_isuserdata(L,1)) + { + std::cerr << "error: first argument to b3CreateRigidbody should be world"; + return 0; + } + btDiscreteDynamicsWorld* world = (btDiscreteDynamicsWorld*) lua_touserdata(L,1); + if (world != sLuaDemo->m_dynamicsWorld) + { + std::cerr << "error: first argument expected to be a world"; + return 0; + } + + if (!lua_isuserdata(L,2)) + { + std::cerr << "error: second argument to b3CreateRigidbody should be world"; + return 0; + } + + btScalar mass = lua_tonumber(L,3); + + luaL_checktype(L,4, LUA_TTABLE); + + btVector3 pos = getLuaVectorArg(L,4); + + btQuaternion orn = getLuaQuaternionArg(L,5); + + btCollisionShape* colShape = (btCollisionShape* )lua_touserdata(L,2); + //expect userdata = sLuaDemo->m_dynamicsWorld + + btVector3 inertia(0,0,0); + if (mass) + { + colShape->calculateLocalInertia(mass,inertia); + } + + + + btRigidBody* body = new btRigidBody(mass,0,colShape,inertia); + body->getWorldTransform().setOrigin(pos); + body->getWorldTransform().setRotation(orn); + + + CustomShapeData* shapeData = (CustomShapeData*)colShape->getUserPointer(); + if (shapeData) + { + CustomRigidBodyData* rbd = new CustomRigidBodyData; + static int curColor = 0; + btVector4 color = colors[curColor]; + curColor++; + curColor&=3; + + CustomShapeData* shapeData = (CustomShapeData*)body->getCollisionShape()->getUserPointer(); + if (shapeData) + { + + rbd ->m_graphicsInstanceIndex = sLuaDemo->m_glApp->m_instancingRenderer->registerGraphicsInstance(shapeData->m_shapeIndex,startTransform.getOrigin(),startTransform.getRotation(),color,shapeData->m_localScaling); + body->setUserPointer(rbd); + } + } + + world->addRigidBody(body); + lua_pushlightuserdata (L, body); + return 1; + } else + { + std::cerr << "Error: invalid number of arguments to createRigidBody, expected 5 (world,shape,mass,pos,orn) but got " << argc; + } + return 0; +} + +static int setBodyPosition(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc==3) + { + if (!lua_isuserdata(L,1)) + { + std::cerr << "error: first argument needs to be a world"; + return 0; + } + if (!lua_isuserdata(L,2)) + { + std::cerr << "error: second argument needs to be a body"; + return 0; + } + btRigidBody* body = (btRigidBody*)lua_touserdata(L,2); + btVector3 pos = getLuaVectorArg(L,3); + + btTransform& tr = body ->getWorldTransform(); + tr.setOrigin(pos); + body->setWorldTransform(tr); + } else + { + std::cerr << "error: setBodyPosition expects 6 arguments like setBodyPosition(world,body,0,1,0)"; + } + return 0; +} + +static int setBodyOrientation(lua_State *L) +{ + int argc = lua_gettop(L); + if (argc==3) + { + if (!lua_isuserdata(L,1)) + { + std::cerr << "error: first argument needs to be a world"; + return 0; + } + if (!lua_isuserdata(L,2)) + { + std::cerr << "error: second argument needs to be a body"; + return 0; + } + btRigidBody* body = (btRigidBody*)lua_touserdata(L,2); + btQuaternion orn = getLuaQuaternionArg(L,3); + btTransform& tr = body ->getWorldTransform(); + tr.setRotation(orn); + body->setWorldTransform(tr); + } else + { + std::cerr << "error: setBodyOrientation expects 3 arguments like setBodyOrientation(world,body,orn)"; + } + return 0; +} + +//b3CreateConvexShape(world, points) + +//b3CreateHingeConstraint(world,bodyA,bodyB,...) + + + + + +LuaDemo::LuaDemo(SimpleOpenGL3App* app) +:Bullet2RigidBodyDemo(app) +{ + sLuaDemo = this; +} + +LuaDemo::~LuaDemo() +{ + sLuaDemo = 0; +} + +static void report_errors(lua_State *L, int status) +{ + if ( status!=0 ) { + std::cerr << "-- " << lua_tostring(L, -1) << std::endl; + lua_pop(L, 1); // remove error message + } +} + + +void LuaDemo::initPhysics() +{ + + + const char* prefix[]={"./","./data/","../data/","../../data/","../../../data/","../../../../data/"}; + int numPrefixes = sizeof(prefix)/sizeof(const char*); + char relativeFileName[1024]; + FILE* f=0; + int result = 0; + + for (int i=0;!f && iregisterCubeShape(); + float pos[]={0,0,0}; + float orn[]={0,0,0,1}; + + + + + { + float halfExtents[]={scaling,scaling,scaling,1}; + btVector4 colors[4] = + { + btVector4(1,0,0,1), + btVector4(0,1,0,1), + btVector4(0,1,1,1), + btVector4(1,1,0,1), + }; + + + + btTransform startTransform; + startTransform.setIdentity(); + btScalar mass = 1.f; + btVector3 localInertia; + btBoxShape* colShape = new btBoxShape(btVector3(halfExtents[0],halfExtents[1],halfExtents[2])); + colShape ->calculateLocalInertia(mass,localInertia); + + for (int k=0;k<3;k++) + { + for (int i=0;i<3;i++) + { + for(int j = 0;j<3;j++) + { + + btVector4 color = colors[curColor]; + curColor++; + curColor&=3; + startTransform.setOrigin(btVector3( + btScalar(2.0*scaling*i), + btScalar(2.*scaling+2.0*scaling*k), + btScalar(2.0*scaling*j))); + + m_glApp->m_instancingRenderer->registerGraphicsInstance(cubeShapeId,startTransform.getOrigin(),startTransform.getRotation(),color,halfExtents); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform); + btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia); + btRigidBody* body = new btRigidBody(rbInfo); + + + m_dynamicsWorld->addRigidBody(body); + } + } + } + } +#endif + + m_glApp->m_instancingRenderer->writeTransforms(); +} +void LuaDemo::exitPhysics() +{ + //todo: delete bodies, shapes, constraints + + if (m_dynamicsWorld) + { + delete m_dynamicsWorld; + m_dynamicsWorld=0; + delete m_solver; + m_solver=0; + delete m_bp; + m_bp=0; + delete m_dispatcher; + m_dispatcher=0; + delete m_config; + m_config=0; + } +} +void LuaDemo::renderScene() +{ + //sync graphics -> physics world transforms + if (m_dynamicsWorld) + { + for (int i=0;igetNumCollisionObjects();i++) + { + btVector3 pos = m_dynamicsWorld->getCollisionObjectArray()[i]->getWorldTransform().getOrigin(); + btQuaternion orn = m_dynamicsWorld->getCollisionObjectArray()[i]->getWorldTransform().getRotation(); + if (m_dynamicsWorld->getCollisionObjectArray()[i]->getUserPointer()) + { + CustomRigidBodyData* rbd = (CustomRigidBodyData*)m_dynamicsWorld->getCollisionObjectArray()[i]->getUserPointer(); + + + m_glApp->m_instancingRenderer->writeSingleInstanceTransformToCPU(pos,orn,rbd->m_graphicsInstanceIndex); + } + } + m_glApp->m_instancingRenderer->writeTransforms(); + } + + m_glApp->m_instancingRenderer->renderScene(); +} + + +void LuaDemo::stepSimulation(float dt) +{ + if (m_dynamicsWorld) + m_dynamicsWorld->stepSimulation(dt); +} + + + diff --git a/Demos3/bullet2/LuaDemo/LuaDemo.h b/Demos3/bullet2/LuaDemo/LuaDemo.h new file mode 100644 index 000000000..f3f03d096 --- /dev/null +++ b/Demos3/bullet2/LuaDemo/LuaDemo.h @@ -0,0 +1,29 @@ +#ifndef LUA_DEMO_H +#define LUA_DEMO_H + +#include "LinearMath/btVector3.h" +#include "../BasicDemo/Bullet2RigidBodyDemo.h" + + +//We use a struct instead of class, to make it easier to interface with Lua +struct LuaDemo : public Bullet2RigidBodyDemo +{ + +public: + + static BulletDemoInterface* MyCreateFunc(SimpleOpenGL3App* app) + { + return new LuaDemo(app); + } + + LuaDemo(SimpleOpenGL3App* app); + virtual ~LuaDemo(); + + virtual void initPhysics(); + virtual void exitPhysics(); + virtual void renderScene(); + virtual void stepSimulation(float dt); +}; + + +#endif //BASIC_DEMO_H diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp index 080f15834..8bb2b47a6 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.cpp +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.cpp @@ -218,6 +218,46 @@ int SimpleOpenGL3App::registerCubeShape() int shapeId = m_instancingRenderer->registerShape(&cube_vertices[0],numVertices,cube_indices,numIndices); return shapeId; } + + +int SimpleOpenGL3App::registerGraphicsSphereShape(float radius, bool usePointSprites, int largeSphereThreshold, int mediumSphereThreshold) +{ + + int strideInBytes = 9*sizeof(float); + + int graphicsShapeIndex = -1; + + if (radius>=largeSphereThreshold) + { + int numVertices = sizeof(detailed_sphere_vertices)/strideInBytes; + int numIndices = sizeof(detailed_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&detailed_sphere_vertices[0],numVertices,detailed_sphere_indices,numIndices); + } else + { + + if (usePointSprites) + { + int numVertices = sizeof(point_sphere_vertices)/strideInBytes; + int numIndices = sizeof(point_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&point_sphere_vertices[0],numVertices,point_sphere_indices,numIndices,B3_GL_POINTS); + } else + { + if (radius>=mediumSphereThreshold) + { + int numVertices = sizeof(medium_sphere_vertices)/strideInBytes; + int numIndices = sizeof(medium_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&medium_sphere_vertices[0],numVertices,medium_sphere_indices,numIndices); + } else + { + int numVertices = sizeof(low_sphere_vertices)/strideInBytes; + int numIndices = sizeof(low_sphere_indices)/sizeof(int); + graphicsShapeIndex = m_instancingRenderer->registerShape(&low_sphere_vertices[0],numVertices,low_sphere_indices,numIndices); + } + } + } + return graphicsShapeIndex; +} + void SimpleOpenGL3App::drawGrid(int gridSize, float yOffset) { diff --git a/btgui/OpenGLWindow/SimpleOpenGL3App.h b/btgui/OpenGLWindow/SimpleOpenGL3App.h index d282c58b6..be50ee095 100644 --- a/btgui/OpenGLWindow/SimpleOpenGL3App.h +++ b/btgui/OpenGLWindow/SimpleOpenGL3App.h @@ -17,6 +17,7 @@ struct SimpleOpenGL3App virtual ~SimpleOpenGL3App(); int registerCubeShape(); + int registerGraphicsSphereShape(float radius, bool usePointSprites=true, int largeSphereThreshold=100, int mediumSphereThreshold=10); void drawGrid(int gridSize=10, float yOffset=0.001); void swapBuffer(); diff --git a/data/init_physics.lua b/data/init_physics.lua new file mode 100644 index 000000000..eec83f143 --- /dev/null +++ b/data/init_physics.lua @@ -0,0 +1,70 @@ +-- Very basic Lua script to create some Bullet objects. +-- See also Demos3/AllBullet2Demos using Demos3/bullet2/LuaDemo + +--right now we cannot interleave adding instances of different shapes, they have to be added in-order +--hence the two loops. this will be fixed soon + +world = createDefaultDynamicsWorld() + +cubeshape = createCubeShape(world, 30,1,30) +pos={0,0,0} +orn = {0,0,0,1} +mass = 0 +body = createRigidBody(world,cubeshape,mass,pos,orn) + +shape = createCubeShape(world, 1,1,1) + +x=0 +z=0 +maxy = 10 + +toggle=1 + +for x=0,10 do + for y=0,10 do + if toggle==1 then + toggle = 0 + for z=0,10 do + mass = 1 + if (y==maxy) then + --mass=30; + end + pos = {-14+x*2,2+2*y,z*2} + + body = createRigidBody(world,shape,mass,pos,orn) + setBodyPosition(world,body,pos) + setBodyOrientation(world,body,orn) + end + else + toggle = 1 + + end + end +end + +toggle=1 +shape = createSphereShape(world, 1) + +for x=0,10 do + for y=0,20 do + if toggle==1 then + toggle = 0 + else + toggle = 1 + for z=0,10 do + mass = 1 + if (y==maxy) then + --mass=30; + end + + + + pos = {-14+x*2,2+2*y,z*2} + + body = createRigidBody(world,shape,mass,pos,orn) + setBodyPosition(world,body,pos) + setBodyOrientation(world,body,orn) + end + end + end +end