Merge branch 'master' into 3D-NN-walkers-example
This commit is contained in:
@@ -18,6 +18,7 @@ language "C++"
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h",
|
||||
"../CommonInterfaces/*",
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +50,7 @@ files {
|
||||
"../ExampleBrowser/OpenGLGuiHelper.cpp",
|
||||
"../ExampleBrowser/GL_ShapeDrawer.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../Utils/b3Clock.cpp",
|
||||
"../Utils/b3Clock.h",
|
||||
}
|
||||
@@ -90,6 +92,7 @@ files {
|
||||
"../ExampleBrowser/OpenGLGuiHelper.cpp",
|
||||
"../ExampleBrowser/GL_ShapeDrawer.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../TinyRenderer/geometry.cpp",
|
||||
"../TinyRenderer/model.cpp",
|
||||
"../TinyRenderer/tgaimage.cpp",
|
||||
@@ -130,6 +133,7 @@ files {
|
||||
"*.h",
|
||||
"../StandaloneMain/main_tinyrenderer_single_example.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../OpenGLWindow/SimpleCamera.cpp",
|
||||
"../TinyRenderer/geometry.cpp",
|
||||
"../TinyRenderer/model.cpp",
|
||||
@@ -175,6 +179,7 @@ files {
|
||||
"BasicExample.cpp",
|
||||
"*.h",
|
||||
"../StandaloneMain/hellovr_opengl_main.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../ExampleBrowser/OpenGLGuiHelper.cpp",
|
||||
"../ExampleBrowser/GL_ShapeDrawer.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
@@ -200,4 +205,4 @@ if os.is("MacOSX") then
|
||||
links{"Cocoa.framework"}
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,10 +32,12 @@ subject to the following restrictions:
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btTransform.h"
|
||||
#include "../MultiThreadedDemo/ParallelFor.h"
|
||||
|
||||
class btDynamicsWorld;
|
||||
|
||||
#define NUMRAYS 500
|
||||
#define USE_PARALLEL_RAYCASTS 1
|
||||
|
||||
class btRigidBody;
|
||||
class btBroadphaseInterface;
|
||||
@@ -47,11 +49,11 @@ struct btCollisionAlgorithmCreateFunc;
|
||||
class btDefaultCollisionConfiguration;
|
||||
|
||||
|
||||
#include "../CommonInterfaces/CommonRigidBodyBase.h"
|
||||
#include "../MultiThreadedDemo/CommonRigidBodyMTBase.h"
|
||||
|
||||
|
||||
|
||||
class BenchmarkDemo : public CommonRigidBodyBase
|
||||
class BenchmarkDemo : public CommonRigidBodyMTBase
|
||||
{
|
||||
|
||||
//keep the collision shapes, for deletion/cleanup
|
||||
@@ -91,7 +93,7 @@ class BenchmarkDemo : public CommonRigidBodyBase
|
||||
public:
|
||||
|
||||
BenchmarkDemo(struct GUIHelperInterface* helper, int benchmark)
|
||||
:CommonRigidBodyBase(helper),
|
||||
:CommonRigidBodyMTBase(helper),
|
||||
m_benchmark(benchmark)
|
||||
{
|
||||
}
|
||||
@@ -204,7 +206,39 @@ public:
|
||||
sign = -1.0;
|
||||
}
|
||||
|
||||
void cast (btCollisionWorld* cw)
|
||||
void castRays( btCollisionWorld* cw, int iBegin, int iEnd )
|
||||
{
|
||||
for ( int i = iBegin; i < iEnd; ++i )
|
||||
{
|
||||
btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]);
|
||||
|
||||
cw->rayTest (source[i], dest[i], cb);
|
||||
if (cb.hasHit ())
|
||||
{
|
||||
hit[i] = cb.m_hitPointWorld;
|
||||
normal[i] = cb.m_hitNormalWorld;
|
||||
normal[i].normalize ();
|
||||
} else {
|
||||
hit[i] = dest[i];
|
||||
normal[i] = btVector3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
struct CastRaysLoopBody
|
||||
{
|
||||
btRaycastBar2* mRaycasts;
|
||||
btCollisionWorld* mWorld;
|
||||
CastRaysLoopBody(btCollisionWorld* cw, btRaycastBar2* rb) : mWorld(cw), mRaycasts(rb) {}
|
||||
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
mRaycasts->castRays(mWorld, iBegin, iEnd);
|
||||
}
|
||||
};
|
||||
|
||||
void cast (btCollisionWorld* cw, bool multiThreading = false)
|
||||
{
|
||||
#ifdef USE_BT_CLOCK
|
||||
frame_timer.reset ();
|
||||
@@ -228,22 +262,19 @@ public:
|
||||
normal[i].normalize ();
|
||||
}
|
||||
#else
|
||||
for (int i = 0; i < NUMRAYS; i++)
|
||||
{
|
||||
btCollisionWorld::ClosestRayResultCallback cb(source[i], dest[i]);
|
||||
|
||||
cw->rayTest (source[i], dest[i], cb);
|
||||
if (cb.hasHit ())
|
||||
{
|
||||
hit[i] = cb.m_hitPointWorld;
|
||||
normal[i] = cb.m_hitNormalWorld;
|
||||
normal[i].normalize ();
|
||||
} else {
|
||||
hit[i] = dest[i];
|
||||
normal[i] = btVector3(1.0, 0.0, 0.0);
|
||||
}
|
||||
|
||||
}
|
||||
#if USE_PARALLEL_RAYCASTS
|
||||
if ( multiThreading )
|
||||
{
|
||||
CastRaysLoopBody rayLooper(cw, this);
|
||||
int grainSize = 20; // number of raycasts per task
|
||||
parallelFor( 0, NUMRAYS, grainSize, rayLooper );
|
||||
}
|
||||
else
|
||||
#endif // USE_PARALLEL_RAYCASTS
|
||||
{
|
||||
// single threaded
|
||||
castRays(cw, 0, NUMRAYS);
|
||||
}
|
||||
#ifdef USE_BT_CLOCK
|
||||
ms += frame_timer.getTimeMilliseconds ();
|
||||
#endif //USE_BT_CLOCK
|
||||
@@ -354,42 +385,43 @@ void BenchmarkDemo::initPhysics()
|
||||
|
||||
setCameraDistance(btScalar(100.));
|
||||
|
||||
///collision configuration contains default setup for memory, collision setup
|
||||
btDefaultCollisionConstructionInfo cci;
|
||||
cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
|
||||
m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
|
||||
createEmptyDynamicsWorld();
|
||||
/////collision configuration contains default setup for memory, collision setup
|
||||
//btDefaultCollisionConstructionInfo cci;
|
||||
//cci.m_defaultMaxPersistentManifoldPoolSize = 32768;
|
||||
//m_collisionConfiguration = new btDefaultCollisionConfiguration(cci);
|
||||
|
||||
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
|
||||
m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
|
||||
|
||||
m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
|
||||
/////use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
|
||||
//m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration);
|
||||
//
|
||||
//m_dispatcher->setDispatcherFlags(btCollisionDispatcher::CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION);
|
||||
|
||||
|
||||
|
||||
///the maximum size of the collision world. Make sure objects stay within these boundaries
|
||||
///Don't make the world AABB size too large, it will harm simulation quality and performance
|
||||
btVector3 worldAabbMin(-1000,-1000,-1000);
|
||||
btVector3 worldAabbMax(1000,1000,1000);
|
||||
|
||||
btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache();
|
||||
m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache);
|
||||
/////the maximum size of the collision world. Make sure objects stay within these boundaries
|
||||
/////Don't make the world AABB size too large, it will harm simulation quality and performance
|
||||
//btVector3 worldAabbMin(-1000,-1000,-1000);
|
||||
//btVector3 worldAabbMax(1000,1000,1000);
|
||||
//
|
||||
//btHashedOverlappingPairCache* pairCache = new btHashedOverlappingPairCache();
|
||||
//m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,3500,pairCache);
|
||||
// m_broadphase = new btSimpleBroadphase();
|
||||
// m_broadphase = new btDbvtBroadphase();
|
||||
|
||||
|
||||
///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
|
||||
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
|
||||
//btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
|
||||
|
||||
|
||||
m_solver = sol;
|
||||
//m_solver = sol;
|
||||
|
||||
btDiscreteDynamicsWorld* dynamicsWorld;
|
||||
m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
//btDiscreteDynamicsWorld* dynamicsWorld;
|
||||
//m_dynamicsWorld = dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration);
|
||||
|
||||
|
||||
///the following 3 lines increase the performance dramatically, with a little bit of loss of quality
|
||||
m_dynamicsWorld->getSolverInfo().m_solverMode |=SOLVER_ENABLE_FRICTION_DIRECTION_CACHING; //don't recalculate friction values each frame
|
||||
dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations
|
||||
m_dynamicsWorld->getSolverInfo().m_numIterations = 5; //few solver iterations
|
||||
//m_defaultContactProcessingThreshold = 0.f;//used when creating bodies: body->setContactProcessingThreshold(...);
|
||||
m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
|
||||
|
||||
@@ -1242,7 +1274,7 @@ void BenchmarkDemo::initRays()
|
||||
|
||||
void BenchmarkDemo::castRays()
|
||||
{
|
||||
raycastBar.cast (m_dynamicsWorld);
|
||||
raycastBar.cast (m_dynamicsWorld, m_multithreadedWorld);
|
||||
}
|
||||
|
||||
void BenchmarkDemo::createTest7()
|
||||
@@ -1264,7 +1296,7 @@ void BenchmarkDemo::exitPhysics()
|
||||
}
|
||||
m_ragdolls.clear();
|
||||
|
||||
CommonRigidBodyBase::exitPhysics();
|
||||
CommonRigidBodyMTBase::exitPhysics();
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -69,6 +69,12 @@ struct GUIHelperInterface
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)=0;
|
||||
|
||||
|
||||
|
||||
virtual int addUserDebugText3D( const char* txt, const double posisionXYZ[3], const double textColorRGB[3], double size, double lifeTime)=0;
|
||||
virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )=0;
|
||||
virtual void removeUserDebugItem( int debugItemUniqueId)=0;
|
||||
virtual void removeAllUserDebugItems( )=0;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -141,7 +147,22 @@ struct DummyGUIHelper : public GUIHelperInterface
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual void removeUserDebugItem( int debugItemUniqueId)
|
||||
{
|
||||
}
|
||||
virtual void removeAllUserDebugItems( )
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif //GUI_HELPER_INTERFACE_H
|
||||
|
||||
@@ -120,7 +120,7 @@ struct CommonGraphicsApp
|
||||
virtual int getUpAxis() const = 0;
|
||||
|
||||
virtual void swapBuffer() = 0;
|
||||
virtual void drawText( const char* txt, int posX, int posY) = 0;
|
||||
virtual void drawText( const char* txt, int posX, int posY, float size = 1.0f) = 0;
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)=0;
|
||||
virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA)=0;
|
||||
virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex = -1, float textureScaling = 1)=0;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
typedef void (*SliderParamChangedCallback) (float newVal);
|
||||
typedef void (*SliderParamChangedCallback) (float newVal, void* userPointer);
|
||||
#include "LinearMath/btScalar.h"
|
||||
|
||||
struct SliderParams
|
||||
@@ -16,6 +16,7 @@ struct SliderParams
|
||||
btScalar* m_paramValuePointer;
|
||||
void* m_userPointer;
|
||||
bool m_clampToNotches;
|
||||
bool m_clampToIntegers;
|
||||
bool m_showValues;
|
||||
|
||||
SliderParams(const char* name, btScalar* targetValuePointer)
|
||||
@@ -26,6 +27,7 @@ struct SliderParams
|
||||
m_paramValuePointer(targetValuePointer),
|
||||
m_userPointer(0),
|
||||
m_clampToNotches(true),
|
||||
m_clampToIntegers(false),
|
||||
m_showValues(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -950,9 +950,9 @@ bool NN3DWalkersExample::keyboardCallback(int key, int state)
|
||||
case ']':
|
||||
gWalkerMotorStrength *= 1.1f;
|
||||
return true;
|
||||
// case 'l':
|
||||
case 'l':
|
||||
// printWalkerConfigs();
|
||||
// return true;
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -138,19 +138,15 @@ static btScalar gCFMSingularityAvoidance = 0;
|
||||
|
||||
//GUI related parameter changing helpers
|
||||
|
||||
inline void floorSliderValues(float notUsed) { // floor values that should be ints
|
||||
gSolverIterations = floor(gSolverIterations);
|
||||
}
|
||||
|
||||
inline void twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond) { // function to change simulation physics steps per second
|
||||
inline void twxChangePhysicsStepsPerSecond(float physicsStepsPerSecond, void*) { // function to change simulation physics steps per second
|
||||
gPhysicsStepsPerSecond = physicsStepsPerSecond;
|
||||
}
|
||||
|
||||
inline void twxChangeFPS(float framesPerSecond) {
|
||||
inline void twxChangeFPS(float framesPerSecond, void*) {
|
||||
gFramesPerSecond = framesPerSecond;
|
||||
}
|
||||
|
||||
inline void twxChangeERPCFM(float notUsed) { // function to change ERP/CFM appropriately
|
||||
inline void twxChangeERPCFM(float notUsed, void*) { // function to change ERP/CFM appropriately
|
||||
gChangeErpCfm = true;
|
||||
}
|
||||
|
||||
@@ -166,13 +162,12 @@ inline void changeSolver(int comboboxId, const char* item, void* userPointer) {
|
||||
}
|
||||
|
||||
|
||||
inline void twxChangeSolverIterations(float notUsed){ // change the solver iterations
|
||||
inline void twxChangeSolverIterations(float notUsed, void* userPtr) { // change the solver iterations
|
||||
|
||||
floorSliderValues(0); // floor the values set by slider
|
||||
|
||||
}
|
||||
|
||||
inline void clampToCustomSpeedNotches(float speed) { // function to clamp to custom speed notches
|
||||
inline void clampToCustomSpeedNotches(float speed, void*) { // function to clamp to custom speed notches
|
||||
double minSpeed = 0;
|
||||
double minSpeedDist = SimulationSpeeds::MAX_SPEED;
|
||||
for (int i = 0; i < SimulationSpeeds::NUM_SPEEDS; i++) {
|
||||
@@ -200,7 +195,7 @@ inline void switchMaximumSpeed(int buttonId, bool buttonState, void* userPointer
|
||||
// b3Printf("Run maximum speed %s", gMaximumSpeed?"on":"off");
|
||||
}
|
||||
|
||||
inline void setApplicationTick(float frequency){ // set internal application tick
|
||||
inline void setApplicationTick(float frequency, void*){ // set internal application tick
|
||||
gApplicationTick = 1000.0f/frequency;
|
||||
}
|
||||
|
||||
@@ -384,7 +379,7 @@ struct NN3DWalkersTimeWarpBase: public CommonRigidBodyBase {
|
||||
slider.m_minVal = 0;
|
||||
slider.m_maxVal = 1000;
|
||||
slider.m_callback = twxChangePhysicsStepsPerSecond;
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
|
||||
@@ -108,6 +108,29 @@ ELSE(WIN32)
|
||||
ENDIF(APPLE)
|
||||
ENDIF(WIN32)
|
||||
|
||||
IF (BULLET2_MULTITHREADED_OPEN_MP_DEMO)
|
||||
ADD_DEFINITIONS("-DBT_USE_OPENMP=1")
|
||||
IF (MSVC)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /openmp")
|
||||
ELSE (MSVC)
|
||||
# GCC, Clang
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
|
||||
ENDIF (MSVC)
|
||||
ENDIF (BULLET2_MULTITHREADED_OPEN_MP_DEMO)
|
||||
|
||||
IF (BULLET2_MULTITHREADED_PPL_DEMO)
|
||||
ADD_DEFINITIONS("-DBT_USE_PPL=1")
|
||||
ENDIF (BULLET2_MULTITHREADED_PPL_DEMO)
|
||||
|
||||
IF (BULLET2_MULTITHREADED_TBB_DEMO)
|
||||
SET (BULLET2_TBB_INCLUDE_DIR "not found" CACHE PATH "Directory for Intel TBB includes.")
|
||||
SET (BULLET2_TBB_LIB_DIR "not found" CACHE PATH "Directory for Intel TBB libraries.")
|
||||
find_library(TBB_LIBRARY tbb PATHS ${BULLET2_TBB_LIB_DIR})
|
||||
find_library(TBBMALLOC_LIBRARY tbbmalloc PATHS ${BULLET2_TBB_LIB_DIR})
|
||||
ADD_DEFINITIONS("-DBT_USE_TBB=1")
|
||||
INCLUDE_DIRECTORIES( ${BULLET2_TBB_INCLUDE_DIR} )
|
||||
LINK_LIBRARIES( ${TBB_LIBRARY} ${TBBMALLOC_LIBRARY} )
|
||||
ENDIF (BULLET2_MULTITHREADED_TBB_DEMO)
|
||||
|
||||
SET(ExtendedTutorialsSources
|
||||
../ExtendedTutorials/Chain.cpp
|
||||
@@ -146,6 +169,7 @@ SET(BulletExampleBrowser_SRCS
|
||||
|
||||
../SharedMemory/PhysicsServer.cpp
|
||||
../SharedMemory/PhysicsClientSharedMemory.cpp
|
||||
../SharedMemory/PhysicsClientSharedMemory_C_API.cpp
|
||||
../SharedMemory/PhysicsClient.cpp
|
||||
../SharedMemory/PhysicsClientC_API.cpp
|
||||
../SharedMemory/PhysicsServerExample.cpp
|
||||
@@ -173,6 +197,11 @@ SET(BulletExampleBrowser_SRCS
|
||||
../InverseKinematics/InverseKinematicsExample.h
|
||||
../ForkLift/ForkLiftDemo.cpp
|
||||
../ForkLift/ForkLiftDemo.h
|
||||
../MultiThreadedDemo/MultiThreadedDemo.cpp
|
||||
../MultiThreadedDemo/MultiThreadedDemo.h
|
||||
../MultiThreadedDemo/CommonRigidBodyMTBase.cpp
|
||||
../MultiThreadedDemo/CommonRigidBodyMTBase.h
|
||||
../MultiThreadedDemo/ParallelFor.h
|
||||
../Tutorial/Tutorial.cpp
|
||||
../Tutorial/Tutorial.h
|
||||
../Tutorial/Dof6ConstraintTutorial.cpp
|
||||
@@ -346,9 +375,26 @@ ADD_CUSTOM_COMMAND(
|
||||
COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${BULLET_PHYSICS_SOURCE_DIR}/data ${PROJECT_BINARY_DIR}/data
|
||||
)
|
||||
|
||||
IF (BULLET2_MULTITHREADED_TBB_DEMO AND WIN32)
|
||||
# add a post build command to copy some dlls to the executable directory
|
||||
set(TBB_VC_VER "vc12")
|
||||
set(TBB_VC_ARCH "ia32")
|
||||
# assume 32-bit build in VC12 for now
|
||||
# checks can be added here at a later time
|
||||
ADD_CUSTOM_COMMAND(TARGET App_ExampleBrowser POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${BULLET2_TBB_INCLUDE_DIR}/../bin/${TBB_VC_ARCH}/${TBB_VC_VER}/tbb.dll"
|
||||
$<TARGET_FILE_DIR:App_ExampleBrowser>)
|
||||
ADD_CUSTOM_COMMAND(TARGET App_ExampleBrowser POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${BULLET2_TBB_INCLUDE_DIR}/../bin/${TBB_VC_ARCH}/${TBB_VC_VER}/tbbmalloc.dll"
|
||||
$<TARGET_FILE_DIR:App_ExampleBrowser>)
|
||||
ENDIF (BULLET2_MULTITHREADED_TBB_DEMO AND WIN32)
|
||||
|
||||
|
||||
IF (INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES)
|
||||
SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES DEBUG_POSTFIX "_Debug")
|
||||
SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES MINSIZEREL_POSTFIX "_MinsizeRel")
|
||||
SET_TARGET_PROPERTIES(App_ExampleBrowser PROPERTIES RELWITHDEBINFO_POSTFIX "_RelWithDebugInfo")
|
||||
ENDIF(INTERNAL_ADD_POSTFIX_EXECUTABLE_NAMES)
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "../RenderingExamples/TinyRendererSetup.h"
|
||||
#include "../RenderingExamples/DynamicTexturedCubeDemo.h"
|
||||
#include "../ForkLift/ForkLiftDemo.h"
|
||||
#include "../MultiThreadedDemo/MultiThreadedDemo.h"
|
||||
#include "../BasicDemo/BasicExample.h"
|
||||
#include "../Planar2D/Planar2D.h"
|
||||
#include "../Benchmarks/BenchmarkDemo.h"
|
||||
@@ -269,6 +270,7 @@ static ExampleEntry gDefaultExamples[]=
|
||||
ExampleEntry(1,"Two Point Grasp","Grasp experiment with two point contact to test rolling friction", GripperGraspExampleCreateFunc, eTWO_POINT_GRASP),
|
||||
ExampleEntry(1,"One Motor Gripper Grasp","Grasp experiment with a gripper with one motor to test slider constraint for closed loop structure", GripperGraspExampleCreateFunc, eONE_MOTOR_GRASP),
|
||||
ExampleEntry(1,"Grasp Soft Body","Grasp soft body experiment", GripperGraspExampleCreateFunc, eGRASP_SOFT_BODY),
|
||||
ExampleEntry(1,"Softbody Multibody Coupling","Two way coupling between soft body and multibody experiment", GripperGraspExampleCreateFunc, eSOFTBODY_MULTIBODY_COUPLING),
|
||||
|
||||
|
||||
#ifdef ENABLE_LUA
|
||||
@@ -284,7 +286,13 @@ static ExampleEntry gDefaultExamples[]=
|
||||
ExampleEntry(1,"Fracture demo", "Create a basic custom implementation to model fracturing objects, based on a btCompoundShape. It explicitly propagates the collision impulses and breaks the rigid body into multiple rigid bodies. Press F to toggle fracture and glue mode.", FractureDemoCreateFunc),
|
||||
|
||||
ExampleEntry(1,"Planar 2D","Show the use of 2D collision shapes and rigid body simulation. The collision shape is wrapped into a btConvex2dShape. The rigid bodies are restricted in a plane using the 'setAngularFactor' and 'setLinearFactor' API call.",Planar2DCreateFunc),
|
||||
|
||||
#if BT_USE_OPENMP || BT_USE_TBB || BT_USE_PPL
|
||||
// only enable MultiThreaded demo if a task scheduler is available
|
||||
ExampleEntry( 1, "Multithreaded Demo",
|
||||
"Stacks of boxes that do not sleep. Good for testing performance with large numbers of bodies and contacts. Sliders can be used to change the number of stacks (restart needed after each change)."
|
||||
,
|
||||
MultiThreadedDemoCreateFunc ),
|
||||
#endif
|
||||
|
||||
|
||||
ExampleEntry(0,"Rendering"),
|
||||
|
||||
@@ -782,7 +782,7 @@ GL_ShapeDrawer::~GL_ShapeDrawer()
|
||||
}
|
||||
}
|
||||
|
||||
void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWorld, int pass)
|
||||
void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWorld, int pass, int cameraUpAxis)
|
||||
{
|
||||
|
||||
btAssert(dynamicsWorld);
|
||||
@@ -849,7 +849,12 @@ void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWo
|
||||
//if (!(getDebugMode()& btIDebugDraw::DBG_DrawWireframe))
|
||||
int debugMode = 0;//getDebugMode()
|
||||
//btVector3 m_sundirection(-1,-1,-1);
|
||||
|
||||
btVector3 m_sundirection(btVector3(1,-2,1)*1000);
|
||||
if (cameraUpAxis==2)
|
||||
{
|
||||
m_sundirection = btVector3(1,1,-2)*1000;
|
||||
}
|
||||
|
||||
switch(pass)
|
||||
{
|
||||
@@ -861,9 +866,12 @@ void GL_ShapeDrawer::drawSceneInternal(const btDiscreteDynamicsWorld* dynamicsWo
|
||||
|
||||
}
|
||||
|
||||
void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, bool useShadows)
|
||||
//this GL_ShapeDrawer will be removed, in the meanwhile directly access this global 'useShadoMaps'
|
||||
extern bool useShadowMap;
|
||||
void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, bool useShadows1, int cameraUpAxis)
|
||||
{
|
||||
|
||||
bool useShadows = useShadowMap;
|
||||
GLfloat light_ambient[] = { btScalar(0.2), btScalar(0.2), btScalar(0.2), btScalar(1.0) };
|
||||
GLfloat light_diffuse[] = { btScalar(1.0), btScalar(1.0), btScalar(1.0), btScalar(1.0) };
|
||||
GLfloat light_specular[] = { btScalar(1.0), btScalar(1.0), btScalar(1.0), btScalar(1.0 )};
|
||||
@@ -897,7 +905,7 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo
|
||||
{
|
||||
glClear(GL_STENCIL_BUFFER_BIT);
|
||||
glEnable(GL_CULL_FACE);
|
||||
drawSceneInternal(dynamicsWorld,0);
|
||||
drawSceneInternal(dynamicsWorld,0, cameraUpAxis);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
glDepthMask(GL_FALSE);
|
||||
@@ -907,10 +915,10 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo
|
||||
glStencilFunc(GL_ALWAYS,1,0xFFFFFFFFL);
|
||||
glFrontFace(GL_CCW);
|
||||
glStencilOp(GL_KEEP,GL_KEEP,GL_INCR);
|
||||
drawSceneInternal(dynamicsWorld,1);
|
||||
drawSceneInternal(dynamicsWorld,1,cameraUpAxis);
|
||||
glFrontFace(GL_CW);
|
||||
glStencilOp(GL_KEEP,GL_KEEP,GL_DECR);
|
||||
drawSceneInternal(dynamicsWorld,1);
|
||||
drawSceneInternal(dynamicsWorld,1,cameraUpAxis);
|
||||
glFrontFace(GL_CCW);
|
||||
|
||||
glPolygonMode(GL_FRONT,GL_FILL);
|
||||
@@ -929,7 +937,7 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo
|
||||
glStencilFunc( GL_NOTEQUAL, 0, 0xFFFFFFFFL );
|
||||
glStencilOp( GL_KEEP, GL_KEEP, GL_KEEP );
|
||||
glDisable(GL_LIGHTING);
|
||||
drawSceneInternal(dynamicsWorld,2);
|
||||
drawSceneInternal(dynamicsWorld,2,cameraUpAxis);
|
||||
glEnable(GL_LIGHTING);
|
||||
glDepthFunc(GL_LESS);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
@@ -938,6 +946,6 @@ void GL_ShapeDrawer::drawScene(const btDiscreteDynamicsWorld* dynamicsWorld, boo
|
||||
else
|
||||
{
|
||||
glDisable(GL_CULL_FACE);
|
||||
drawSceneInternal(dynamicsWorld,0);
|
||||
drawSceneInternal(dynamicsWorld,0,cameraUpAxis);
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,7 @@ protected:
|
||||
|
||||
ShapeCache* cache(btConvexShape*);
|
||||
|
||||
virtual void drawSceneInternal(const btDiscreteDynamicsWorld* world, int pass);
|
||||
virtual void drawSceneInternal(const btDiscreteDynamicsWorld* world, int pass, int cameraUpAxis);
|
||||
|
||||
public:
|
||||
GL_ShapeDrawer();
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
|
||||
|
||||
|
||||
virtual void drawScene(const btDiscreteDynamicsWorld* world, bool useShadows);
|
||||
virtual void drawScene(const btDiscreteDynamicsWorld* world, bool useShadows, int cameraUpAxis);
|
||||
|
||||
///drawOpenGL might allocate temporary memoty, stores pointer in shape userpointer
|
||||
virtual void drawOpenGL(btScalar* m, const btCollisionShape* shape, const btVector3& color,int debugMode,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax);
|
||||
|
||||
@@ -28,18 +28,20 @@ template<typename T>
|
||||
struct MySliderEventHandler : public Gwen::Event::Handler
|
||||
{
|
||||
SliderParamChangedCallback m_callback;
|
||||
void* m_userPointer;
|
||||
Gwen::Controls::TextBox* m_label;
|
||||
Gwen::Controls::Slider* m_pSlider;
|
||||
char m_variableName[1024];
|
||||
T* m_targetValue;
|
||||
bool m_showValue;
|
||||
|
||||
MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target,SliderParamChangedCallback callback)
|
||||
MySliderEventHandler(const char* varName, Gwen::Controls::TextBox* label, Gwen::Controls::Slider* pSlider,T* target, SliderParamChangedCallback callback, void* userPtr)
|
||||
:m_label(label),
|
||||
m_pSlider(pSlider),
|
||||
m_targetValue(target),
|
||||
m_showValue(true),
|
||||
m_callback(callback)
|
||||
m_callback(callback),
|
||||
m_userPointer(userPtr)
|
||||
{
|
||||
memcpy(m_variableName,varName,strlen(varName)+1);
|
||||
}
|
||||
@@ -55,7 +57,7 @@ struct MySliderEventHandler : public Gwen::Event::Handler
|
||||
|
||||
if (m_callback)
|
||||
{
|
||||
(*m_callback)(v);
|
||||
(*m_callback)(v, m_userPointer);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -223,12 +225,20 @@ void GwenParameterInterface::registerSliderFloatParameter(SliderParams& params)
|
||||
pSlider->SetPos( 10, m_gwenInternalData->m_curYposition );
|
||||
pSlider->SetSize( 200, 20 );
|
||||
pSlider->SetRange( params.m_minVal, params.m_maxVal);
|
||||
pSlider->SetNotchCount(16);//float(params.m_maxVal-params.m_minVal)/100.f);
|
||||
pSlider->SetClampToNotches( params.m_clampToNotches );
|
||||
if (params.m_clampToIntegers)
|
||||
{
|
||||
pSlider->SetNotchCount( int( params.m_maxVal - params.m_minVal ) );
|
||||
pSlider->SetClampToNotches( params.m_clampToNotches );
|
||||
}
|
||||
else
|
||||
{
|
||||
pSlider->SetNotchCount( 16 );//float(params.m_maxVal-params.m_minVal)/100.f);
|
||||
pSlider->SetClampToNotches( params.m_clampToNotches );
|
||||
}
|
||||
pSlider->SetValue( *params.m_paramValuePointer);//dimensions[i] );
|
||||
char labelName[1024];
|
||||
sprintf(labelName,"%s",params.m_name);//axisNames[0]);
|
||||
MySliderEventHandler<btScalar>* handler = new MySliderEventHandler<btScalar>(labelName,label,pSlider,params.m_paramValuePointer,params.m_callback);
|
||||
MySliderEventHandler<btScalar>* handler = new MySliderEventHandler<btScalar>(labelName,label,pSlider,params.m_paramValuePointer,params.m_callback, params.m_userPointer);
|
||||
handler->m_showValue = params.m_showValues;
|
||||
m_paramInternalData->m_sliderEventHandlers.push_back(handler);
|
||||
|
||||
|
||||
@@ -134,9 +134,9 @@ int gSharedMemoryKey=-1;
|
||||
|
||||
int gPreferredOpenCLDeviceIndex=-1;
|
||||
int gPreferredOpenCLPlatformIndex=-1;
|
||||
int gGpuArraySizeX=15;
|
||||
int gGpuArraySizeY=15;
|
||||
int gGpuArraySizeZ=15;
|
||||
int gGpuArraySizeX=45;
|
||||
int gGpuArraySizeY=55;
|
||||
int gGpuArraySizeZ=45;
|
||||
|
||||
//#include <float.h>
|
||||
//unsigned int fp_control_state = _controlfp(_EM_INEXACT, _MCW_EM);
|
||||
@@ -1167,7 +1167,7 @@ void OpenGLExampleBrowser::update(float deltaTime)
|
||||
}
|
||||
BT_PROFILE("Render Scene");
|
||||
sCurrentDemo->renderScene();
|
||||
}
|
||||
} else
|
||||
{
|
||||
B3_PROFILE("physicsDebugDraw");
|
||||
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
|
||||
|
||||
@@ -338,7 +338,7 @@ void OpenGLGuiHelper::render(const btDiscreteDynamicsWorld* rbWorld)
|
||||
if (m_data->m_gl2ShapeDrawer && rbWorld)
|
||||
{
|
||||
m_data->m_gl2ShapeDrawer->enableTexture(true);
|
||||
m_data->m_gl2ShapeDrawer->drawScene(rbWorld,true);
|
||||
m_data->m_gl2ShapeDrawer->drawScene(rbWorld,true, m_data->m_glApp->getUpAxis());
|
||||
}
|
||||
}
|
||||
void OpenGLGuiHelper::createPhysicsDebugDrawer(btDiscreteDynamicsWorld* rbWorld)
|
||||
|
||||
@@ -55,9 +55,27 @@ struct OpenGLGuiHelper : public GUIHelperInterface
|
||||
|
||||
virtual void drawText3D( const char* txt, float posX, float posY, float posZ, float size);
|
||||
|
||||
virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual void removeUserDebugItem( int debugItemUniqueId)
|
||||
{
|
||||
}
|
||||
virtual void removeAllUserDebugItems( )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void renderInternalGl2(int pass, const btDiscreteDynamicsWorld* dynamicsWorld);
|
||||
|
||||
void setVRMode(bool vrMode);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //OPENGL_GUI_HELPER_H
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "../Importers/ImportURDFDemo/ImportURDFSetup.h"
|
||||
#include "../Importers/ImportSDFDemo/ImportSDFSetup.h"
|
||||
#include "../Importers/ImportSTLDemo/ImportSTLSetup.h"
|
||||
#include "../Importers/ImportBullet/SerializeSetup.h"
|
||||
|
||||
#include "LinearMath/btAlignedAllocator.h"
|
||||
|
||||
|
||||
@@ -34,6 +36,8 @@ int main(int argc, char* argv[])
|
||||
exampleBrowser->registerFileImporter(".sdf", ImportSDFCreateFunc);
|
||||
exampleBrowser->registerFileImporter(".obj", ImportObjCreateFunc);
|
||||
exampleBrowser->registerFileImporter(".stl", ImportSTLCreateFunc);
|
||||
exampleBrowser->registerFileImporter(".bullet", SerializeBulletCreateFunc);
|
||||
|
||||
|
||||
clock.reset();
|
||||
if (init)
|
||||
|
||||
@@ -63,6 +63,14 @@ project "App_BulletExampleBrowser"
|
||||
"../SharedMemory/PhysicsServer.cpp",
|
||||
"../SharedMemory/PhysicsServerSharedMemory.cpp",
|
||||
"../SharedMemory/PhysicsClientSharedMemory.cpp",
|
||||
"../SharedMemory/PhysicsClientSharedMemory_C_API.cpp",
|
||||
"../SharedMemory/PhysicsClientSharedMemory_C_API.h",
|
||||
"../SharedMemory/PhysicsClientSharedMemory2.cpp",
|
||||
"../SharedMemory/PhysicsClientSharedMemory2.h",
|
||||
"../SharedMemory/PhysicsClientSharedMemory2_C_API.cpp",
|
||||
"../SharedMemory/PhysicsClientSharedMemory2_C_API.h",
|
||||
"../SharedMemory/SharedMemoryCommandProcessor.cpp",
|
||||
"../SharedMemory/SharedMemoryCommandProcessor.h",
|
||||
"../SharedMemory/SharedMemoryInProcessPhysicsC_API.cpp",
|
||||
"../SharedMemory/PhysicsClient.cpp",
|
||||
"../SharedMemory/PosixSharedMemory.cpp",
|
||||
@@ -95,7 +103,8 @@ project "App_BulletExampleBrowser"
|
||||
"../RoboticsLearning/*",
|
||||
"../Collision/Internal/*",
|
||||
"../Benchmarks/*",
|
||||
"../CommonInterfaces/*",
|
||||
"../MultiThreadedDemo/*",
|
||||
"../CommonInterfaces/*.h",
|
||||
"../ForkLift/ForkLiftDemo.*",
|
||||
"../Importers/**",
|
||||
"../../Extras/Serialize/BulletWorldImporter/*",
|
||||
|
||||
@@ -69,19 +69,19 @@ struct InclinedPlaneExample : public CommonRigidBodyBase
|
||||
|
||||
};
|
||||
|
||||
void onBoxFrictionChanged(float friction);
|
||||
void onBoxFrictionChanged(float friction, void* userPtr);
|
||||
|
||||
void onBoxRestitutionChanged(float restitution);
|
||||
void onBoxRestitutionChanged(float restitution, void* userPtr);
|
||||
|
||||
void onSphereFrictionChanged(float friction);
|
||||
void onSphereFrictionChanged(float friction, void* userPtr);
|
||||
|
||||
void onSphereRestitutionChanged(float restitution);
|
||||
void onSphereRestitutionChanged(float restitution, void* userPtr);
|
||||
|
||||
void onRampInclinationChanged(float inclination);
|
||||
void onRampInclinationChanged(float inclination, void* userPtr);
|
||||
|
||||
void onRampFrictionChanged(float friction);
|
||||
void onRampFrictionChanged(float friction, void* userPtr);
|
||||
|
||||
void onRampRestitutionChanged(float restitution);
|
||||
void onRampRestitutionChanged(float restitution, void* userPtr);
|
||||
|
||||
void InclinedPlaneExample::initPhysics()
|
||||
{
|
||||
@@ -306,35 +306,35 @@ bool InclinedPlaneExample::keyboardCallback(int key, int state) {
|
||||
|
||||
|
||||
// GUI parameter modifiers
|
||||
void onBoxFrictionChanged(float friction){
|
||||
void onBoxFrictionChanged(float friction, void*){
|
||||
if(gBox){
|
||||
gBox->setFriction(friction);
|
||||
// b3Printf("Friction of box changed to %f",friction );
|
||||
}
|
||||
}
|
||||
|
||||
void onBoxRestitutionChanged(float restitution){
|
||||
void onBoxRestitutionChanged(float restitution, void*){
|
||||
if(gBox){
|
||||
gBox->setRestitution(restitution);
|
||||
//b3Printf("Restitution of box changed to %f",restitution);
|
||||
}
|
||||
}
|
||||
|
||||
void onSphereFrictionChanged(float friction){
|
||||
void onSphereFrictionChanged(float friction, void*){
|
||||
if(gSphere){
|
||||
gSphere->setFriction(friction);
|
||||
//b3Printf("Friction of sphere changed to %f",friction );
|
||||
}
|
||||
}
|
||||
|
||||
void onSphereRestitutionChanged(float restitution){
|
||||
void onSphereRestitutionChanged(float restitution, void*){
|
||||
if(gSphere){
|
||||
gSphere->setRestitution(restitution);
|
||||
//b3Printf("Restitution of sphere changed to %f",restitution);
|
||||
}
|
||||
}
|
||||
|
||||
void onRampInclinationChanged(float inclination){
|
||||
void onRampInclinationChanged(float inclination, void*){
|
||||
if(ramp){
|
||||
btTransform startTransform;
|
||||
startTransform.setIdentity();
|
||||
@@ -351,14 +351,14 @@ void onRampInclinationChanged(float inclination){
|
||||
}
|
||||
}
|
||||
|
||||
void onRampFrictionChanged(float friction){
|
||||
void onRampFrictionChanged(float friction, void*){
|
||||
if(ramp){
|
||||
ramp->setFriction(friction);
|
||||
//b3Printf("Friction of ramp changed to %f \n",friction );
|
||||
}
|
||||
}
|
||||
|
||||
void onRampRestitutionChanged(float restitution){
|
||||
void onRampRestitutionChanged(float restitution, void*){
|
||||
if(ramp){
|
||||
ramp->setRestitution(restitution);
|
||||
//b3Printf("Restitution of ramp changed to %f \n",restitution);
|
||||
|
||||
@@ -71,11 +71,9 @@ struct MultiPendulumExample: public CommonRigidBodyBase {
|
||||
|
||||
static MultiPendulumExample* mex = NULL; // Handle to the example to access it via functions. Do not use this in your simulation!
|
||||
|
||||
void onMultiPendulaLengthChanged(float pendulaLength); // Change the pendula length
|
||||
void onMultiPendulaLengthChanged(float pendulaLength, void*); // Change the pendula length
|
||||
|
||||
void onMultiPendulaRestitutionChanged(float pendulaRestitution); // change the pendula restitution
|
||||
|
||||
void floorMSliderValue(float notUsed); // floor the slider values which should be integers
|
||||
void onMultiPendulaRestitutionChanged(float pendulaRestitution, void*); // change the pendula restitution
|
||||
|
||||
void applyMForceWithForceScalar(float forceScalar);
|
||||
|
||||
@@ -85,8 +83,7 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene
|
||||
SliderParams slider("Number of Pendula", &gPendulaQty);
|
||||
slider.m_minVal = 1;
|
||||
slider.m_maxVal = 50;
|
||||
slider.m_callback = floorMSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -95,8 +92,7 @@ void MultiPendulumExample::initPhysics() { // Setup your physics scene
|
||||
SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula);
|
||||
slider.m_minVal = 0;
|
||||
slider.m_maxVal = 49;
|
||||
slider.m_callback = floorMSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -397,7 +393,7 @@ void MultiPendulumExample::applyPendulumForce(btScalar pendulumForce){
|
||||
|
||||
// GUI parameter modifiers
|
||||
|
||||
void onMultiPendulaLengthChanged(float pendulaLength) { // Change the pendula length
|
||||
void onMultiPendulaLengthChanged(float pendulaLength, void*) { // Change the pendula length
|
||||
if (mex){
|
||||
mex->changePendulaLength(pendulaLength);
|
||||
}
|
||||
@@ -405,18 +401,13 @@ void onMultiPendulaLengthChanged(float pendulaLength) { // Change the pendula le
|
||||
|
||||
}
|
||||
|
||||
void onMultiPendulaRestitutionChanged(float pendulaRestitution) { // change the pendula restitution
|
||||
void onMultiPendulaRestitutionChanged(float pendulaRestitution, void*) { // change the pendula restitution
|
||||
if (mex){
|
||||
mex->changePendulaRestitution(pendulaRestitution);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void floorMSliderValue(float notUsed) { // floor the slider values which should be integers
|
||||
gPendulaQty = floor(gPendulaQty);
|
||||
gDisplacedPendula = floor(gDisplacedPendula);
|
||||
}
|
||||
|
||||
void applyMForceWithForceScalar(float forceScalar) {
|
||||
if(mex){
|
||||
btScalar appliedForce = forceScalar * gDisplacementForce;
|
||||
|
||||
@@ -71,11 +71,9 @@ struct NewtonsCradleExample: public CommonRigidBodyBase {
|
||||
|
||||
static NewtonsCradleExample* nex = NULL;
|
||||
|
||||
void onPendulaLengthChanged(float pendulaLength); // Change the pendula length
|
||||
void onPendulaLengthChanged(float pendulaLength, void* userPtr); // Change the pendula length
|
||||
|
||||
void onPendulaRestitutionChanged(float pendulaRestitution); // change the pendula restitution
|
||||
|
||||
void floorSliderValue(float notUsed); // floor the slider values which should be integers
|
||||
void onPendulaRestitutionChanged(float pendulaRestitution, void* userPtr); // change the pendula restitution
|
||||
|
||||
void applyForceWithForceScalar(float forceScalar);
|
||||
|
||||
@@ -85,8 +83,7 @@ void NewtonsCradleExample::initPhysics() {
|
||||
SliderParams slider("Number of Pendula", &gPendulaQty);
|
||||
slider.m_minVal = 1;
|
||||
slider.m_maxVal = 50;
|
||||
slider.m_callback = floorSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -95,8 +92,7 @@ void NewtonsCradleExample::initPhysics() {
|
||||
SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula);
|
||||
slider.m_minVal = 0;
|
||||
slider.m_maxVal = 49;
|
||||
slider.m_callback = floorSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -343,25 +339,19 @@ void NewtonsCradleExample::applyPendulumForce(btScalar pendulumForce){
|
||||
|
||||
// GUI parameter modifiers
|
||||
|
||||
void onPendulaLengthChanged(float pendulaLength) {
|
||||
void onPendulaLengthChanged(float pendulaLength, void*) {
|
||||
if (nex){
|
||||
nex->changePendulaLength(pendulaLength);
|
||||
//b3Printf("Pendula length changed to %f \n",sliderValue );
|
||||
}
|
||||
}
|
||||
|
||||
void onPendulaRestitutionChanged(float pendulaRestitution) {
|
||||
void onPendulaRestitutionChanged(float pendulaRestitution, void*) {
|
||||
if (nex){
|
||||
nex->changePendulaRestitution(pendulaRestitution);
|
||||
}
|
||||
}
|
||||
|
||||
void floorSliderValue(float notUsed) {
|
||||
gPendulaQty = floor(gPendulaQty);
|
||||
gDisplacedPendula = floor(gDisplacedPendula);
|
||||
|
||||
}
|
||||
|
||||
void applyForceWithForceScalar(float forceScalar) {
|
||||
if(nex){
|
||||
btScalar appliedForce = forceScalar * gDisplacementForce;
|
||||
|
||||
@@ -105,9 +105,7 @@ struct NewtonsRopeCradleExample : public CommonRigidBodyBase {
|
||||
|
||||
static NewtonsRopeCradleExample* nex = NULL;
|
||||
|
||||
void onRopePendulaRestitutionChanged(float pendulaRestitution);
|
||||
|
||||
void floorRSliderValue(float notUsed);
|
||||
void onRopePendulaRestitutionChanged(float pendulaRestitution, void*);
|
||||
|
||||
void applyRForceWithForceScalar(float forceScalar);
|
||||
|
||||
@@ -118,8 +116,7 @@ void NewtonsRopeCradleExample::initPhysics()
|
||||
SliderParams slider("Number of Pendula", &gPendulaQty);
|
||||
slider.m_minVal = 1;
|
||||
slider.m_maxVal = 50;
|
||||
slider.m_callback = floorRSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -128,8 +125,7 @@ void NewtonsRopeCradleExample::initPhysics()
|
||||
SliderParams slider("Number of Displaced Pendula", &gDisplacedPendula);
|
||||
slider.m_minVal = 0;
|
||||
slider.m_maxVal = 49;
|
||||
slider.m_callback = floorRSliderValue; // hack to get integer values
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -148,8 +144,7 @@ void NewtonsRopeCradleExample::initPhysics()
|
||||
SliderParams slider("Rope Resolution", &gRopeResolution);
|
||||
slider.m_minVal = 1;
|
||||
slider.m_maxVal = 20;
|
||||
slider.m_clampToNotches = false;
|
||||
slider.m_callback = floorRSliderValue;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(
|
||||
slider);
|
||||
}
|
||||
@@ -357,18 +352,12 @@ void NewtonsRopeCradleExample::applyPendulumForce(btScalar pendulumForce){
|
||||
|
||||
// GUI parameter modifiers
|
||||
|
||||
void onRopePendulaRestitutionChanged(float pendulaRestitution) {
|
||||
void onRopePendulaRestitutionChanged(float pendulaRestitution, void*) {
|
||||
if (nex){
|
||||
nex->changePendulaRestitution(pendulaRestitution);
|
||||
}
|
||||
}
|
||||
|
||||
void floorRSliderValue(float notUsed) {
|
||||
gPendulaQty = floor(gPendulaQty);
|
||||
gDisplacedPendula = floor(gDisplacedPendula);
|
||||
gRopeResolution = floor(gRopeResolution);
|
||||
}
|
||||
|
||||
void applyRForceWithForceScalar(float forceScalar) {
|
||||
if(nex){
|
||||
btScalar appliedForce = forceScalar * gDisplacementForce;
|
||||
|
||||
@@ -17,6 +17,7 @@ language "C++"
|
||||
|
||||
files {
|
||||
"RigidBodyFromObj.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"**.h",
|
||||
"../StandaloneMain/main_console_single_example.cpp",
|
||||
"../Utils/b3ResourcePath.cpp",
|
||||
@@ -68,6 +69,7 @@ files {
|
||||
"RigidBodyFromObj.cpp",
|
||||
"*.h",
|
||||
"../StandaloneMain/main_opengl_single_example.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../ExampleBrowser/OpenGLGuiHelper.cpp",
|
||||
"../ExampleBrowser/GL_ShapeDrawer.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
@@ -132,6 +134,7 @@ files {
|
||||
"../ExampleBrowser/OpenGLGuiHelper.cpp",
|
||||
"../ExampleBrowser/GL_ShapeDrawer.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../TinyRenderer/geometry.cpp",
|
||||
"../TinyRenderer/model.cpp",
|
||||
"../TinyRenderer/tgaimage.cpp",
|
||||
@@ -193,6 +196,7 @@ files {
|
||||
"../StandaloneMain/main_tinyrenderer_single_example.cpp",
|
||||
"../OpenGLWindow/SimpleCamera.cpp",
|
||||
"../ExampleBrowser/CollisionShape2TriangleMesh.cpp",
|
||||
"../CommonInterfaces/*",
|
||||
"../TinyRenderer/geometry.cpp",
|
||||
"../TinyRenderer/model.cpp",
|
||||
"../TinyRenderer/tgaimage.cpp",
|
||||
|
||||
236
examples/Importers/ImportMJCFDemo/ImportMJCFSetup.cpp
Normal file
236
examples/Importers/ImportMJCFDemo/ImportMJCFSetup.cpp
Normal file
@@ -0,0 +1,236 @@
|
||||
|
||||
#include "ImportMJCFSetup.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btGeneric6DofSpring2Constraint.h"
|
||||
//#define TEST_MULTIBODY_SERIALIZATION 1
|
||||
|
||||
#include "BulletDynamics/Featherstone/btMultiBodyLinkCollider.h"
|
||||
#include "Bullet3Common/b3FileUtils.h"
|
||||
|
||||
#include "BulletDynamics/Featherstone/btMultiBodyJointMotor.h"
|
||||
#include "BulletDynamics/Featherstone/btMultiBodyDynamicsWorld.h"
|
||||
#include "../CommonInterfaces/CommonParameterInterface.h"
|
||||
#include "../../Utils/b3ResourcePath.h"
|
||||
|
||||
#include "../CommonInterfaces/CommonMultiBodyBase.h"
|
||||
|
||||
#include "../ImportURDFDemo/MyMultiBodyCreator.h"
|
||||
|
||||
class ImportMJCFSetup : public CommonMultiBodyBase
|
||||
{
|
||||
char m_fileName[1024];
|
||||
|
||||
struct ImportMJCFInternalData* m_data;
|
||||
bool m_useMultiBody;
|
||||
btAlignedObjectArray<std::string* > m_nameMemory;
|
||||
btScalar m_grav;
|
||||
int m_upAxis;
|
||||
public:
|
||||
ImportMJCFSetup(struct GUIHelperInterface* helper, int option, const char* fileName);
|
||||
virtual ~ImportMJCFSetup();
|
||||
|
||||
virtual void initPhysics();
|
||||
virtual void stepSimulation(float deltaTime);
|
||||
|
||||
void setFileName(const char* mjcfFileName);
|
||||
|
||||
virtual void resetCamera()
|
||||
{
|
||||
float dist = 3.5;
|
||||
float pitch = -136;
|
||||
float yaw = 28;
|
||||
float targetPos[3]={0.47,0,-0.64};
|
||||
m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static btAlignedObjectArray<std::string> gMCFJFileNameArray;
|
||||
|
||||
|
||||
#define MAX_NUM_MOTORS 1024
|
||||
|
||||
struct ImportMJCFInternalData
|
||||
{
|
||||
ImportMJCFInternalData()
|
||||
:m_numMotors(0),
|
||||
m_mb(0)
|
||||
{
|
||||
for (int i=0;i<MAX_NUM_MOTORS;i++)
|
||||
{
|
||||
m_jointMotors[i] = 0;
|
||||
m_generic6DofJointMotors[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
btScalar m_motorTargetVelocities[MAX_NUM_MOTORS];
|
||||
btMultiBodyJointMotor* m_jointMotors [MAX_NUM_MOTORS];
|
||||
btGeneric6DofSpring2Constraint* m_generic6DofJointMotors [MAX_NUM_MOTORS];
|
||||
int m_numMotors;
|
||||
btMultiBody* m_mb;
|
||||
btRigidBody* m_rb;
|
||||
|
||||
};
|
||||
|
||||
|
||||
ImportMJCFSetup::ImportMJCFSetup(struct GUIHelperInterface* helper, int option, const char* fileName)
|
||||
:CommonMultiBodyBase(helper),
|
||||
m_grav(0),
|
||||
m_upAxis(2)
|
||||
{
|
||||
m_data = new ImportMJCFInternalData;
|
||||
|
||||
if (option==1)
|
||||
{
|
||||
m_useMultiBody = true;
|
||||
} else
|
||||
{
|
||||
m_useMultiBody = false;
|
||||
}
|
||||
|
||||
static int count = 0;
|
||||
if (fileName)
|
||||
{
|
||||
setFileName(fileName);
|
||||
} else
|
||||
{
|
||||
gMCFJFileNameArray.clear();
|
||||
|
||||
|
||||
|
||||
//load additional MJCF file names from file
|
||||
|
||||
FILE* f = fopen("mjcf_files.txt","r");
|
||||
if (f)
|
||||
{
|
||||
int result;
|
||||
//warning: we don't avoid string buffer overflow in this basic example in fscanf
|
||||
char fileName[1024];
|
||||
do
|
||||
{
|
||||
result = fscanf(f,"%s",fileName);
|
||||
b3Printf("mjcf_files.txt entry %s",fileName);
|
||||
if (result==1)
|
||||
{
|
||||
gMCFJFileNameArray.push_back(fileName);
|
||||
}
|
||||
} while (result==1);
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if (gMCFJFileNameArray.size()==0)
|
||||
{
|
||||
gMCFJFileNameArray.push_back("quadruped/quadruped.mjcf");
|
||||
|
||||
}
|
||||
|
||||
int numFileNames = gMCFJFileNameArray.size();
|
||||
|
||||
if (count>=numFileNames)
|
||||
{
|
||||
count=0;
|
||||
}
|
||||
sprintf(m_fileName,"%s",gMCFJFileNameArray[count++].c_str());
|
||||
}
|
||||
}
|
||||
|
||||
ImportMJCFSetup::~ImportMJCFSetup()
|
||||
{
|
||||
for (int i=0;i<m_nameMemory.size();i++)
|
||||
{
|
||||
delete m_nameMemory[i];
|
||||
}
|
||||
m_nameMemory.clear();
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
static btVector4 colors[4] =
|
||||
{
|
||||
btVector4(1,0,0,1),
|
||||
btVector4(0,1,0,1),
|
||||
btVector4(0,1,1,1),
|
||||
btVector4(1,1,0,1),
|
||||
};
|
||||
|
||||
|
||||
static btVector3 selectColor()
|
||||
{
|
||||
|
||||
static int curColor = 0;
|
||||
btVector4 color = colors[curColor];
|
||||
curColor++;
|
||||
curColor&=3;
|
||||
return color;
|
||||
}
|
||||
|
||||
void ImportMJCFSetup::setFileName(const char* mjcfFileName)
|
||||
{
|
||||
memcpy(m_fileName,mjcfFileName,strlen(mjcfFileName)+1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ImportMJCFSetup::initPhysics()
|
||||
{
|
||||
|
||||
|
||||
m_guiHelper->setUpAxis(m_upAxis);
|
||||
|
||||
this->createEmptyDynamicsWorld();
|
||||
//m_dynamicsWorld->getSolverInfo().m_numIterations = 100;
|
||||
m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld);
|
||||
m_dynamicsWorld->getDebugDrawer()->setDebugMode(
|
||||
btIDebugDraw::DBG_DrawConstraints
|
||||
+btIDebugDraw::DBG_DrawContactPoints
|
||||
+btIDebugDraw::DBG_DrawAabb
|
||||
);//+btIDebugDraw::DBG_DrawConstraintLimits);
|
||||
|
||||
|
||||
if (m_guiHelper->getParameterInterface())
|
||||
{
|
||||
SliderParams slider("Gravity", &m_grav);
|
||||
slider.m_minVal = -10;
|
||||
slider.m_maxVal = 10;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ImportMJCFSetup::stepSimulation(float deltaTime)
|
||||
{
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
btVector3 gravity(0, 0, 0);
|
||||
gravity[m_upAxis] = m_grav;
|
||||
m_dynamicsWorld->setGravity(gravity);
|
||||
|
||||
for (int i=0;i<m_data->m_numMotors;i++)
|
||||
{
|
||||
if (m_data->m_jointMotors[i])
|
||||
{
|
||||
m_data->m_jointMotors[i]->setVelocityTarget(m_data->m_motorTargetVelocities[i]);
|
||||
}
|
||||
if (m_data->m_generic6DofJointMotors[i])
|
||||
{
|
||||
GenericConstraintUserInfo* jointInfo = (GenericConstraintUserInfo*)m_data->m_generic6DofJointMotors[i]->getUserConstraintPtr();
|
||||
m_data->m_generic6DofJointMotors[i]->setTargetVelocity(jointInfo->m_jointAxisIndex,m_data->m_motorTargetVelocities[i]);
|
||||
//jointInfo->
|
||||
}
|
||||
}
|
||||
|
||||
//the maximal coordinates/iterative MLCP solver requires a smallish timestep to converge
|
||||
m_dynamicsWorld->stepSimulation(deltaTime,10,1./240.);
|
||||
}
|
||||
}
|
||||
|
||||
class CommonExampleInterface* ImportMJCFCreateFunc(struct CommonExampleOptions& options)
|
||||
{
|
||||
|
||||
return new ImportMJCFSetup(options.m_guiHelper, options.m_option,options.m_fileName);
|
||||
}
|
||||
8
examples/Importers/ImportMJCFDemo/ImportMJCFSetup.h
Normal file
8
examples/Importers/ImportMJCFDemo/ImportMJCFSetup.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef IMPORT_MJCF_SETUP_H
|
||||
#define IMPORT_MJCF_SETUP_H
|
||||
|
||||
|
||||
class CommonExampleInterface* ImportMJCFCreateFunc(struct CommonExampleOptions& options);
|
||||
|
||||
|
||||
#endif //IMPORT_MJCF_SETUP_H
|
||||
@@ -135,7 +135,7 @@ ImportUrdfSetup::ImportUrdfSetup(struct GUIHelperInterface* helper, int option,
|
||||
|
||||
if (gFileNameArray.size()==0)
|
||||
{
|
||||
gFileNameArray.push_back("r2d2.urdf");
|
||||
gFileNameArray.push_back("quadruped/quadruped.urdf");
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,34 @@ void InitURDF2BulletCache(const URDFImporterInterface& u2b, URDF2BulletCachedDat
|
||||
|
||||
}
|
||||
|
||||
void processContactParameters(const URDFLinkContactInfo& contactInfo, btCollisionObject* col)
|
||||
{
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_LATERAL_FRICTION) != 0)
|
||||
{
|
||||
col->setFriction(contactInfo.m_lateralFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_RESTITUTION) != 0)
|
||||
{
|
||||
col->setRestitution(contactInfo.m_restitution);
|
||||
}
|
||||
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_ROLLING_FRICTION) != 0)
|
||||
{
|
||||
col->setRollingFriction(contactInfo.m_rollingFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_SPINNING_FRICTION) != 0)
|
||||
{
|
||||
col->setSpinningFriction(contactInfo.m_spinningFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_STIFFNESS_DAMPING) != 0)
|
||||
{
|
||||
col->setContactStiffnessAndDamping(contactInfo.m_contactStiffness, contactInfo.m_contactDamping);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void ConvertURDF2BulletInternal(
|
||||
const URDFImporterInterface& u2b, MultiBodyCreationInterface& creation,
|
||||
URDF2BulletCachedData& cache, int urdfLinkIndex,
|
||||
@@ -258,11 +286,18 @@ void ConvertURDF2BulletInternal(
|
||||
|
||||
world1->addRigidBody(body);
|
||||
|
||||
|
||||
compoundShape->setUserIndex(graphicsIndex);
|
||||
|
||||
URDFLinkContactInfo contactInfo;
|
||||
u2b.getLinkContactInfo(urdfLinkIndex, contactInfo);
|
||||
|
||||
processContactParameters(contactInfo, body);
|
||||
creation.createRigidBodyGraphicsInstance(urdfLinkIndex, body, color, graphicsIndex);
|
||||
cache.registerRigidBody(urdfLinkIndex, body, inertialFrameInWorldSpace, mass, localInertiaDiagonal, compoundShape, localInertialFrame);
|
||||
|
||||
|
||||
|
||||
//untested: u2b.convertLinkVisualShapes2(urdfLinkIndex,pathPrefix,localInertialFrame,body);
|
||||
} else
|
||||
{
|
||||
@@ -413,22 +448,7 @@ void ConvertURDF2BulletInternal(
|
||||
URDFLinkContactInfo contactInfo;
|
||||
u2b.getLinkContactInfo(urdfLinkIndex,contactInfo);
|
||||
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_LATERAL_FRICTION)!=0)
|
||||
{
|
||||
col->setFriction(contactInfo.m_lateralFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_ROLLING_FRICTION)!=0)
|
||||
{
|
||||
col->setRollingFriction(contactInfo.m_rollingFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_SPINNING_FRICTION)!=0)
|
||||
{
|
||||
col->setSpinningFriction(contactInfo.m_spinningFriction);
|
||||
}
|
||||
if ((contactInfo.m_flags & URDF_CONTACT_HAS_STIFFNESS_DAMPING)!=0)
|
||||
{
|
||||
col->setContactStiffnessAndDamping(contactInfo.m_contactStiffness,contactInfo.m_contactDamping);
|
||||
}
|
||||
processContactParameters(contactInfo, col);
|
||||
|
||||
if (mbLinkIndex>=0) //???? double-check +/- 1
|
||||
{
|
||||
|
||||
@@ -22,6 +22,7 @@ enum URDF_LinkContactFlags
|
||||
URDF_CONTACT_HAS_STIFFNESS_DAMPING=16,
|
||||
URDF_CONTACT_HAS_ROLLING_FRICTION=32,
|
||||
URDF_CONTACT_HAS_SPINNING_FRICTION=64,
|
||||
URDF_CONTACT_HAS_RESTITUTION=128,
|
||||
|
||||
};
|
||||
|
||||
@@ -30,6 +31,7 @@ struct URDFLinkContactInfo
|
||||
btScalar m_lateralFriction;
|
||||
btScalar m_rollingFriction;
|
||||
btScalar m_spinningFriction;
|
||||
btScalar m_restitution;
|
||||
btScalar m_inertiaScaling;
|
||||
btScalar m_contactCfm;
|
||||
btScalar m_contactErp;
|
||||
@@ -42,6 +44,7 @@ struct URDFLinkContactInfo
|
||||
:m_lateralFriction(0.5),
|
||||
m_rollingFriction(0),
|
||||
m_spinningFriction(0),
|
||||
m_restitution(0),
|
||||
m_inertiaScaling(1),
|
||||
m_contactCfm(0),
|
||||
m_contactErp(0),
|
||||
|
||||
@@ -672,6 +672,31 @@ bool UrdfParser::parseLink(UrdfModel& model, UrdfLink& link, TiXmlElement *confi
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TiXmlElement *restitution_xml = ci->FirstChildElement("restitution");
|
||||
if (restitution_xml)
|
||||
{
|
||||
if (m_parseSDF)
|
||||
{
|
||||
link.m_contactInfo.m_restitution = urdfLexicalCast<double>(restitution_xml->GetText());
|
||||
link.m_contactInfo.m_flags |= URDF_CONTACT_HAS_RESTITUTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!restitution_xml->Attribute("value"))
|
||||
{
|
||||
logger->reportError("Link/contact: restitution element must have value attribute");
|
||||
return false;
|
||||
}
|
||||
|
||||
link.m_contactInfo.m_restitution = urdfLexicalCast<double>(restitution_xml->Attribute("value"));
|
||||
link.m_contactInfo.m_flags |= URDF_CONTACT_HAS_RESTITUTION;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
TiXmlElement *spinning_xml = ci->FirstChildElement("spinning_friction");
|
||||
if (spinning_xml)
|
||||
|
||||
868
examples/MultiThreadedDemo/CommonRigidBodyMTBase.cpp
Normal file
868
examples/MultiThreadedDemo/CommonRigidBodyMTBase.cpp
Normal file
@@ -0,0 +1,868 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
|
||||
class btCollisionShape;
|
||||
|
||||
#include "CommonRigidBodyMTBase.h"
|
||||
#include "../CommonInterfaces/CommonParameterInterface.h"
|
||||
#include "ParallelFor.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "LinearMath/btPoolAllocator.h"
|
||||
#include "btBulletCollisionCommon.h"
|
||||
#include "BulletDynamics/Dynamics/btSimulationIslandManagerMt.h" // for setSplitIslands()
|
||||
#include "BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h"
|
||||
#include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h"
|
||||
|
||||
TaskManager gTaskMgr;
|
||||
|
||||
#define USE_PARALLEL_NARROWPHASE 1 // detect collisions in parallel
|
||||
#define USE_PARALLEL_ISLAND_SOLVER 1 // solve simulation islands in parallel
|
||||
#define USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS 1
|
||||
#define USE_PARALLEL_INTEGRATE_TRANSFORMS 1
|
||||
#define USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION 1
|
||||
|
||||
#if defined (_MSC_VER) && _MSC_VER >= 1600
|
||||
// give us a compile error if any signatures of overriden methods is changed
|
||||
#define BT_OVERRIDE override
|
||||
#else
|
||||
#define BT_OVERRIDE
|
||||
#endif
|
||||
|
||||
|
||||
class Profiler
|
||||
{
|
||||
public:
|
||||
enum RecordType
|
||||
{
|
||||
kRecordInternalTimeStep,
|
||||
kRecordDispatchAllCollisionPairs,
|
||||
kRecordDispatchIslands,
|
||||
kRecordPredictUnconstrainedMotion,
|
||||
kRecordCreatePredictiveContacts,
|
||||
kRecordIntegrateTransforms,
|
||||
kRecordCount
|
||||
};
|
||||
|
||||
private:
|
||||
btClock mClock;
|
||||
|
||||
struct Record
|
||||
{
|
||||
int mCallCount;
|
||||
unsigned long long mAccum;
|
||||
unsigned int mStartTime;
|
||||
unsigned int mHistory[8];
|
||||
|
||||
void begin(unsigned int curTime)
|
||||
{
|
||||
mStartTime = curTime;
|
||||
}
|
||||
void end(unsigned int curTime)
|
||||
{
|
||||
unsigned int endTime = curTime;
|
||||
unsigned int elapsed = endTime - mStartTime;
|
||||
mAccum += elapsed;
|
||||
mHistory[ mCallCount & 7 ] = elapsed;
|
||||
++mCallCount;
|
||||
}
|
||||
float getAverageTime() const
|
||||
{
|
||||
int count = btMin( 8, mCallCount );
|
||||
if ( count > 0 )
|
||||
{
|
||||
unsigned int sum = 0;
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
sum += mHistory[ i ];
|
||||
}
|
||||
float avg = float( sum ) / float( count );
|
||||
return avg;
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
Record mRecords[ kRecordCount ];
|
||||
|
||||
public:
|
||||
void begin(RecordType rt)
|
||||
{
|
||||
mRecords[rt].begin(mClock.getTimeMicroseconds());
|
||||
}
|
||||
void end(RecordType rt)
|
||||
{
|
||||
mRecords[rt].end(mClock.getTimeMicroseconds());
|
||||
}
|
||||
float getAverageTime(RecordType rt) const
|
||||
{
|
||||
return mRecords[rt].getAverageTime();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Profiler gProfiler;
|
||||
|
||||
class ProfileHelper
|
||||
{
|
||||
Profiler::RecordType mRecType;
|
||||
public:
|
||||
ProfileHelper(Profiler::RecordType rt)
|
||||
{
|
||||
mRecType = rt;
|
||||
gProfiler.begin( mRecType );
|
||||
}
|
||||
~ProfileHelper()
|
||||
{
|
||||
gProfiler.end( mRecType );
|
||||
}
|
||||
};
|
||||
|
||||
int gThreadsRunningCounter = 0;
|
||||
btSpinMutex gThreadsRunningCounterMutex;
|
||||
|
||||
void btPushThreadsAreRunning()
|
||||
{
|
||||
gThreadsRunningCounterMutex.lock();
|
||||
gThreadsRunningCounter++;
|
||||
gThreadsRunningCounterMutex.unlock();
|
||||
}
|
||||
|
||||
void btPopThreadsAreRunning()
|
||||
{
|
||||
gThreadsRunningCounterMutex.lock();
|
||||
gThreadsRunningCounter--;
|
||||
gThreadsRunningCounterMutex.unlock();
|
||||
}
|
||||
|
||||
bool btThreadsAreRunning()
|
||||
{
|
||||
return gThreadsRunningCounter != 0;
|
||||
}
|
||||
|
||||
|
||||
#if USE_PARALLEL_NARROWPHASE
|
||||
|
||||
class MyCollisionDispatcher : public btCollisionDispatcher
|
||||
{
|
||||
btSpinMutex m_manifoldPtrsMutex;
|
||||
|
||||
public:
|
||||
MyCollisionDispatcher( btCollisionConfiguration* config ) : btCollisionDispatcher( config )
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~MyCollisionDispatcher()
|
||||
{
|
||||
}
|
||||
|
||||
btPersistentManifold* getNewManifold( const btCollisionObject* body0, const btCollisionObject* body1 ) BT_OVERRIDE
|
||||
{
|
||||
// added spin-locks
|
||||
//optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance)
|
||||
|
||||
btScalar contactBreakingThreshold = ( m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD ) ?
|
||||
btMin( body0->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ), body1->getCollisionShape()->getContactBreakingThreshold( gContactBreakingThreshold ) )
|
||||
: gContactBreakingThreshold;
|
||||
|
||||
btScalar contactProcessingThreshold = btMin( body0->getContactProcessingThreshold(), body1->getContactProcessingThreshold() );
|
||||
|
||||
void* mem = m_persistentManifoldPoolAllocator->allocate( sizeof( btPersistentManifold ) );
|
||||
if (NULL == mem)
|
||||
{
|
||||
//we got a pool memory overflow, by default we fallback to dynamically allocate memory. If we require a contiguous contact pool then assert.
|
||||
if ( ( m_dispatcherFlags&CD_DISABLE_CONTACTPOOL_DYNAMIC_ALLOCATION ) == 0 )
|
||||
{
|
||||
mem = btAlignedAlloc( sizeof( btPersistentManifold ), 16 );
|
||||
}
|
||||
else
|
||||
{
|
||||
btAssert( 0 );
|
||||
//make sure to increase the m_defaultMaxPersistentManifoldPoolSize in the btDefaultCollisionConstructionInfo/btDefaultCollisionConfiguration
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
btPersistentManifold* manifold = new(mem) btPersistentManifold( body0, body1, 0, contactBreakingThreshold, contactProcessingThreshold );
|
||||
m_manifoldPtrsMutex.lock();
|
||||
manifold->m_index1a = m_manifoldsPtr.size();
|
||||
m_manifoldsPtr.push_back( manifold );
|
||||
m_manifoldPtrsMutex.unlock();
|
||||
|
||||
return manifold;
|
||||
}
|
||||
|
||||
void releaseManifold( btPersistentManifold* manifold ) BT_OVERRIDE
|
||||
{
|
||||
clearManifold( manifold );
|
||||
|
||||
m_manifoldPtrsMutex.lock();
|
||||
int findIndex = manifold->m_index1a;
|
||||
btAssert( findIndex < m_manifoldsPtr.size() );
|
||||
m_manifoldsPtr.swap( findIndex, m_manifoldsPtr.size() - 1 );
|
||||
m_manifoldsPtr[ findIndex ]->m_index1a = findIndex;
|
||||
m_manifoldsPtr.pop_back();
|
||||
m_manifoldPtrsMutex.unlock();
|
||||
|
||||
manifold->~btPersistentManifold();
|
||||
if ( m_persistentManifoldPoolAllocator->validPtr( manifold ) )
|
||||
{
|
||||
m_persistentManifoldPoolAllocator->freeMemory( manifold );
|
||||
}
|
||||
else
|
||||
{
|
||||
btAlignedFree( manifold );
|
||||
}
|
||||
}
|
||||
|
||||
struct Updater
|
||||
{
|
||||
btBroadphasePair* mPairArray;
|
||||
btNearCallback mCallback;
|
||||
btCollisionDispatcher* mDispatcher;
|
||||
const btDispatcherInfo* mInfo;
|
||||
|
||||
Updater()
|
||||
{
|
||||
mPairArray = NULL;
|
||||
mCallback = NULL;
|
||||
mDispatcher = NULL;
|
||||
mInfo = NULL;
|
||||
}
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
for ( int i = iBegin; i < iEnd; ++i )
|
||||
{
|
||||
btBroadphasePair* pair = &mPairArray[ i ];
|
||||
mCallback( *pair, *mDispatcher, *mInfo );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
virtual void dispatchAllCollisionPairs( btOverlappingPairCache* pairCache, const btDispatcherInfo& info, btDispatcher* dispatcher ) BT_OVERRIDE
|
||||
{
|
||||
ProfileHelper prof(Profiler::kRecordDispatchAllCollisionPairs);
|
||||
int grainSize = 40; // iterations per task
|
||||
int pairCount = pairCache->getNumOverlappingPairs();
|
||||
Updater updater;
|
||||
updater.mCallback = getNearCallback();
|
||||
updater.mPairArray = pairCount > 0 ? pairCache->getOverlappingPairArrayPtr() : NULL;
|
||||
updater.mDispatcher = this;
|
||||
updater.mInfo = &info;
|
||||
|
||||
btPushThreadsAreRunning();
|
||||
parallelFor( 0, pairCount, grainSize, updater );
|
||||
btPopThreadsAreRunning();
|
||||
|
||||
if (m_manifoldsPtr.size() < 1)
|
||||
return;
|
||||
|
||||
// reconstruct the manifolds array to ensure determinism
|
||||
m_manifoldsPtr.resizeNoInitialize(0);
|
||||
btBroadphasePair* pairs = pairCache->getOverlappingPairArrayPtr();
|
||||
for (int i = 0; i < pairCount; ++i)
|
||||
{
|
||||
btCollisionAlgorithm* algo = pairs[i].m_algorithm;
|
||||
if (algo) algo->getAllContactManifolds(m_manifoldsPtr);
|
||||
}
|
||||
|
||||
// update the indices (used when releasing manifolds)
|
||||
for (int i = 0; i < m_manifoldsPtr.size(); ++i)
|
||||
m_manifoldsPtr[i]->m_index1a = i;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_PARALLEL_ISLAND_SOLVER
|
||||
///
|
||||
/// MyConstraintSolverPool - masquerades as a constraint solver, but really it is a threadsafe pool of them.
|
||||
///
|
||||
/// Each solver in the pool is protected by a mutex. When solveGroup is called from a thread,
|
||||
/// the pool looks for a solver that isn't being used by another thread, locks it, and dispatches the
|
||||
/// call to the solver.
|
||||
/// So long as there are at least as many solvers as there are hardware threads, it should never need to
|
||||
/// spin wait.
|
||||
///
|
||||
class MyConstraintSolverPool : public btConstraintSolver
|
||||
{
|
||||
const static size_t kCacheLineSize = 128;
|
||||
struct ThreadSolver
|
||||
{
|
||||
btConstraintSolver* solver;
|
||||
btSpinMutex mutex;
|
||||
char _cachelinePadding[ kCacheLineSize - sizeof( btSpinMutex ) - sizeof( void* ) ]; // keep mutexes from sharing a cache line
|
||||
};
|
||||
btAlignedObjectArray<ThreadSolver> m_solvers;
|
||||
btConstraintSolverType m_solverType;
|
||||
|
||||
ThreadSolver* getAndLockThreadSolver()
|
||||
{
|
||||
while ( true )
|
||||
{
|
||||
for ( int i = 0; i < m_solvers.size(); ++i )
|
||||
{
|
||||
ThreadSolver& solver = m_solvers[ i ];
|
||||
if ( solver.mutex.tryLock() )
|
||||
{
|
||||
return &solver;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
void init( btConstraintSolver** solvers, int numSolvers )
|
||||
{
|
||||
m_solverType = BT_SEQUENTIAL_IMPULSE_SOLVER;
|
||||
m_solvers.resize( numSolvers );
|
||||
for ( int i = 0; i < numSolvers; ++i )
|
||||
{
|
||||
m_solvers[ i ].solver = solvers[ i ];
|
||||
}
|
||||
if ( numSolvers > 0 )
|
||||
{
|
||||
m_solverType = solvers[ 0 ]->getSolverType();
|
||||
}
|
||||
}
|
||||
public:
|
||||
// create the solvers for me
|
||||
explicit MyConstraintSolverPool( int numSolvers )
|
||||
{
|
||||
btAlignedObjectArray<btConstraintSolver*> solvers;
|
||||
solvers.reserve( numSolvers );
|
||||
for ( int i = 0; i < numSolvers; ++i )
|
||||
{
|
||||
btConstraintSolver* solver = new btSequentialImpulseConstraintSolver();
|
||||
solvers.push_back( solver );
|
||||
}
|
||||
init( &solvers[ 0 ], numSolvers );
|
||||
}
|
||||
|
||||
// pass in fully constructed solvers (destructor will delete them)
|
||||
MyConstraintSolverPool( btConstraintSolver** solvers, int numSolvers )
|
||||
{
|
||||
init( solvers, numSolvers );
|
||||
}
|
||||
virtual ~MyConstraintSolverPool()
|
||||
{
|
||||
// delete all solvers
|
||||
for ( int i = 0; i < m_solvers.size(); ++i )
|
||||
{
|
||||
ThreadSolver& solver = m_solvers[ i ];
|
||||
delete solver.solver;
|
||||
solver.solver = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//virtual void prepareSolve( int /* numBodies */, int /* numManifolds */ ) { ; } // does nothing
|
||||
|
||||
///solve a group of constraints
|
||||
virtual btScalar solveGroup( btCollisionObject** bodies,
|
||||
int numBodies,
|
||||
btPersistentManifold** manifolds,
|
||||
int numManifolds,
|
||||
btTypedConstraint** constraints,
|
||||
int numConstraints,
|
||||
const btContactSolverInfo& info,
|
||||
btIDebugDraw* debugDrawer,
|
||||
btDispatcher* dispatcher
|
||||
)
|
||||
{
|
||||
ThreadSolver* solver = getAndLockThreadSolver();
|
||||
solver->solver->solveGroup( bodies, numBodies, manifolds, numManifolds, constraints, numConstraints, info, debugDrawer, dispatcher );
|
||||
solver->mutex.unlock();
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
//virtual void allSolved( const btContactSolverInfo& /* info */, class btIDebugDraw* /* debugDrawer */ ) { ; } // does nothing
|
||||
|
||||
///clear internal cached data and reset random seed
|
||||
virtual void reset()
|
||||
{
|
||||
for ( int i = 0; i < m_solvers.size(); ++i )
|
||||
{
|
||||
ThreadSolver& solver = m_solvers[ i ];
|
||||
solver.mutex.lock();
|
||||
solver.solver->reset();
|
||||
solver.mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
virtual btConstraintSolverType getSolverType() const
|
||||
{
|
||||
return m_solverType;
|
||||
}
|
||||
};
|
||||
|
||||
struct UpdateIslandDispatcher
|
||||
{
|
||||
btAlignedObjectArray<btSimulationIslandManagerMt::Island*>* islandsPtr;
|
||||
btSimulationIslandManagerMt::IslandCallback* callback;
|
||||
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
for ( int i = iBegin; i < iEnd; ++i )
|
||||
{
|
||||
btSimulationIslandManagerMt::Island* island = ( *islandsPtr )[ i ];
|
||||
btPersistentManifold** manifolds = island->manifoldArray.size() ? &island->manifoldArray[ 0 ] : NULL;
|
||||
btTypedConstraint** constraintsPtr = island->constraintArray.size() ? &island->constraintArray[ 0 ] : NULL;
|
||||
callback->processIsland( &island->bodyArray[ 0 ],
|
||||
island->bodyArray.size(),
|
||||
manifolds,
|
||||
island->manifoldArray.size(),
|
||||
constraintsPtr,
|
||||
island->constraintArray.size(),
|
||||
island->id
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static int gNumIslands = 0;
|
||||
|
||||
void parallelIslandDispatch( btAlignedObjectArray<btSimulationIslandManagerMt::Island*>* islandsPtr, btSimulationIslandManagerMt::IslandCallback* callback )
|
||||
{
|
||||
ProfileHelper prof(Profiler::kRecordDispatchIslands);
|
||||
gNumIslands = islandsPtr->size();
|
||||
int grainSize = 1; // iterations per task
|
||||
UpdateIslandDispatcher dispatcher;
|
||||
dispatcher.islandsPtr = islandsPtr;
|
||||
dispatcher.callback = callback;
|
||||
btPushThreadsAreRunning();
|
||||
parallelFor( 0, islandsPtr->size(), grainSize, dispatcher );
|
||||
btPopThreadsAreRunning();
|
||||
}
|
||||
#endif //#if USE_PARALLEL_ISLAND_SOLVER
|
||||
|
||||
|
||||
void profileBeginCallback(btDynamicsWorld *world, btScalar timeStep)
|
||||
{
|
||||
gProfiler.begin(Profiler::kRecordInternalTimeStep);
|
||||
}
|
||||
|
||||
void profileEndCallback(btDynamicsWorld *world, btScalar timeStep)
|
||||
{
|
||||
gProfiler.end(Profiler::kRecordInternalTimeStep);
|
||||
}
|
||||
|
||||
///
|
||||
/// MyDiscreteDynamicsWorld
|
||||
///
|
||||
/// Should function exactly like btDiscreteDynamicsWorld.
|
||||
/// 3 methods that iterate over all of the rigidbodies can run in parallel:
|
||||
/// - predictUnconstraintMotion
|
||||
/// - integrateTransforms
|
||||
/// - createPredictiveContacts
|
||||
///
|
||||
ATTRIBUTE_ALIGNED16( class ) MyDiscreteDynamicsWorld : public btDiscreteDynamicsWorldMt
|
||||
{
|
||||
typedef btDiscreteDynamicsWorld ParentClass;
|
||||
|
||||
protected:
|
||||
#if USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION
|
||||
struct UpdaterUnconstrainedMotion
|
||||
{
|
||||
btScalar timeStep;
|
||||
btRigidBody** rigidBodies;
|
||||
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
for ( int i = iBegin; i < iEnd; ++i )
|
||||
{
|
||||
btRigidBody* body = rigidBodies[ i ];
|
||||
if ( !body->isStaticOrKinematicObject() )
|
||||
{
|
||||
//don't integrate/update velocities here, it happens in the constraint solver
|
||||
body->applyDamping( timeStep );
|
||||
body->predictIntegratedTransform( timeStep, body->getInterpolationWorldTransform() );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
virtual void predictUnconstraintMotion( btScalar timeStep ) BT_OVERRIDE
|
||||
{
|
||||
ProfileHelper prof( Profiler::kRecordPredictUnconstrainedMotion );
|
||||
BT_PROFILE( "predictUnconstraintMotion" );
|
||||
int grainSize = 50; // num of iterations per task for TBB
|
||||
int bodyCount = m_nonStaticRigidBodies.size();
|
||||
UpdaterUnconstrainedMotion update;
|
||||
update.timeStep = timeStep;
|
||||
update.rigidBodies = bodyCount ? &m_nonStaticRigidBodies[ 0 ] : NULL;
|
||||
btPushThreadsAreRunning();
|
||||
parallelFor( 0, bodyCount, grainSize, update );
|
||||
btPopThreadsAreRunning();
|
||||
}
|
||||
#endif // #if USE_PARALLEL_PREDICT_UNCONSTRAINED_MOTION
|
||||
|
||||
#if USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS
|
||||
struct UpdaterCreatePredictiveContacts
|
||||
{
|
||||
btScalar timeStep;
|
||||
btRigidBody** rigidBodies;
|
||||
MyDiscreteDynamicsWorld* world;
|
||||
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
world->createPredictiveContactsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep );
|
||||
}
|
||||
};
|
||||
|
||||
virtual void createPredictiveContacts( btScalar timeStep )
|
||||
{
|
||||
ProfileHelper prof( Profiler::kRecordCreatePredictiveContacts );
|
||||
releasePredictiveContacts();
|
||||
int grainSize = 50; // num of iterations per task for TBB or OPENMP
|
||||
if ( int bodyCount = m_nonStaticRigidBodies.size() )
|
||||
{
|
||||
UpdaterCreatePredictiveContacts update;
|
||||
update.world = this;
|
||||
update.timeStep = timeStep;
|
||||
update.rigidBodies = &m_nonStaticRigidBodies[ 0 ];
|
||||
btPushThreadsAreRunning();
|
||||
parallelFor( 0, bodyCount, grainSize, update );
|
||||
btPopThreadsAreRunning();
|
||||
}
|
||||
}
|
||||
#endif // #if USE_PARALLEL_CREATE_PREDICTIVE_CONTACTS
|
||||
|
||||
#if USE_PARALLEL_INTEGRATE_TRANSFORMS
|
||||
struct UpdaterIntegrateTransforms
|
||||
{
|
||||
btScalar timeStep;
|
||||
btRigidBody** rigidBodies;
|
||||
MyDiscreteDynamicsWorld* world;
|
||||
|
||||
void forLoop( int iBegin, int iEnd ) const
|
||||
{
|
||||
world->integrateTransformsInternal( &rigidBodies[ iBegin ], iEnd - iBegin, timeStep );
|
||||
}
|
||||
};
|
||||
|
||||
virtual void integrateTransforms( btScalar timeStep ) BT_OVERRIDE
|
||||
{
|
||||
ProfileHelper prof( Profiler::kRecordIntegrateTransforms );
|
||||
BT_PROFILE( "integrateTransforms" );
|
||||
int grainSize = 50; // num of iterations per task for TBB or OPENMP
|
||||
if ( int bodyCount = m_nonStaticRigidBodies.size() )
|
||||
{
|
||||
UpdaterIntegrateTransforms update;
|
||||
update.world = this;
|
||||
update.timeStep = timeStep;
|
||||
update.rigidBodies = &m_nonStaticRigidBodies[ 0 ];
|
||||
btPushThreadsAreRunning();
|
||||
parallelFor( 0, bodyCount, grainSize, update );
|
||||
btPopThreadsAreRunning();
|
||||
}
|
||||
}
|
||||
#endif // #if USE_PARALLEL_INTEGRATE_TRANSFORMS
|
||||
|
||||
public:
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
MyDiscreteDynamicsWorld( btDispatcher* dispatcher,
|
||||
btBroadphaseInterface* pairCache,
|
||||
btConstraintSolver* constraintSolver,
|
||||
btCollisionConfiguration* collisionConfiguration
|
||||
) :
|
||||
btDiscreteDynamicsWorldMt( dispatcher, pairCache, constraintSolver, collisionConfiguration )
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
static bool gMultithreadedWorld = false;
|
||||
static bool gDisplayProfileInfo = false;
|
||||
static btScalar gSliderNumThreads = 1.0f; // should be int
|
||||
static btScalar gSliderSolverIterations = 10.0f; // should be int
|
||||
|
||||
|
||||
////////////////////////////////////
|
||||
CommonRigidBodyMTBase::CommonRigidBodyMTBase( struct GUIHelperInterface* helper )
|
||||
:m_broadphase( 0 ),
|
||||
m_dispatcher( 0 ),
|
||||
m_solver( 0 ),
|
||||
m_collisionConfiguration( 0 ),
|
||||
m_dynamicsWorld( 0 ),
|
||||
m_pickedBody( 0 ),
|
||||
m_pickedConstraint( 0 ),
|
||||
m_guiHelper( helper )
|
||||
{
|
||||
m_multithreadedWorld = false;
|
||||
m_multithreadCapable = false;
|
||||
gTaskMgr.init();
|
||||
}
|
||||
|
||||
CommonRigidBodyMTBase::~CommonRigidBodyMTBase()
|
||||
{
|
||||
gTaskMgr.shutdown();
|
||||
}
|
||||
|
||||
void boolPtrButtonCallback(int buttonId, bool buttonState, void* userPointer)
|
||||
{
|
||||
if (bool* val = static_cast<bool*>(userPointer))
|
||||
{
|
||||
*val = ! *val;
|
||||
}
|
||||
}
|
||||
|
||||
void apiSelectButtonCallback(int buttonId, bool buttonState, void* userPointer)
|
||||
{
|
||||
gTaskMgr.setApi(static_cast<TaskManager::Api>(buttonId));
|
||||
if (gTaskMgr.getApi()==TaskManager::apiNone)
|
||||
{
|
||||
gSliderNumThreads = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
gSliderNumThreads = float(gTaskMgr.getNumThreads());
|
||||
}
|
||||
}
|
||||
|
||||
void setThreadCountCallback(float val, void* userPtr)
|
||||
{
|
||||
if (gTaskMgr.getApi()==TaskManager::apiNone)
|
||||
{
|
||||
gSliderNumThreads = 1.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
gTaskMgr.setNumThreads( int( gSliderNumThreads ) );
|
||||
}
|
||||
}
|
||||
|
||||
void setSolverIterationCountCallback(float val, void* userPtr)
|
||||
{
|
||||
if (btDiscreteDynamicsWorld* world = reinterpret_cast<btDiscreteDynamicsWorld*>(userPtr))
|
||||
{
|
||||
world->getSolverInfo().m_numIterations = btMax(1, int(gSliderSolverIterations));
|
||||
}
|
||||
}
|
||||
|
||||
void CommonRigidBodyMTBase::createEmptyDynamicsWorld()
|
||||
{
|
||||
gNumIslands = 0;
|
||||
#if BT_THREADSAFE && (BT_USE_OPENMP || BT_USE_PPL || BT_USE_TBB)
|
||||
m_multithreadCapable = true;
|
||||
#endif
|
||||
if ( gMultithreadedWorld )
|
||||
{
|
||||
m_dispatcher = NULL;
|
||||
btDefaultCollisionConstructionInfo cci;
|
||||
cci.m_defaultMaxPersistentManifoldPoolSize = 80000;
|
||||
cci.m_defaultMaxCollisionAlgorithmPoolSize = 80000;
|
||||
m_collisionConfiguration = new btDefaultCollisionConfiguration( cci );
|
||||
|
||||
#if USE_PARALLEL_NARROWPHASE
|
||||
m_dispatcher = new MyCollisionDispatcher( m_collisionConfiguration );
|
||||
#else
|
||||
m_dispatcher = new btCollisionDispatcher( m_collisionConfiguration );
|
||||
#endif //USE_PARALLEL_NARROWPHASE
|
||||
|
||||
m_broadphase = new btDbvtBroadphase();
|
||||
|
||||
#if USE_PARALLEL_ISLAND_SOLVER
|
||||
m_solver = new MyConstraintSolverPool( TaskManager::getMaxNumThreads() );
|
||||
#else
|
||||
m_solver = new btSequentialImpulseConstraintSolver();
|
||||
#endif //#if USE_PARALLEL_ISLAND_SOLVER
|
||||
btDiscreteDynamicsWorld* world = new MyDiscreteDynamicsWorld( m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration );
|
||||
m_dynamicsWorld = world;
|
||||
|
||||
#if USE_PARALLEL_ISLAND_SOLVER
|
||||
if ( btSimulationIslandManagerMt* islandMgr = dynamic_cast<btSimulationIslandManagerMt*>( world->getSimulationIslandManager() ) )
|
||||
{
|
||||
islandMgr->setIslandDispatchFunction( parallelIslandDispatch );
|
||||
m_multithreadedWorld = true;
|
||||
}
|
||||
#endif //#if USE_PARALLEL_ISLAND_SOLVER
|
||||
}
|
||||
else
|
||||
{
|
||||
// single threaded world
|
||||
m_multithreadedWorld = false;
|
||||
|
||||
///collision configuration contains default setup for memory, collision setup
|
||||
m_collisionConfiguration = new btDefaultCollisionConfiguration();
|
||||
//m_collisionConfiguration->setConvexConvexMultipointIterations();
|
||||
|
||||
///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded)
|
||||
m_dispatcher = new btCollisionDispatcher( m_collisionConfiguration );
|
||||
|
||||
m_broadphase = new btDbvtBroadphase();
|
||||
|
||||
///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded)
|
||||
btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver;
|
||||
m_solver = sol;
|
||||
|
||||
m_dynamicsWorld = new btDiscreteDynamicsWorld( m_dispatcher, m_broadphase, m_solver, m_collisionConfiguration );
|
||||
}
|
||||
m_dynamicsWorld->setInternalTickCallback( profileBeginCallback, NULL, true );
|
||||
m_dynamicsWorld->setInternalTickCallback( profileEndCallback, NULL, false );
|
||||
m_dynamicsWorld->setGravity( btVector3( 0, -10, 0 ) );
|
||||
createDefaultParameters();
|
||||
}
|
||||
|
||||
|
||||
void CommonRigidBodyMTBase::createDefaultParameters()
|
||||
{
|
||||
if (m_multithreadCapable)
|
||||
{
|
||||
// create a button to toggle multithreaded world
|
||||
ButtonParams button( "Multithreaded world enable", 0, true );
|
||||
button.m_userPointer = &gMultithreadedWorld;
|
||||
button.m_callback = boolPtrButtonCallback;
|
||||
m_guiHelper->getParameterInterface()->registerButtonParameter( button );
|
||||
}
|
||||
{
|
||||
// create a button to toggle profile printing
|
||||
ButtonParams button( "Display profile timings", 0, true );
|
||||
button.m_userPointer = &gDisplayProfileInfo;
|
||||
button.m_callback = boolPtrButtonCallback;
|
||||
m_guiHelper->getParameterInterface()->registerButtonParameter( button );
|
||||
}
|
||||
{
|
||||
SliderParams slider( "Solver iterations", &gSliderSolverIterations );
|
||||
slider.m_minVal = 1.0f;
|
||||
slider.m_maxVal = 30.0f;
|
||||
slider.m_callback = setSolverIterationCountCallback;
|
||||
slider.m_userPointer = m_dynamicsWorld;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
if (m_multithreadedWorld)
|
||||
{
|
||||
// create a button for each supported threading API
|
||||
for (int iApi = 0; iApi < TaskManager::apiCount; ++iApi)
|
||||
{
|
||||
TaskManager::Api api = static_cast<TaskManager::Api>(iApi);
|
||||
if (gTaskMgr.isSupported(api))
|
||||
{
|
||||
char str[1024];
|
||||
sprintf(str, "API %s", gTaskMgr.getApiName(api));
|
||||
ButtonParams button( str, iApi, false );
|
||||
button.m_callback = apiSelectButtonCallback;
|
||||
m_guiHelper->getParameterInterface()->registerButtonParameter( button );
|
||||
}
|
||||
}
|
||||
{
|
||||
// create a slider to set the number of threads to use
|
||||
gSliderNumThreads = float(gTaskMgr.getNumThreads());
|
||||
SliderParams slider("Thread count", &gSliderNumThreads);
|
||||
slider.m_minVal = 1.0f;
|
||||
slider.m_maxVal = float(gTaskMgr.getMaxNumThreads()*2);
|
||||
slider.m_callback = setThreadCountCallback;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CommonRigidBodyMTBase::physicsDebugDraw(int debugFlags)
|
||||
{
|
||||
if (m_dynamicsWorld && m_dynamicsWorld->getDebugDrawer())
|
||||
{
|
||||
m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugFlags);
|
||||
m_dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
char msg[ 1024 ];
|
||||
int xCoord = 400;
|
||||
int yCoord = 30;
|
||||
int yStep = 30;
|
||||
if (m_multithreadCapable)
|
||||
{
|
||||
if ( m_multithreadedWorld != gMultithreadedWorld )
|
||||
{
|
||||
sprintf( msg, "restart example to begin in %s mode",
|
||||
gMultithreadedWorld ? "multithreaded" : "single threaded"
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, 300, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
}
|
||||
}
|
||||
if (gDisplayProfileInfo)
|
||||
{
|
||||
if ( m_multithreadedWorld )
|
||||
{
|
||||
int numManifolds = m_dispatcher->getNumManifolds();
|
||||
int numContacts = 0;
|
||||
for ( int i = 0; i < numManifolds; ++i )
|
||||
{
|
||||
const btPersistentManifold* man = m_dispatcher->getManifoldByIndexInternal( i );
|
||||
numContacts += man->getNumContacts();
|
||||
}
|
||||
const char* mtApi = TaskManager::getApiName( gTaskMgr.getApi() );
|
||||
sprintf( msg, "islands=%d bodies=%d manifolds=%d contacts=%d [%s] threads=%d",
|
||||
gNumIslands,
|
||||
m_dynamicsWorld->getNumCollisionObjects(),
|
||||
numManifolds,
|
||||
numContacts,
|
||||
mtApi,
|
||||
gTaskMgr.getApi() == TaskManager::apiNone ? 1 : gTaskMgr.getNumThreads()
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, 100, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
}
|
||||
|
||||
sprintf( msg, "internalSimStep %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordInternalTimeStep )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
|
||||
if ( m_multithreadedWorld )
|
||||
{
|
||||
sprintf( msg,
|
||||
"DispatchCollisionPairs %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordDispatchAllCollisionPairs )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
|
||||
sprintf( msg,
|
||||
"SolveAllIslands %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordDispatchIslands )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
|
||||
sprintf( msg,
|
||||
"PredictUnconstrainedMotion %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordPredictUnconstrainedMotion )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
|
||||
sprintf( msg,
|
||||
"CreatePredictiveContacts %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordCreatePredictiveContacts )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
|
||||
sprintf( msg,
|
||||
"IntegrateTransforms %5.3f ms",
|
||||
gProfiler.getAverageTime( Profiler::kRecordIntegrateTransforms )*0.001f
|
||||
);
|
||||
m_guiHelper->getAppInterface()->drawText( msg, xCoord, yCoord, 0.4f );
|
||||
yCoord += yStep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
438
examples/MultiThreadedDemo/CommonRigidBodyMTBase.h
Normal file
438
examples/MultiThreadedDemo/CommonRigidBodyMTBase.h
Normal file
@@ -0,0 +1,438 @@
|
||||
|
||||
#ifndef COMMON_RIGID_BODY_MT_BASE_H
|
||||
#define COMMON_RIGID_BODY_MT_BASE_H
|
||||
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "../CommonInterfaces/CommonExampleInterface.h"
|
||||
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
||||
#include "../CommonInterfaces/CommonRenderInterface.h"
|
||||
#include "../CommonInterfaces/CommonCameraInterface.h"
|
||||
#include "../CommonInterfaces/CommonGraphicsAppInterface.h"
|
||||
#include "../CommonInterfaces/CommonWindowInterface.h"
|
||||
|
||||
struct CommonRigidBodyMTBase : public CommonExampleInterface
|
||||
{
|
||||
//keep the collision shapes, for deletion/cleanup
|
||||
btAlignedObjectArray<btCollisionShape*> m_collisionShapes;
|
||||
btBroadphaseInterface* m_broadphase;
|
||||
btCollisionDispatcher* m_dispatcher;
|
||||
btConstraintSolver* m_solver;
|
||||
btDefaultCollisionConfiguration* m_collisionConfiguration;
|
||||
btDiscreteDynamicsWorld* m_dynamicsWorld;
|
||||
bool m_multithreadedWorld;
|
||||
bool m_multithreadCapable;
|
||||
|
||||
//data for picking objects
|
||||
class btRigidBody* m_pickedBody;
|
||||
class btTypedConstraint* m_pickedConstraint;
|
||||
int m_savedState;
|
||||
btVector3 m_oldPickingPos;
|
||||
btVector3 m_hitPos;
|
||||
btScalar m_oldPickingDist;
|
||||
struct GUIHelperInterface* m_guiHelper;
|
||||
|
||||
CommonRigidBodyMTBase(struct GUIHelperInterface* helper);
|
||||
virtual ~CommonRigidBodyMTBase();
|
||||
|
||||
|
||||
btDiscreteDynamicsWorld* getDynamicsWorld()
|
||||
{
|
||||
return m_dynamicsWorld;
|
||||
}
|
||||
|
||||
virtual void createDefaultParameters();
|
||||
virtual void createEmptyDynamicsWorld();
|
||||
|
||||
virtual void stepSimulation(float deltaTime)
|
||||
{
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
m_dynamicsWorld->stepSimulation(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void physicsDebugDraw(int debugFlags);
|
||||
|
||||
virtual void exitPhysics()
|
||||
{
|
||||
removePickingConstraint();
|
||||
//cleanup in the reverse order of creation/initialization
|
||||
|
||||
//remove the rigidbodies from the dynamics world and delete them
|
||||
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
|
||||
int i;
|
||||
for (i = m_dynamicsWorld->getNumConstraints() - 1; i >= 0; i--)
|
||||
{
|
||||
m_dynamicsWorld->removeConstraint(m_dynamicsWorld->getConstraint(i));
|
||||
}
|
||||
for (i = m_dynamicsWorld->getNumCollisionObjects() - 1; i >= 0; i--)
|
||||
{
|
||||
btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i];
|
||||
btRigidBody* body = btRigidBody::upcast(obj);
|
||||
if (body && body->getMotionState())
|
||||
{
|
||||
delete body->getMotionState();
|
||||
}
|
||||
m_dynamicsWorld->removeCollisionObject(obj);
|
||||
delete obj;
|
||||
}
|
||||
}
|
||||
//delete collision shapes
|
||||
for (int j = 0; j<m_collisionShapes.size(); j++)
|
||||
{
|
||||
btCollisionShape* shape = m_collisionShapes[j];
|
||||
delete shape;
|
||||
}
|
||||
m_collisionShapes.clear();
|
||||
|
||||
delete m_dynamicsWorld;
|
||||
m_dynamicsWorld=0;
|
||||
|
||||
delete m_solver;
|
||||
m_solver=0;
|
||||
|
||||
delete m_broadphase;
|
||||
m_broadphase=0;
|
||||
|
||||
delete m_dispatcher;
|
||||
m_dispatcher=0;
|
||||
|
||||
delete m_collisionConfiguration;
|
||||
m_collisionConfiguration=0;
|
||||
}
|
||||
|
||||
|
||||
virtual void debugDraw(int debugDrawFlags)
|
||||
{
|
||||
if (m_dynamicsWorld)
|
||||
{
|
||||
if (m_dynamicsWorld->getDebugDrawer())
|
||||
{
|
||||
m_dynamicsWorld->getDebugDrawer()->setDebugMode(debugDrawFlags);
|
||||
}
|
||||
m_dynamicsWorld->debugDrawWorld();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
virtual bool keyboardCallback(int key, int state)
|
||||
{
|
||||
if ((key==B3G_F3) && state && m_dynamicsWorld)
|
||||
{
|
||||
btDefaultSerializer* serializer = new btDefaultSerializer();
|
||||
m_dynamicsWorld->serialize(serializer);
|
||||
|
||||
FILE* file = fopen("testFile.bullet","wb");
|
||||
fwrite(serializer->getBufferPointer(),serializer->getCurrentBufferSize(),1, file);
|
||||
fclose(file);
|
||||
//b3Printf("btDefaultSerializer wrote testFile.bullet");
|
||||
delete serializer;
|
||||
return true;
|
||||
|
||||
}
|
||||
return false;//don't handle this key
|
||||
}
|
||||
|
||||
|
||||
btVector3 getRayTo(int x,int y)
|
||||
{
|
||||
CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
|
||||
|
||||
if (!renderer)
|
||||
{
|
||||
btAssert(0);
|
||||
return btVector3(0,0,0);
|
||||
}
|
||||
|
||||
float top = 1.f;
|
||||
float bottom = -1.f;
|
||||
float nearPlane = 1.f;
|
||||
float tanFov = (top-bottom)*0.5f / nearPlane;
|
||||
float fov = btScalar(2.0) * btAtan(tanFov);
|
||||
|
||||
btVector3 camPos,camTarget;
|
||||
|
||||
renderer->getActiveCamera()->getCameraPosition(camPos);
|
||||
renderer->getActiveCamera()->getCameraTargetPosition(camTarget);
|
||||
|
||||
btVector3 rayFrom = camPos;
|
||||
btVector3 rayForward = (camTarget-camPos);
|
||||
rayForward.normalize();
|
||||
float farPlane = 10000.f;
|
||||
rayForward*= farPlane;
|
||||
|
||||
btVector3 rightOffset;
|
||||
btVector3 cameraUp=btVector3(0,0,0);
|
||||
cameraUp[m_guiHelper->getAppInterface()->getUpAxis()]=1;
|
||||
|
||||
btVector3 vertical = cameraUp;
|
||||
|
||||
btVector3 hor;
|
||||
hor = rayForward.cross(vertical);
|
||||
hor.safeNormalize();
|
||||
vertical = hor.cross(rayForward);
|
||||
vertical.safeNormalize();
|
||||
|
||||
float tanfov = tanf(0.5f*fov);
|
||||
|
||||
|
||||
hor *= 2.f * farPlane * tanfov;
|
||||
vertical *= 2.f * farPlane * tanfov;
|
||||
|
||||
btScalar aspect;
|
||||
float width = float(renderer->getScreenWidth());
|
||||
float height = float (renderer->getScreenHeight());
|
||||
|
||||
aspect = width / height;
|
||||
|
||||
hor*=aspect;
|
||||
|
||||
|
||||
btVector3 rayToCenter = rayFrom + rayForward;
|
||||
btVector3 dHor = hor * 1.f/width;
|
||||
btVector3 dVert = vertical * 1.f/height;
|
||||
|
||||
|
||||
btVector3 rayTo = rayToCenter - 0.5f * hor + 0.5f * vertical;
|
||||
rayTo += btScalar(x) * dHor;
|
||||
rayTo -= btScalar(y) * dVert;
|
||||
return rayTo;
|
||||
}
|
||||
|
||||
virtual bool mouseMoveCallback(float x,float y)
|
||||
{
|
||||
CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
|
||||
|
||||
if (!renderer)
|
||||
{
|
||||
btAssert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
btVector3 rayTo = getRayTo(int(x), int(y));
|
||||
btVector3 rayFrom;
|
||||
renderer->getActiveCamera()->getCameraPosition(rayFrom);
|
||||
movePickedBody(rayFrom,rayTo);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool mouseButtonCallback(int button, int state, float x, float y)
|
||||
{
|
||||
CommonRenderInterface* renderer = m_guiHelper->getRenderInterface();
|
||||
|
||||
if (!renderer)
|
||||
{
|
||||
btAssert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
CommonWindowInterface* window = m_guiHelper->getAppInterface()->m_window;
|
||||
|
||||
#if 0
|
||||
if (window->isModifierKeyPressed(B3G_ALT))
|
||||
{
|
||||
printf("ALT pressed\n");
|
||||
} else
|
||||
{
|
||||
printf("NO ALT pressed\n");
|
||||
}
|
||||
|
||||
if (window->isModifierKeyPressed(B3G_SHIFT))
|
||||
{
|
||||
printf("SHIFT pressed\n");
|
||||
} else
|
||||
{
|
||||
printf("NO SHIFT pressed\n");
|
||||
}
|
||||
|
||||
if (window->isModifierKeyPressed(B3G_CONTROL))
|
||||
{
|
||||
printf("CONTROL pressed\n");
|
||||
} else
|
||||
{
|
||||
printf("NO CONTROL pressed\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
if (state==1)
|
||||
{
|
||||
if(button==0 && (!window->isModifierKeyPressed(B3G_ALT) && !window->isModifierKeyPressed(B3G_CONTROL) ))
|
||||
{
|
||||
btVector3 camPos;
|
||||
renderer->getActiveCamera()->getCameraPosition(camPos);
|
||||
|
||||
btVector3 rayFrom = camPos;
|
||||
btVector3 rayTo = getRayTo(int(x),int(y));
|
||||
|
||||
pickBody(rayFrom, rayTo);
|
||||
|
||||
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (button==0)
|
||||
{
|
||||
removePickingConstraint();
|
||||
//remove p2p
|
||||
}
|
||||
}
|
||||
|
||||
//printf("button=%d, state=%d\n",button,state);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
|
||||
{
|
||||
if (m_dynamicsWorld==0)
|
||||
return false;
|
||||
|
||||
btCollisionWorld::ClosestRayResultCallback rayCallback(rayFromWorld, rayToWorld);
|
||||
|
||||
m_dynamicsWorld->rayTest(rayFromWorld, rayToWorld, rayCallback);
|
||||
if (rayCallback.hasHit())
|
||||
{
|
||||
|
||||
btVector3 pickPos = rayCallback.m_hitPointWorld;
|
||||
btRigidBody* body = (btRigidBody*)btRigidBody::upcast(rayCallback.m_collisionObject);
|
||||
if (body)
|
||||
{
|
||||
//other exclusions?
|
||||
if (!(body->isStaticObject() || body->isKinematicObject()))
|
||||
{
|
||||
m_pickedBody = body;
|
||||
m_savedState = m_pickedBody->getActivationState();
|
||||
m_pickedBody->setActivationState(DISABLE_DEACTIVATION);
|
||||
//printf("pickPos=%f,%f,%f\n",pickPos.getX(),pickPos.getY(),pickPos.getZ());
|
||||
btVector3 localPivot = body->getCenterOfMassTransform().inverse() * pickPos;
|
||||
btPoint2PointConstraint* p2p = new btPoint2PointConstraint(*body, localPivot);
|
||||
m_dynamicsWorld->addConstraint(p2p, true);
|
||||
m_pickedConstraint = p2p;
|
||||
btScalar mousePickClamping = 30.f;
|
||||
p2p->m_setting.m_impulseClamp = mousePickClamping;
|
||||
//very weak constraint for picking
|
||||
p2p->m_setting.m_tau = 0.001f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pickObject(pickPos, rayCallback.m_collisionObject);
|
||||
m_oldPickingPos = rayToWorld;
|
||||
m_hitPos = pickPos;
|
||||
m_oldPickingDist = (pickPos - rayFromWorld).length();
|
||||
// printf("hit !\n");
|
||||
//add p2p
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld)
|
||||
{
|
||||
if (m_pickedBody && m_pickedConstraint)
|
||||
{
|
||||
btPoint2PointConstraint* pickCon = static_cast<btPoint2PointConstraint*>(m_pickedConstraint);
|
||||
if (pickCon)
|
||||
{
|
||||
//keep it at the same picking distance
|
||||
|
||||
btVector3 newPivotB;
|
||||
|
||||
btVector3 dir = rayToWorld - rayFromWorld;
|
||||
dir.normalize();
|
||||
dir *= m_oldPickingDist;
|
||||
|
||||
newPivotB = rayFromWorld + dir;
|
||||
pickCon->setPivotB(newPivotB);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
virtual void removePickingConstraint()
|
||||
{
|
||||
if (m_pickedConstraint)
|
||||
{
|
||||
m_pickedBody->forceActivationState(m_savedState);
|
||||
m_pickedBody->activate();
|
||||
m_dynamicsWorld->removeConstraint(m_pickedConstraint);
|
||||
delete m_pickedConstraint;
|
||||
m_pickedConstraint = 0;
|
||||
m_pickedBody = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
btBoxShape* createBoxShape(const btVector3& halfExtents)
|
||||
{
|
||||
btBoxShape* box = new btBoxShape(halfExtents);
|
||||
return box;
|
||||
}
|
||||
|
||||
btRigidBody* createRigidBody(float mass, const btTransform& startTransform, btCollisionShape* shape, const btVector4& color = btVector4(1, 0, 0, 1))
|
||||
{
|
||||
btAssert((!shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE));
|
||||
|
||||
//rigidbody is dynamic if and only if mass is non zero, otherwise static
|
||||
bool isDynamic = (mass != 0.f);
|
||||
|
||||
btVector3 localInertia(0, 0, 0);
|
||||
if (isDynamic)
|
||||
shape->calculateLocalInertia(mass, localInertia);
|
||||
|
||||
//using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects
|
||||
|
||||
#define USE_MOTIONSTATE 1
|
||||
#ifdef USE_MOTIONSTATE
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(startTransform);
|
||||
|
||||
btRigidBody::btRigidBodyConstructionInfo cInfo(mass, myMotionState, shape, localInertia);
|
||||
|
||||
btRigidBody* body = new btRigidBody(cInfo);
|
||||
//body->setContactProcessingThreshold(m_defaultContactProcessingThreshold);
|
||||
|
||||
#else
|
||||
btRigidBody* body = new btRigidBody(mass, 0, shape, localInertia);
|
||||
body->setWorldTransform(startTransform);
|
||||
#endif//
|
||||
|
||||
body->setUserIndex(-1);
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
return body;
|
||||
}
|
||||
|
||||
btRigidBody* createKinematicBody(const btTransform& startTransform, btCollisionShape* shape)
|
||||
{
|
||||
btAssert( ( !shape || shape->getShapeType() != INVALID_SHAPE_PROXYTYPE ) );
|
||||
|
||||
btRigidBody* body = new btRigidBody( 0.0f, NULL, shape );
|
||||
body->setWorldTransform( startTransform );
|
||||
body->setCollisionFlags( body->getCollisionFlags() | btCollisionObject::CF_KINEMATIC_OBJECT );
|
||||
body->setUserIndex( -1 );
|
||||
m_dynamicsWorld->addRigidBody( body );
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
virtual void renderScene()
|
||||
{
|
||||
{
|
||||
|
||||
m_guiHelper->syncPhysicsToGraphics(m_dynamicsWorld);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
m_guiHelper->render(m_dynamicsWorld);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif //#define COMMON_RIGID_BODY_MT_BASE_H
|
||||
|
||||
|
||||
281
examples/MultiThreadedDemo/MultiThreadedDemo.cpp
Normal file
281
examples/MultiThreadedDemo/MultiThreadedDemo.cpp
Normal file
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include "btBulletDynamicsCommon.h"
|
||||
#include "LinearMath/btQuickprof.h"
|
||||
#include "LinearMath/btIDebugDraw.h"
|
||||
#include "../CommonInterfaces/CommonParameterInterface.h"
|
||||
#include <stdio.h> //printf debugging
|
||||
#include <algorithm>
|
||||
|
||||
class btCollisionShape;
|
||||
|
||||
#include "CommonRigidBodyMTBase.h"
|
||||
#include "MultiThreadedDemo.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "btBulletCollisionCommon.h"
|
||||
|
||||
|
||||
#define BT_OVERRIDE
|
||||
|
||||
static btScalar gSliderStackRows = 8.0f;
|
||||
static btScalar gSliderStackColumns = 6.0f;
|
||||
static btScalar gSliderStackHeight = 15.0f;
|
||||
static btScalar gSliderGroundHorizontalAmplitude = 0.0f;
|
||||
static btScalar gSliderGroundVerticalAmplitude = 0.0f;
|
||||
|
||||
|
||||
/// MultiThreadedDemo shows how to setup and use multithreading
|
||||
class MultiThreadedDemo : public CommonRigidBodyMTBase
|
||||
{
|
||||
static const int kUpAxis = 1;
|
||||
|
||||
btRigidBody* localCreateRigidBody(btScalar mass, const btTransform& worldTransform, btCollisionShape* colSape);
|
||||
|
||||
btVector3 m_cameraTargetPos;
|
||||
float m_cameraPitch;
|
||||
float m_cameraYaw;
|
||||
float m_cameraDist;
|
||||
btRigidBody* m_groundBody;
|
||||
btTransform m_groundStartXf;
|
||||
float m_groundMovePhase;
|
||||
|
||||
void createStack( const btVector3& pos, btCollisionShape* boxShape, const btVector3& halfBoxSize, int size );
|
||||
void createSceneObjects();
|
||||
void destroySceneObjects();
|
||||
|
||||
public:
|
||||
BT_DECLARE_ALIGNED_ALLOCATOR();
|
||||
|
||||
MultiThreadedDemo( struct GUIHelperInterface* helper );
|
||||
|
||||
virtual ~MultiThreadedDemo() {}
|
||||
|
||||
virtual void stepSimulation( float deltaTime ) BT_OVERRIDE
|
||||
{
|
||||
if ( m_dynamicsWorld )
|
||||
{
|
||||
if (m_groundBody)
|
||||
{
|
||||
// update ground
|
||||
const float cyclesPerSecond = 1.0f;
|
||||
m_groundMovePhase += cyclesPerSecond * deltaTime;
|
||||
m_groundMovePhase -= floor( m_groundMovePhase ); // keep phase between 0 and 1
|
||||
btTransform xf = m_groundStartXf;
|
||||
float gndHOffset = btSin(m_groundMovePhase * SIMD_2_PI) * gSliderGroundHorizontalAmplitude;
|
||||
float gndHVel = btCos(m_groundMovePhase * SIMD_2_PI) * gSliderGroundHorizontalAmplitude * cyclesPerSecond * SIMD_2_PI; // d(gndHOffset)/dt
|
||||
float gndVOffset = btSin(m_groundMovePhase * SIMD_2_PI) * gSliderGroundVerticalAmplitude;
|
||||
float gndVVel = btCos(m_groundMovePhase * SIMD_2_PI) * gSliderGroundVerticalAmplitude * cyclesPerSecond * SIMD_2_PI; // d(gndVOffset)/dt
|
||||
btVector3 offset(0,0,0);
|
||||
btVector3 vel(0,0,0);
|
||||
int horizAxis = 2;
|
||||
offset[horizAxis] = gndHOffset;
|
||||
vel[horizAxis] = gndHVel;
|
||||
offset[kUpAxis] = gndVOffset;
|
||||
vel[kUpAxis] = gndVVel;
|
||||
xf.setOrigin(xf.getOrigin() + offset);
|
||||
m_groundBody->setWorldTransform( xf );
|
||||
m_groundBody->setLinearVelocity( vel );
|
||||
}
|
||||
// always step by 1/60 for benchmarking
|
||||
m_dynamicsWorld->stepSimulation( 1.0f / 60.0f, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
virtual void initPhysics() BT_OVERRIDE;
|
||||
virtual void resetCamera() BT_OVERRIDE
|
||||
{
|
||||
m_guiHelper->resetCamera( m_cameraDist,
|
||||
m_cameraPitch,
|
||||
m_cameraYaw,
|
||||
m_cameraTargetPos.x(),
|
||||
m_cameraTargetPos.y(),
|
||||
m_cameraTargetPos.z()
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
MultiThreadedDemo::MultiThreadedDemo(struct GUIHelperInterface* helper)
|
||||
: CommonRigidBodyMTBase( helper )
|
||||
{
|
||||
m_groundBody = NULL;
|
||||
m_groundMovePhase = 0.0f;
|
||||
m_cameraTargetPos = btVector3( 0.0f, 0.0f, 0.0f );
|
||||
m_cameraPitch = 90.0f;
|
||||
m_cameraYaw = 30.0f;
|
||||
m_cameraDist = 48.0f;
|
||||
helper->setUpAxis( kUpAxis );
|
||||
}
|
||||
|
||||
|
||||
void MultiThreadedDemo::initPhysics()
|
||||
{
|
||||
createEmptyDynamicsWorld();
|
||||
|
||||
m_dynamicsWorld->setGravity( btVector3( 0, -10, 0 ) );
|
||||
|
||||
{
|
||||
SliderParams slider( "Stack height", &gSliderStackHeight );
|
||||
slider.m_minVal = 1.0f;
|
||||
slider.m_maxVal = 30.0f;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
{
|
||||
SliderParams slider( "Stack rows", &gSliderStackRows );
|
||||
slider.m_minVal = 1.0f;
|
||||
slider.m_maxVal = 20.0f;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
{
|
||||
SliderParams slider( "Stack columns", &gSliderStackColumns );
|
||||
slider.m_minVal = 1.0f;
|
||||
slider.m_maxVal = 20.0f;
|
||||
slider.m_clampToIntegers = true;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
{
|
||||
// horizontal ground shake
|
||||
SliderParams slider( "Ground horiz amp", &gSliderGroundHorizontalAmplitude );
|
||||
slider.m_minVal = 0.0f;
|
||||
slider.m_maxVal = 1.0f;
|
||||
slider.m_clampToNotches = false;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
{
|
||||
// vertical ground shake
|
||||
SliderParams slider( "Ground vert amp", &gSliderGroundVerticalAmplitude );
|
||||
slider.m_minVal = 0.0f;
|
||||
slider.m_maxVal = 1.0f;
|
||||
slider.m_clampToNotches = false;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter( slider );
|
||||
}
|
||||
|
||||
createSceneObjects();
|
||||
|
||||
m_guiHelper->createPhysicsDebugDrawer( m_dynamicsWorld );
|
||||
}
|
||||
|
||||
|
||||
|
||||
btRigidBody* MultiThreadedDemo::localCreateRigidBody(btScalar mass, const btTransform& startTransform, btCollisionShape* shape)
|
||||
{
|
||||
btRigidBody* body = createRigidBody(mass, startTransform, shape);
|
||||
if ( mass > 0.0f )
|
||||
{
|
||||
// prevent bodies from sleeping to make profiling/benchmarking easier
|
||||
body->forceActivationState( DISABLE_DEACTIVATION );
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
|
||||
void MultiThreadedDemo::createStack( const btVector3& center, btCollisionShape* boxShape, const btVector3& halfBoxSize, int size )
|
||||
{
|
||||
btTransform trans;
|
||||
trans.setIdentity();
|
||||
float halfBoxHeight = halfBoxSize.y();
|
||||
float halfBoxWidth = halfBoxSize.x();
|
||||
|
||||
for ( int i = 0; i<size; i++ )
|
||||
{
|
||||
// This constructs a row, from left to right
|
||||
int rowSize = size - i;
|
||||
for ( int j = 0; j< rowSize; j++ )
|
||||
{
|
||||
btVector3 pos = center + btVector3( halfBoxWidth*( 1 + j * 2 - rowSize ),
|
||||
halfBoxHeight * ( 1 + i * 2),
|
||||
0.0f
|
||||
);
|
||||
|
||||
trans.setOrigin( pos );
|
||||
btScalar mass = 1.f;
|
||||
|
||||
btRigidBody* body = localCreateRigidBody( mass, trans, boxShape );
|
||||
body->setFriction(1.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void MultiThreadedDemo::createSceneObjects()
|
||||
{
|
||||
{
|
||||
// create ground box
|
||||
btTransform tr;
|
||||
tr.setIdentity();
|
||||
tr.setOrigin( btVector3( 0.f, -3.f, 0.f ) );
|
||||
m_groundStartXf = tr;
|
||||
|
||||
//either use heightfield or triangle mesh
|
||||
|
||||
btVector3 groundExtents( 400, 400, 400 );
|
||||
groundExtents[ kUpAxis ] = 3;
|
||||
btCollisionShape* groundShape = new btBoxShape( groundExtents );
|
||||
m_collisionShapes.push_back( groundShape );
|
||||
|
||||
//create ground object
|
||||
m_groundBody = createKinematicBody( m_groundStartXf, groundShape );
|
||||
m_groundBody->forceActivationState( DISABLE_DEACTIVATION );
|
||||
m_groundBody->setFriction(1.0f);
|
||||
}
|
||||
|
||||
{
|
||||
// create walls of cubes
|
||||
const btVector3 halfExtents = btVector3( 0.5f, 0.25f, 0.5f );
|
||||
int numStackRows = btMax(1, int(gSliderStackRows));
|
||||
int numStackCols = btMax(1, int(gSliderStackColumns));
|
||||
int stackHeight = 15;
|
||||
float stackZSpacing = 3.0f;
|
||||
float stackXSpacing = 20.0f;
|
||||
|
||||
btBoxShape* boxShape = new btBoxShape( halfExtents );
|
||||
m_collisionShapes.push_back( boxShape );
|
||||
|
||||
for ( int iX = 0; iX < numStackCols; ++iX )
|
||||
{
|
||||
for ( int iZ = 0; iZ < numStackRows; ++iZ )
|
||||
{
|
||||
btVector3 center = btVector3( iX * stackXSpacing, 0.0f, ( iZ - numStackRows / 2 ) * stackZSpacing );
|
||||
createStack( center, boxShape, halfExtents, stackHeight );
|
||||
}
|
||||
}
|
||||
}
|
||||
#if 0
|
||||
if ( false )
|
||||
{
|
||||
// destroyer ball
|
||||
btTransform sphereTrans;
|
||||
sphereTrans.setIdentity();
|
||||
sphereTrans.setOrigin( btVector3( 0, 2, 40 ) );
|
||||
btSphereShape* ball = new btSphereShape( 2.f );
|
||||
m_collisionShapes.push_back( ball );
|
||||
btRigidBody* ballBody = localCreateRigidBody( 10000.f, sphereTrans, ball );
|
||||
ballBody->setLinearVelocity( btVector3( 0, 0, -10 ) );
|
||||
}
|
||||
#endif
|
||||
m_guiHelper->autogenerateGraphicsObjects( m_dynamicsWorld );
|
||||
|
||||
}
|
||||
|
||||
|
||||
CommonExampleInterface* MultiThreadedDemoCreateFunc( struct CommonExampleOptions& options )
|
||||
{
|
||||
return new MultiThreadedDemo(options.m_guiHelper);
|
||||
}
|
||||
|
||||
22
examples/MultiThreadedDemo/MultiThreadedDemo.h
Normal file
22
examples/MultiThreadedDemo/MultiThreadedDemo.h
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
#ifndef MULTITHREADED_DEMO_H
|
||||
#define MULTITHREADED_DEMO_H
|
||||
|
||||
class CommonExampleInterface* MultiThreadedDemoCreateFunc(struct CommonExampleOptions& options);
|
||||
|
||||
#endif // MULTITHREADED_DEMO_H
|
||||
|
||||
|
||||
336
examples/MultiThreadedDemo/ParallelFor.h
Normal file
336
examples/MultiThreadedDemo/ParallelFor.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/*
|
||||
Bullet Continuous Collision Detection and Physics Library
|
||||
Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from the use of this software.
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it freely,
|
||||
subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
#include <stdio.h> //printf debugging
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
// choose threading providers:
|
||||
#if BT_USE_TBB
|
||||
#define USE_TBB 1 // use Intel Threading Building Blocks for thread management
|
||||
#endif
|
||||
|
||||
#if BT_USE_PPL
|
||||
#define USE_PPL 1 // use Microsoft Parallel Patterns Library (installed with Visual Studio 2010 and later)
|
||||
#endif // BT_USE_PPL
|
||||
|
||||
#if BT_USE_OPENMP
|
||||
#define USE_OPENMP 1 // use OpenMP (also need to change compiler options for OpenMP support)
|
||||
#endif
|
||||
|
||||
|
||||
#if USE_OPENMP
|
||||
|
||||
#include <omp.h>
|
||||
|
||||
#endif // #if USE_OPENMP
|
||||
|
||||
|
||||
#if USE_PPL
|
||||
|
||||
#include <ppl.h> // if you get a compile error here, check whether your version of Visual Studio includes PPL
|
||||
// Visual Studio 2010 and later should come with it
|
||||
#include <concrtrm.h> // for GetProcessorCount()
|
||||
#endif // #if USE_PPL
|
||||
|
||||
|
||||
#if USE_TBB
|
||||
|
||||
#define __TBB_NO_IMPLICIT_LINKAGE 1
|
||||
#include <tbb/tbb.h>
|
||||
#include <tbb/task_scheduler_init.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include <tbb/blocked_range.h>
|
||||
|
||||
#endif // #if USE_TBB
|
||||
|
||||
|
||||
|
||||
class TaskManager
|
||||
{
|
||||
public:
|
||||
enum Api
|
||||
{
|
||||
apiNone,
|
||||
apiOpenMP,
|
||||
apiTbb,
|
||||
apiPpl,
|
||||
apiCount
|
||||
};
|
||||
static const char* getApiName( Api api )
|
||||
{
|
||||
switch ( api )
|
||||
{
|
||||
case apiNone: return "None";
|
||||
case apiOpenMP: return "OpenMP";
|
||||
case apiTbb: return "Intel TBB";
|
||||
case apiPpl: return "MS PPL";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
TaskManager()
|
||||
{
|
||||
m_api = apiNone;
|
||||
m_numThreads = 0;
|
||||
#if USE_TBB
|
||||
m_tbbSchedulerInit = NULL;
|
||||
#endif // #if USE_TBB
|
||||
}
|
||||
|
||||
Api getApi() const
|
||||
{
|
||||
return m_api;
|
||||
}
|
||||
|
||||
bool isSupported( Api api ) const
|
||||
{
|
||||
#if USE_OPENMP
|
||||
if ( api == apiOpenMP )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if USE_TBB
|
||||
if ( api == apiTbb )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#if USE_PPL
|
||||
if ( api == apiPpl )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
// apiNone is always "supported"
|
||||
return api == apiNone;
|
||||
}
|
||||
|
||||
void setApi( Api api )
|
||||
{
|
||||
if (isSupported(api))
|
||||
{
|
||||
m_api = api;
|
||||
}
|
||||
else
|
||||
{
|
||||
// no compile time support for selected API, fallback to "none"
|
||||
m_api = apiNone;
|
||||
}
|
||||
}
|
||||
|
||||
static int getMaxNumThreads()
|
||||
{
|
||||
#if USE_OPENMP
|
||||
return omp_get_max_threads();
|
||||
#elif USE_PPL
|
||||
return concurrency::GetProcessorCount();
|
||||
#elif USE_TBB
|
||||
return tbb::task_scheduler_init::default_num_threads();
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
int getNumThreads() const
|
||||
{
|
||||
return m_numThreads;
|
||||
}
|
||||
|
||||
int setNumThreads( int numThreads )
|
||||
{
|
||||
m_numThreads = ( std::max )( 1, numThreads );
|
||||
|
||||
#if USE_OPENMP
|
||||
omp_set_num_threads( m_numThreads );
|
||||
#endif
|
||||
|
||||
#if USE_PPL
|
||||
{
|
||||
using namespace concurrency;
|
||||
if ( CurrentScheduler::Id() != -1 )
|
||||
{
|
||||
CurrentScheduler::Detach();
|
||||
}
|
||||
SchedulerPolicy policy;
|
||||
policy.SetConcurrencyLimits( m_numThreads, m_numThreads );
|
||||
CurrentScheduler::Create( policy );
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_TBB
|
||||
if ( m_tbbSchedulerInit )
|
||||
{
|
||||
delete m_tbbSchedulerInit;
|
||||
m_tbbSchedulerInit = NULL;
|
||||
}
|
||||
m_tbbSchedulerInit = new tbb::task_scheduler_init( m_numThreads );
|
||||
#endif
|
||||
return m_numThreads;
|
||||
}
|
||||
|
||||
void init()
|
||||
{
|
||||
if (m_numThreads == 0)
|
||||
{
|
||||
#if USE_PPL
|
||||
setApi( apiPpl );
|
||||
#endif
|
||||
#if USE_TBB
|
||||
setApi( apiTbb );
|
||||
#endif
|
||||
#if USE_OPENMP
|
||||
setApi( apiOpenMP );
|
||||
#endif
|
||||
setNumThreads(getMaxNumThreads());
|
||||
}
|
||||
else
|
||||
{
|
||||
setNumThreads(m_numThreads);
|
||||
}
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
#if USE_TBB
|
||||
if ( m_tbbSchedulerInit )
|
||||
{
|
||||
delete m_tbbSchedulerInit;
|
||||
m_tbbSchedulerInit = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
Api m_api;
|
||||
int m_numThreads;
|
||||
#if USE_TBB
|
||||
tbb::task_scheduler_init* m_tbbSchedulerInit;
|
||||
#endif // #if USE_TBB
|
||||
};
|
||||
|
||||
extern TaskManager gTaskMgr;
|
||||
|
||||
|
||||
static void initTaskScheduler()
|
||||
{
|
||||
gTaskMgr.init();
|
||||
}
|
||||
|
||||
static void cleanupTaskScheduler()
|
||||
{
|
||||
gTaskMgr.shutdown();
|
||||
}
|
||||
|
||||
|
||||
#if USE_TBB
|
||||
///
|
||||
/// TbbBodyAdapter -- Converts a body object that implements the
|
||||
/// "forLoop(int iBegin, int iEnd) const" function
|
||||
/// into a TBB compatible object that takes a tbb::blocked_range<int> type.
|
||||
///
|
||||
template <class TBody>
|
||||
struct TbbBodyAdapter
|
||||
{
|
||||
const TBody* mBody;
|
||||
|
||||
void operator()( const tbb::blocked_range<int>& range ) const
|
||||
{
|
||||
mBody->forLoop( range.begin(), range.end() );
|
||||
}
|
||||
};
|
||||
#endif // #if USE_TBB
|
||||
|
||||
#if USE_PPL
|
||||
///
|
||||
/// PplBodyAdapter -- Converts a body object that implements the
|
||||
/// "forLoop(int iBegin, int iEnd) const" function
|
||||
/// into a PPL compatible object that implements "void operator()( int ) const"
|
||||
///
|
||||
template <class TBody>
|
||||
struct PplBodyAdapter
|
||||
{
|
||||
const TBody* mBody;
|
||||
int mGrainSize;
|
||||
int mIndexEnd;
|
||||
|
||||
void operator()( int i ) const
|
||||
{
|
||||
mBody->forLoop( i, (std::min)(i + mGrainSize, mIndexEnd) );
|
||||
}
|
||||
};
|
||||
#endif // #if USE_PPL
|
||||
|
||||
|
||||
///
|
||||
/// parallelFor -- interface for submitting work expressed as a for loop to the worker threads
|
||||
///
|
||||
template <class TBody>
|
||||
void parallelFor( int iBegin, int iEnd, int grainSize, const TBody& body )
|
||||
{
|
||||
#if USE_OPENMP
|
||||
if ( gTaskMgr.getApi() == TaskManager::apiOpenMP )
|
||||
{
|
||||
#pragma omp parallel for schedule(static, 1)
|
||||
for ( int i = iBegin; i < iEnd; i += grainSize )
|
||||
{
|
||||
body.forLoop( i, (std::min)( i + grainSize, iEnd ) );
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif // #if USE_OPENMP
|
||||
|
||||
#if USE_PPL
|
||||
if ( gTaskMgr.getApi() == TaskManager::apiPpl )
|
||||
{
|
||||
// PPL dispatch
|
||||
PplBodyAdapter<TBody> pplBody;
|
||||
pplBody.mBody = &body;
|
||||
pplBody.mGrainSize = grainSize;
|
||||
pplBody.mIndexEnd = iEnd;
|
||||
// note: MSVC 2010 doesn't support partitioner args, so avoid them
|
||||
concurrency::parallel_for( iBegin,
|
||||
iEnd,
|
||||
grainSize,
|
||||
pplBody
|
||||
);
|
||||
return;
|
||||
}
|
||||
#endif //#if USE_PPL
|
||||
|
||||
#if USE_TBB
|
||||
if ( gTaskMgr.getApi() == TaskManager::apiTbb )
|
||||
{
|
||||
// TBB dispatch
|
||||
TbbBodyAdapter<TBody> tbbBody;
|
||||
tbbBody.mBody = &body;
|
||||
tbb::parallel_for( tbb::blocked_range<int>( iBegin, iEnd, grainSize ),
|
||||
tbbBody,
|
||||
tbb::simple_partitioner()
|
||||
);
|
||||
return;
|
||||
}
|
||||
#endif // #if USE_TBB
|
||||
|
||||
{
|
||||
// run on main thread
|
||||
body.forLoop( iBegin, iEnd );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "stb_image/stb_image.h"
|
||||
#include "Bullet3Common/b3Quaternion.h"
|
||||
#include "Bullet3Common/b3Matrix3x3.h"
|
||||
#include "../Utils/b3Clock.h"
|
||||
#include "../CommonInterfaces/CommonParameterInterface.h"
|
||||
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
@@ -134,6 +135,8 @@ void SampleThreadFunc(void* userPtr,void* lsMemory)
|
||||
job->executeJob(localStorage->threadId);
|
||||
}
|
||||
|
||||
b3Clock::usleep(250);
|
||||
|
||||
args->m_cs->lock();
|
||||
int exitMagicNumber = args->m_cs->getSharedParam(1);
|
||||
requestExit = (exitMagicNumber==MAGIC_RESET_NUMBER);
|
||||
|
||||
@@ -80,7 +80,18 @@ m_window(0)
|
||||
m_window = helper->getAppInterface()->m_window;
|
||||
|
||||
m_data = new GpuRigidBodyDemoInternalData;
|
||||
m_data->m_guiHelper = helper;
|
||||
}
|
||||
|
||||
void GpuRigidBodyDemo::resetCamera()
|
||||
{
|
||||
float dist = 114;
|
||||
float pitch = 52;
|
||||
float yaw = 35;
|
||||
float targetPos[3]={0,0,0};
|
||||
m_data->m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
|
||||
}
|
||||
|
||||
GpuRigidBodyDemo::~GpuRigidBodyDemo()
|
||||
{
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ public:
|
||||
|
||||
virtual void renderScene();
|
||||
|
||||
|
||||
void resetCamera();
|
||||
|
||||
virtual void stepSimulation(float deltaTime);
|
||||
|
||||
//for picking
|
||||
|
||||
@@ -32,6 +32,7 @@ struct GpuRigidBodyDemoInternalData
|
||||
int m_pickGraphicsShapeIndex;
|
||||
int m_pickGraphicsShapeInstance;
|
||||
b3Config m_config;
|
||||
GUIHelperInterface* m_guiHelper;
|
||||
|
||||
GpuRigidBodyDemoInternalData()
|
||||
:m_instancePosOrnColor(0),
|
||||
@@ -45,7 +46,8 @@ struct GpuRigidBodyDemoInternalData
|
||||
m_pickGraphicsShapeInstance(-1),
|
||||
m_pickBody(-1),
|
||||
m_altPressed(0),
|
||||
m_controlPressed(0)
|
||||
m_controlPressed(0),
|
||||
m_guiHelper(0)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
@@ -17,9 +17,9 @@ subject to the following restrictions:
|
||||
|
||||
///todo: make this configurable in the gui
|
||||
bool useShadowMap = true;// true;//false;//true;
|
||||
int shadowMapWidth= 2048;
|
||||
int shadowMapHeight= 2048;
|
||||
float shadowMapWorldSize=5;
|
||||
int shadowMapWidth= 4096;
|
||||
int shadowMapHeight= 4096;
|
||||
float shadowMapWorldSize=10;
|
||||
|
||||
#define MAX_POINTS_IN_BATCH 1024
|
||||
#define MAX_LINES_IN_BATCH 1024
|
||||
@@ -1539,7 +1539,7 @@ void GLInstancingRenderer::renderSceneInternal(int renderMode)
|
||||
b3Assert(glGetError() ==GL_NO_ERROR);
|
||||
} else
|
||||
{
|
||||
//glDisable(GL_CULL_FACE);
|
||||
glEnable(GL_CULL_FACE);
|
||||
glCullFace(GL_BACK);
|
||||
|
||||
}
|
||||
|
||||
@@ -70,6 +70,11 @@ struct SimpleOpenGL2AppInternalData
|
||||
{
|
||||
GLuint m_fontTextureId;
|
||||
GLuint m_largeFontTextureId;
|
||||
int m_upAxis;
|
||||
SimpleOpenGL2AppInternalData()
|
||||
:m_upAxis(1)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
static GLuint BindFont2(const CTexFont *_Font)
|
||||
@@ -268,10 +273,11 @@ void SimpleOpenGL2App::drawGrid(DrawGridData data)
|
||||
}
|
||||
void SimpleOpenGL2App::setUpAxis(int axis)
|
||||
{
|
||||
this->m_data->m_upAxis = axis;
|
||||
}
|
||||
int SimpleOpenGL2App::getUpAxis() const
|
||||
{
|
||||
return 1;
|
||||
return this->m_data->m_upAxis;
|
||||
}
|
||||
|
||||
void SimpleOpenGL2App::swapBuffer()
|
||||
@@ -280,7 +286,7 @@ void SimpleOpenGL2App::swapBuffer()
|
||||
m_window->startRendering();
|
||||
|
||||
}
|
||||
void SimpleOpenGL2App::drawText( const char* txt, int posX, int posY)
|
||||
void SimpleOpenGL2App::drawText( const char* txt, int posX, int posY, float size)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ public:
|
||||
virtual int getUpAxis() const;
|
||||
|
||||
virtual void swapBuffer();
|
||||
virtual void drawText( const char* txt, int posX, int posY);
|
||||
virtual void drawText( const char* txt, int posX, int posY, float size);
|
||||
virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA){};
|
||||
virtual void setBackgroundColor(float red, float green, float blue);
|
||||
virtual int registerCubeShape(float halfExtentsX,float halfExtentsY, float halfExtentsZ, int textureIndex = -1, float textureScaling = 1)
|
||||
|
||||
@@ -33,6 +33,7 @@ void SimpleOpenGL2Renderer::updateCamera(int upAxis)
|
||||
float projection[16];
|
||||
float view[16];
|
||||
m_camera.setAspectRatio((float)m_width/(float)m_height);
|
||||
m_camera.setCameraUpAxis(upAxis);
|
||||
m_camera.update();
|
||||
m_camera.getCameraProjectionMatrix(projection);
|
||||
m_camera.getCameraViewMatrix(view);
|
||||
|
||||
@@ -352,7 +352,7 @@ void SimpleOpenGL3App::drawText3D( const char* txt, float worldPosX, float world
|
||||
}
|
||||
|
||||
|
||||
void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi)
|
||||
void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi, float size)
|
||||
{
|
||||
|
||||
float posX = (float)posXi;
|
||||
@@ -374,7 +374,7 @@ void SimpleOpenGL3App::drawText( const char* txt, int posXi, int posYi)
|
||||
{
|
||||
bool measureOnly = false;
|
||||
|
||||
float fontSize= 64;//512;//128;
|
||||
float fontSize= 64*size;//512;//128;
|
||||
sth_draw_text(m_data->m_fontStash,
|
||||
m_data->m_droidRegular,fontSize,posX,posY,
|
||||
txt,&dx, this->m_instancingRenderer->getScreenWidth(),
|
||||
|
||||
@@ -31,7 +31,7 @@ struct SimpleOpenGL3App : public CommonGraphicsApp
|
||||
virtual int getUpAxis() const;
|
||||
|
||||
virtual void swapBuffer();
|
||||
virtual void drawText( const char* txt, int posX, int posY);
|
||||
virtual void drawText( const char* txt, int posX, int posY, float size=1.0f);
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size);
|
||||
virtual void drawTexturedRect(float x0, float y0, float x1, float y1, float color[4], float u0,float v0, float u1, float v1, int useRGBA);
|
||||
struct sth_stash* getFontStash();
|
||||
|
||||
@@ -200,7 +200,6 @@ void RaytestDemo::initPhysics()
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setRollingFriction(1);
|
||||
body->setFriction(1);
|
||||
//add the body to the dynamics world
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
@@ -269,6 +268,7 @@ void RaytestDemo::initPhysics()
|
||||
rbInfo.m_startWorldTransform = startTransform;
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setRollingFriction(0.03);
|
||||
body->setSpinningFriction(0.03);
|
||||
body->setFriction(1);
|
||||
body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ struct TinyRendererSetupInternalData
|
||||
|
||||
TGAImage m_rgbColorBuffer;
|
||||
b3AlignedObjectArray<float> m_depthBuffer;
|
||||
b3AlignedObjectArray<float> m_shadowBuffer;
|
||||
b3AlignedObjectArray<int> m_segmentationMaskBuffer;
|
||||
|
||||
|
||||
@@ -53,6 +54,7 @@ struct TinyRendererSetupInternalData
|
||||
m_animateRenderer(0)
|
||||
{
|
||||
m_depthBuffer.resize(m_width*m_height);
|
||||
m_shadowBuffer.resize(m_width*m_height);
|
||||
// m_segmentationMaskBuffer.resize(m_width*m_height);
|
||||
|
||||
}
|
||||
@@ -152,7 +154,7 @@ TinyRendererSetup::TinyRendererSetup(struct GUIHelperInterface* gui)
|
||||
|
||||
const char* fileName = "textured_sphere_smooth.obj";
|
||||
fileName = "cube.obj";
|
||||
|
||||
fileName = "torus/torus_with_plane.obj";
|
||||
|
||||
{
|
||||
|
||||
@@ -188,6 +190,7 @@ TinyRendererSetup::TinyRendererSetup(struct GUIHelperInterface* gui)
|
||||
TinyRenderObjectData* ob = new TinyRenderObjectData(
|
||||
m_internalData->m_rgbColorBuffer,
|
||||
m_internalData->m_depthBuffer,
|
||||
&m_internalData->m_shadowBuffer,
|
||||
&m_internalData->m_segmentationMaskBuffer,
|
||||
m_internalData->m_renderObjects.size());
|
||||
|
||||
@@ -328,6 +331,7 @@ void TinyRendererSetup::stepSimulation(float deltaTime)
|
||||
{
|
||||
m_internalData->m_rgbColorBuffer.set(x,y,clearColor);
|
||||
m_internalData->m_depthBuffer[x+y*m_internalData->m_width] = -1e30f;
|
||||
m_internalData->m_shadowBuffer[x+y*m_internalData->m_width] = -1e30f;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +343,46 @@ void TinyRendererSetup::stepSimulation(float deltaTime)
|
||||
render->getActiveCamera()->getCameraViewMatrix(viewMat);
|
||||
render->getActiveCamera()->getCameraProjectionMatrix(projMat);
|
||||
|
||||
|
||||
for (int o=0;o<this->m_internalData->m_renderObjects.size();o++)
|
||||
{
|
||||
|
||||
const btTransform& tr = m_internalData->m_transforms[o];
|
||||
tr.getOpenGLMatrix(modelMat2);
|
||||
|
||||
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
for (int j=0;j<4;j++)
|
||||
{
|
||||
m_internalData->m_renderObjects[o]->m_modelMatrix[i][j] = float(modelMat2[i+4*j]);
|
||||
m_internalData->m_renderObjects[o]->m_viewMatrix[i][j] = viewMat[i+4*j];
|
||||
m_internalData->m_renderObjects[o]->m_projectionMatrix[i][j] = projMat[i+4*j];
|
||||
|
||||
btVector3 lightDirWorld;
|
||||
switch (m_app->getUpAxis())
|
||||
{
|
||||
case 1:
|
||||
lightDirWorld = btVector3(-50.f,100,30);
|
||||
break;
|
||||
case 2:
|
||||
lightDirWorld = btVector3(-50.f,30,100);
|
||||
break;
|
||||
default:{}
|
||||
};
|
||||
|
||||
m_internalData->m_renderObjects[o]->m_lightDirWorld = lightDirWorld.normalized();
|
||||
|
||||
btVector3 lightColor(1.0,1.0,1.0);
|
||||
m_internalData->m_renderObjects[o]->m_lightColor = lightColor;
|
||||
|
||||
m_internalData->m_renderObjects[o]->m_lightDistance = 10.0;
|
||||
m_internalData->m_renderObjects[o]->m_lightAmbientCoeff = 0.6;
|
||||
m_internalData->m_renderObjects[o]->m_lightDiffuseCoeff = 0.35;
|
||||
m_internalData->m_renderObjects[o]->m_lightSpecularCoeff = 0.05;
|
||||
}
|
||||
}
|
||||
TinyRenderer::renderObjectDepth(*m_internalData->m_renderObjects[o]);
|
||||
}
|
||||
|
||||
for (int o=0;o<this->m_internalData->m_renderObjects.size();o++)
|
||||
{
|
||||
@@ -369,6 +412,14 @@ void TinyRendererSetup::stepSimulation(float deltaTime)
|
||||
};
|
||||
|
||||
m_internalData->m_renderObjects[o]->m_lightDirWorld = lightDirWorld.normalized();
|
||||
|
||||
btVector3 lightColor(1.0,1.0,1.0);
|
||||
m_internalData->m_renderObjects[o]->m_lightColor = lightColor;
|
||||
|
||||
m_internalData->m_renderObjects[o]->m_lightDistance = 10.0;
|
||||
m_internalData->m_renderObjects[o]->m_lightAmbientCoeff = 0.6;
|
||||
m_internalData->m_renderObjects[o]->m_lightDiffuseCoeff = 0.35;
|
||||
m_internalData->m_renderObjects[o]->m_lightSpecularCoeff = 0.05;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,7 +343,6 @@ public:
|
||||
slider.m_maxVal=1;
|
||||
m_guiHelper->getParameterInterface()->registerSliderFloatParameter(slider);
|
||||
}
|
||||
if (1)
|
||||
{
|
||||
b3RobotSimLoadFileArgs args("");
|
||||
args.m_fileName = "gripper/wsg50_one_motor_gripper_new.sdf";
|
||||
@@ -374,12 +373,10 @@ public:
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (1)
|
||||
{
|
||||
b3RobotSimLoadFileArgs args("");
|
||||
args.m_fileName = "plane.urdf";
|
||||
args.m_startPosition.setValue(0,0,0);
|
||||
args.m_startPosition.setValue(0,0,-0.2);
|
||||
args.m_startOrientation.setEulerZYX(0,0,0);
|
||||
args.m_forceOverrideFixedBase = true;
|
||||
args.m_useMultiBody = true;
|
||||
@@ -388,7 +385,7 @@ public:
|
||||
|
||||
}
|
||||
m_robotSim.setGravity(b3MakeVector3(0,0,-10));
|
||||
m_robotSim.loadBunny();
|
||||
m_robotSim.loadBunny(0.1,0.1,0.02);
|
||||
|
||||
b3JointInfo revoluteJoint1;
|
||||
revoluteJoint1.m_parentFrame[0] = -0.055;
|
||||
@@ -431,6 +428,46 @@ public:
|
||||
m_robotSim.createJoint(0, 2, 0, 4, &revoluteJoint1);
|
||||
m_robotSim.createJoint(0, 3, 0, 6, &revoluteJoint2);
|
||||
}
|
||||
|
||||
if ((m_options & eSOFTBODY_MULTIBODY_COUPLING)!=0)
|
||||
{
|
||||
{
|
||||
b3RobotSimLoadFileArgs args("");
|
||||
args.m_fileName = "kuka_iiwa/model_free_base.urdf";
|
||||
args.m_startPosition.setValue(0,1.0,2.0);
|
||||
args.m_startOrientation.setEulerZYX(0,0,1.57);
|
||||
args.m_forceOverrideFixedBase = false;
|
||||
args.m_useMultiBody = true;
|
||||
b3RobotSimLoadFileResults results;
|
||||
m_robotSim.loadFile(args,results);
|
||||
|
||||
int kukaId = results.m_uniqueObjectIds[0];
|
||||
int numJoints = m_robotSim.getNumJoints(kukaId);
|
||||
b3Printf("numJoints = %d",numJoints);
|
||||
|
||||
for (int i=0;i<numJoints;i++)
|
||||
{
|
||||
b3JointInfo jointInfo;
|
||||
m_robotSim.getJointInfo(kukaId,i,&jointInfo);
|
||||
b3Printf("joint[%d].m_jointName=%s",i,jointInfo.m_jointName);
|
||||
b3JointMotorArgs controlArgs(CONTROL_MODE_VELOCITY);
|
||||
controlArgs.m_maxTorqueValue = 0.0;
|
||||
m_robotSim.setJointMotorControl(kukaId,i,controlArgs);
|
||||
}
|
||||
}
|
||||
{
|
||||
b3RobotSimLoadFileArgs args("");
|
||||
args.m_fileName = "plane.urdf";
|
||||
args.m_startPosition.setValue(0,0,0);
|
||||
args.m_startOrientation.setEulerZYX(0,0,0);
|
||||
args.m_forceOverrideFixedBase = true;
|
||||
args.m_useMultiBody = false;
|
||||
b3RobotSimLoadFileResults results;
|
||||
m_robotSim.loadFile(args,results);
|
||||
}
|
||||
m_robotSim.setGravity(b3MakeVector3(0,0,-10));
|
||||
m_robotSim.loadBunny(0.5,10.0,0.1);
|
||||
}
|
||||
}
|
||||
virtual void exitPhysics()
|
||||
{
|
||||
@@ -479,7 +516,7 @@ public:
|
||||
int fingerJointIndices[2]={0,1};
|
||||
double fingerTargetVelocities[2]={sGripperVerticalVelocity,sGripperClosingTargetVelocity
|
||||
};
|
||||
double maxTorqueValues[2]={50.0,50.0};
|
||||
double maxTorqueValues[2]={50.0,10.0};
|
||||
for (int i=0;i<2;i++)
|
||||
{
|
||||
b3JointMotorArgs controlArgs(CONTROL_MODE_VELOCITY);
|
||||
|
||||
@@ -22,6 +22,7 @@ enum GripperGraspExampleOptions
|
||||
eTWO_POINT_GRASP=2,
|
||||
eONE_MOTOR_GRASP=4,
|
||||
eGRASP_SOFT_BODY=8,
|
||||
eSOFTBODY_MULTIBODY_COUPLING=16,
|
||||
};
|
||||
|
||||
class CommonExampleInterface* GripperGraspExampleCreateFunc(struct CommonExampleOptions& options);
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include "Bullet3Common/b3AlignedObjectArray.h"
|
||||
#include "../CommonInterfaces/CommonRenderInterface.h"
|
||||
//#include "../CommonInterfaces/CommonExampleInterface.h"
|
||||
#include "../SharedMemory/PhysicsServerCommandProcessor.h"
|
||||
|
||||
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
||||
#include "../SharedMemory/PhysicsServerSharedMemory.h"
|
||||
#include "../SharedMemory/PhysicsServerSharedMemory.h"
|
||||
@@ -399,6 +401,21 @@ public:
|
||||
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)
|
||||
{
|
||||
}
|
||||
|
||||
virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual void removeUserDebugItem( int debugItemUniqueId)
|
||||
{
|
||||
}
|
||||
virtual void removeAllUserDebugItems( )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -666,7 +683,7 @@ void b3RobotSimAPI::createJoint(int parentBodyIndex, int parentJointIndex, int c
|
||||
b3Assert(b3CanSubmitCommand(m_data->m_physicsClient));
|
||||
if (b3CanSubmitCommand(m_data->m_physicsClient))
|
||||
{
|
||||
statusHandle = b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClient, b3CreateJoint(m_data->m_physicsClient, parentBodyIndex, parentJointIndex, childBodyIndex, childJointIndex, jointInfo));
|
||||
statusHandle = b3SubmitClientCommandAndWaitStatus(m_data->m_physicsClient, b3InitCreateUserConstraintCommand(m_data->m_physicsClient, parentBodyIndex, parentJointIndex, childBodyIndex, childJointIndex, jointInfo));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -893,7 +910,8 @@ bool b3RobotSimAPI::connect(GUIHelperInterface* guiHelper)
|
||||
}
|
||||
else
|
||||
{
|
||||
m_data->m_clientServerDirect = new PhysicsDirect();
|
||||
PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor;
|
||||
m_data->m_clientServerDirect = new PhysicsDirect(sdk);
|
||||
bool connected = m_data->m_clientServerDirect->connect(guiHelper);
|
||||
m_data->m_physicsClient = (b3PhysicsClientHandle)m_data->m_clientServerDirect;
|
||||
|
||||
@@ -1000,8 +1018,11 @@ void b3RobotSimAPI::getLinkState(int bodyUniqueId, int linkIndex, double* worldP
|
||||
}
|
||||
}
|
||||
|
||||
void b3RobotSimAPI::loadBunny()
|
||||
void b3RobotSimAPI::loadBunny(double scale, double mass, double collisionMargin)
|
||||
{
|
||||
b3SharedMemoryCommandHandle command = b3LoadBunnyCommandInit(m_data->m_physicsClient);
|
||||
b3LoadBunnySetScale(command, scale);
|
||||
b3LoadBunnySetMass(command, mass);
|
||||
b3LoadBunnySetCollisionMargin(command, collisionMargin);
|
||||
b3SubmitClientCommand(m_data->m_physicsClient, command);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ public:
|
||||
|
||||
void getLinkState(int bodyUniqueId, int linkIndex, double* worldPosition, double* worldOrientation);
|
||||
|
||||
void loadBunny();
|
||||
void loadBunny(double scale, double mass, double collisionMargin);
|
||||
};
|
||||
|
||||
#endif //B3_ROBOT_SIM_API_H
|
||||
|
||||
@@ -123,8 +123,8 @@ void RollingFrictionDemo::initPhysics()
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setFriction(1);
|
||||
body->setRollingFriction(1);
|
||||
body->setFriction(.5);
|
||||
|
||||
//add the body to the dynamics world
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
@@ -153,8 +153,7 @@ void RollingFrictionDemo::initPhysics()
|
||||
btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform);
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setFriction(1);
|
||||
body->setRollingFriction(1);
|
||||
body->setFriction(.1);
|
||||
//add the body to the dynamics world
|
||||
m_dynamicsWorld->addRigidBody(body);
|
||||
}
|
||||
@@ -217,7 +216,8 @@ void RollingFrictionDemo::initPhysics()
|
||||
btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,colShape,localInertia);
|
||||
btRigidBody* body = new btRigidBody(rbInfo);
|
||||
body->setFriction(1.f);
|
||||
body->setRollingFriction(.3);
|
||||
body->setRollingFriction(.1);
|
||||
body->setSpinningFriction(0.1);
|
||||
body->setAnisotropicFriction(colShape->getAnisotropicRollingFrictionDirection(),btCollisionObject::CF_ANISOTROPIC_ROLLING_FRICTION);
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ struct IKTrajectoryHelperInternalData
|
||||
VectorRn m_nullSpaceVelocity;
|
||||
|
||||
b3AlignedObjectArray<Node*> m_ikNodes;
|
||||
Jacobian* m_ikJacobian;
|
||||
|
||||
IKTrajectoryHelperInternalData()
|
||||
{
|
||||
@@ -48,23 +47,21 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3],
|
||||
{
|
||||
bool useAngularPart = (ikMethod==IK2_VEL_DLS_WITH_ORIENTATION || ikMethod==IK2_VEL_DLS_WITH_ORIENTATION_NULLSPACE) ? true : false;
|
||||
|
||||
m_data->m_ikJacobian = new Jacobian(useAngularPart,numQ);
|
||||
|
||||
// Reset(m_ikTree,m_ikJacobian);
|
||||
Jacobian ikJacobian(useAngularPart,numQ);
|
||||
|
||||
m_data->m_ikJacobian->Reset();
|
||||
ikJacobian.Reset();
|
||||
|
||||
bool UseJacobianTargets1 = false;
|
||||
|
||||
if ( UseJacobianTargets1 ) {
|
||||
m_data->m_ikJacobian->SetJtargetActive();
|
||||
ikJacobian.SetJtargetActive();
|
||||
}
|
||||
else {
|
||||
m_data->m_ikJacobian->SetJendActive();
|
||||
ikJacobian.SetJendActive();
|
||||
}
|
||||
VectorR3 targets;
|
||||
targets.Set(endEffectorTargetPosition[0],endEffectorTargetPosition[1],endEffectorTargetPosition[2]);
|
||||
m_data->m_ikJacobian->ComputeJacobian(&targets); // Set up Jacobian and deltaS vectors
|
||||
ikJacobian.ComputeJacobian(&targets); // Set up Jacobian and deltaS vectors
|
||||
|
||||
// Set one end effector world position from Bullet
|
||||
VectorRn deltaS(3);
|
||||
@@ -112,8 +109,8 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3],
|
||||
completeJacobian.Set(i+3,j,angular_jacobian[i*numQ+j]);
|
||||
}
|
||||
}
|
||||
m_data->m_ikJacobian->SetDeltaS(deltaC);
|
||||
m_data->m_ikJacobian->SetJendTrans(completeJacobian);
|
||||
ikJacobian.SetDeltaS(deltaC);
|
||||
ikJacobian.SetJendTrans(completeJacobian);
|
||||
} else
|
||||
{
|
||||
VectorRn deltaC(3);
|
||||
@@ -126,53 +123,53 @@ bool IKTrajectoryHelper::computeIK(const double endEffectorTargetPosition[3],
|
||||
completeJacobian.Set(i,j,linear_jacobian[i*numQ+j]);
|
||||
}
|
||||
}
|
||||
m_data->m_ikJacobian->SetDeltaS(deltaC);
|
||||
m_data->m_ikJacobian->SetJendTrans(completeJacobian);
|
||||
ikJacobian.SetDeltaS(deltaC);
|
||||
ikJacobian.SetJendTrans(completeJacobian);
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the change in theta values
|
||||
switch (ikMethod) {
|
||||
case IK2_JACOB_TRANS:
|
||||
m_data->m_ikJacobian->CalcDeltaThetasTranspose(); // Jacobian transpose method
|
||||
ikJacobian.CalcDeltaThetasTranspose(); // Jacobian transpose method
|
||||
break;
|
||||
case IK2_DLS:
|
||||
case IK2_VEL_DLS:
|
||||
case IK2_VEL_DLS_WITH_ORIENTATION:
|
||||
m_data->m_ikJacobian->CalcDeltaThetasDLS(); // Damped least squares method
|
||||
ikJacobian.CalcDeltaThetasDLS(); // Damped least squares method
|
||||
break;
|
||||
case IK2_VEL_DLS_WITH_NULLSPACE:
|
||||
case IK2_VEL_DLS_WITH_ORIENTATION_NULLSPACE:
|
||||
assert(m_data->m_nullSpaceVelocity.GetLength()==numQ);
|
||||
m_data->m_ikJacobian->CalcDeltaThetasDLSwithNullspace(m_data->m_nullSpaceVelocity);
|
||||
ikJacobian.CalcDeltaThetasDLSwithNullspace(m_data->m_nullSpaceVelocity);
|
||||
break;
|
||||
case IK2_DLS_SVD:
|
||||
m_data->m_ikJacobian->CalcDeltaThetasDLSwithSVD();
|
||||
ikJacobian.CalcDeltaThetasDLSwithSVD();
|
||||
break;
|
||||
case IK2_PURE_PSEUDO:
|
||||
m_data->m_ikJacobian->CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method
|
||||
ikJacobian.CalcDeltaThetasPseudoinverse(); // Pure pseudoinverse method
|
||||
break;
|
||||
case IK2_SDLS:
|
||||
m_data->m_ikJacobian->CalcDeltaThetasSDLS(); // Selectively damped least squares method
|
||||
ikJacobian.CalcDeltaThetasSDLS(); // Selectively damped least squares method
|
||||
break;
|
||||
default:
|
||||
m_data->m_ikJacobian->ZeroDeltaThetas();
|
||||
ikJacobian.ZeroDeltaThetas();
|
||||
break;
|
||||
}
|
||||
|
||||
// Use for velocity IK, update theta dot
|
||||
//m_data->m_ikJacobian->UpdateThetaDot();
|
||||
//ikJacobian.UpdateThetaDot();
|
||||
|
||||
// Use for position IK, incrementally update theta
|
||||
//m_data->m_ikJacobian->UpdateThetas();
|
||||
//ikJacobian.UpdateThetas();
|
||||
|
||||
// Apply the change in the theta values
|
||||
//m_data->m_ikJacobian->UpdatedSClampValue(&targets);
|
||||
//ikJacobian.UpdatedSClampValue(&targets);
|
||||
|
||||
for (int i=0;i<numQ;i++)
|
||||
{
|
||||
// Use for velocity IK
|
||||
q_new[i] = m_data->m_ikJacobian->dTheta[i] + q_current[i];
|
||||
q_new[i] = ikJacobian.dTheta[i] + q_current[i];
|
||||
|
||||
// Use for position IK
|
||||
//q_new[i] = m_data->m_ikNodes[i]->GetTheta();
|
||||
@@ -203,4 +200,4 @@ bool IKTrajectoryHelper::computeNullspaceVel(int numQ, const double* q_current,
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
|
||||
virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData)=0;
|
||||
|
||||
virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects) = 0;
|
||||
|
||||
virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo) = 0;
|
||||
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,14 +11,18 @@ B3_DECLARE_HANDLE(b3SharedMemoryCommandHandle);
|
||||
B3_DECLARE_HANDLE(b3SharedMemoryStatusHandle);
|
||||
|
||||
|
||||
///There are several connection methods, see following header files:
|
||||
#include "PhysicsClientSharedMemory_C_API.h"
|
||||
#include "PhysicsClientSharedMemory2_C_API.h"
|
||||
#include "PhysicsDirectC_API.h"
|
||||
#include "PhysicsClientUDP_C_API.h"
|
||||
#include "SharedMemoryInProcessPhysicsC_API.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
///b3ConnectSharedMemory will connect to a physics server over shared memory, so
|
||||
///make sure to start the server first.
|
||||
///and a way to spawn an OpenGL 3D GUI physics server and connect (b3CreateInProcessPhysicsServerAndConnect)
|
||||
b3PhysicsClientHandle b3ConnectSharedMemory(int key);
|
||||
|
||||
|
||||
///b3DisconnectSharedMemory will disconnect the client from the server and cleanup memory.
|
||||
void b3DisconnectSharedMemory(b3PhysicsClientHandle physClient);
|
||||
@@ -68,33 +72,86 @@ int b3GetNumJoints(b3PhysicsClientHandle physClient, int bodyIndex);
|
||||
///given a body and joint index, return the joint information. See b3JointInfo in SharedMemoryPublic.h
|
||||
int b3GetJointInfo(b3PhysicsClientHandle physClient, int bodyIndex, int jointIndex, struct b3JointInfo* info);
|
||||
|
||||
b3SharedMemoryCommandHandle b3CreateJoint(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info);
|
||||
b3SharedMemoryCommandHandle b3InitCreateUserConstraintCommand(b3PhysicsClientHandle physClient, int parentBodyIndex, int parentJointIndex, int childBodyIndex, int childJointIndex, struct b3JointInfo* info);
|
||||
int b3GetStatusUserConstraintUniqueId(b3SharedMemoryStatusHandle statusHandle);
|
||||
b3SharedMemoryCommandHandle b3InitRemoveUserConstraintCommand(b3PhysicsClientHandle physClient, int userConstraintUniqueId);
|
||||
|
||||
///Request debug lines for debug visualization. The flags in debugMode are the same as used in Bullet
|
||||
///Request physics debug lines for debug visualization. The flags in debugMode are the same as used in Bullet
|
||||
///See btIDebugDraw::DebugDrawModes in Bullet/src/LinearMath/btIDebugDraw.h
|
||||
b3SharedMemoryCommandHandle b3InitRequestDebugLinesCommand(b3PhysicsClientHandle physClient, int debugMode);
|
||||
|
||||
///Get the pointers to the debug line information, after b3InitRequestDebugLinesCommand returns
|
||||
///Get the pointers to the physics debug line information, after b3InitRequestDebugLinesCommand returns
|
||||
///status CMD_DEBUG_LINES_COMPLETED
|
||||
void b3GetDebugLines(b3PhysicsClientHandle physClient, struct b3DebugLines* lines);
|
||||
|
||||
/// Add/remove user-specific debug lines and debug text messages
|
||||
b3SharedMemoryCommandHandle b3InitUserDebugDrawAddLine3D(b3PhysicsClientHandle physClient, double fromXYZ[3], double toXYZ[3], double colorRGB[3], double lineWidth, double lifeTime);
|
||||
b3SharedMemoryCommandHandle b3InitUserDebugDrawAddText3D(b3PhysicsClientHandle physClient, const char* txt, double positionXYZ[3], double colorRGB[3], double textSize, double lifeTime);
|
||||
b3SharedMemoryCommandHandle b3InitUserDebugDrawRemove(b3PhysicsClientHandle physClient, int debugItemUniqueId);
|
||||
b3SharedMemoryCommandHandle b3InitUserDebugDrawRemoveAll(b3PhysicsClientHandle physClient);
|
||||
|
||||
b3SharedMemoryCommandHandle b3InitDebugDrawingCommand(b3PhysicsClientHandle physClient);
|
||||
void b3SetDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex, double objectColorRGB[3]);
|
||||
void b3RemoveDebugObjectColor(b3SharedMemoryCommandHandle commandHandle, int objectUniqueId, int linkIndex);
|
||||
|
||||
///All debug items unique Ids are positive: a negative unique Id means failure.
|
||||
int b3GetDebugItemUniqueId(b3SharedMemoryStatusHandle statusHandle);
|
||||
|
||||
|
||||
///request an image from a simulated camera, using a software renderer.
|
||||
b3SharedMemoryCommandHandle b3InitRequestCameraImage(b3PhysicsClientHandle physClient);
|
||||
void b3RequestCameraImageSetCameraMatrices(b3SharedMemoryCommandHandle command, float viewMatrix[16], float projectionMatrix[16]);
|
||||
void b3RequestCameraImageSetViewMatrix(b3SharedMemoryCommandHandle command, const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3]);
|
||||
void b3RequestCameraImageSetViewMatrix2(b3SharedMemoryCommandHandle commandHandle, const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis);
|
||||
void b3RequestCameraImageSetProjectionMatrix(b3SharedMemoryCommandHandle command, float left, float right, float bottom, float top, float nearVal, float farVal);
|
||||
void b3RequestCameraImageSetFOVProjectionMatrix(b3SharedMemoryCommandHandle command, float fov, float aspect, float nearVal, float farVal);
|
||||
void b3RequestCameraImageSetPixelResolution(b3SharedMemoryCommandHandle command, int width, int height );
|
||||
void b3RequestCameraImageSetLightDirection(b3SharedMemoryCommandHandle commandHandle, const float lightDirection[3]);
|
||||
void b3RequestCameraImageSetLightColor(b3SharedMemoryCommandHandle commandHandle, const float lightColor[3]);
|
||||
void b3RequestCameraImageSetLightDistance(b3SharedMemoryCommandHandle commandHandle, float lightDistance);
|
||||
void b3RequestCameraImageSetLightAmbientCoeff(b3SharedMemoryCommandHandle commandHandle, float lightAmbientCoeff);
|
||||
void b3RequestCameraImageSetLightDiffuseCoeff(b3SharedMemoryCommandHandle commandHandle, float lightDiffuseCoeff);
|
||||
void b3RequestCameraImageSetLightSpecularCoeff(b3SharedMemoryCommandHandle commandHandle, float lightSpecularCoeff);
|
||||
void b3RequestCameraImageSetShadow(b3SharedMemoryCommandHandle commandHandle, int hasShadow);
|
||||
void b3RequestCameraImageSelectRenderer(b3SharedMemoryCommandHandle commandHandle, int renderer);
|
||||
void b3GetCameraImageData(b3PhysicsClientHandle physClient, struct b3CameraImageData* imageData);
|
||||
|
||||
///compute a view matrix, helper function for b3RequestCameraImageSetCameraMatrices
|
||||
void b3ComputeViewMatrixFromPositions(const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3], float viewMatrix[16]);
|
||||
void b3ComputeViewMatrixFromYawPitchRoll(const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis, float viewMatrix[16]);
|
||||
|
||||
///compute a projection matrix, helper function for b3RequestCameraImageSetCameraMatrices
|
||||
void b3ComputeProjectionMatrix(float left, float right, float bottom, float top, float nearVal, float farVal, float projectionMatrix[16]);
|
||||
void b3ComputeProjectionMatrixFOV(float fov, float aspect, float nearVal, float farVal, float projectionMatrix[16]);
|
||||
|
||||
|
||||
/* obsolete, please use b3ComputeViewProjectionMatrices */
|
||||
void b3RequestCameraImageSetViewMatrix(b3SharedMemoryCommandHandle command, const float cameraPosition[3], const float cameraTargetPosition[3], const float cameraUp[3]);
|
||||
/* obsolete, please use b3ComputeViewProjectionMatrices */
|
||||
void b3RequestCameraImageSetViewMatrix2(b3SharedMemoryCommandHandle commandHandle, const float cameraTargetPosition[3], float distance, float yaw, float pitch, float roll, int upAxis);
|
||||
/* obsolete, please use b3ComputeViewProjectionMatrices */
|
||||
void b3RequestCameraImageSetProjectionMatrix(b3SharedMemoryCommandHandle command, float left, float right, float bottom, float top, float nearVal, float farVal);
|
||||
/* obsolete, please use b3ComputeViewProjectionMatrices */
|
||||
void b3RequestCameraImageSetFOVProjectionMatrix(b3SharedMemoryCommandHandle command, float fov, float aspect, float nearVal, float farVal);
|
||||
|
||||
|
||||
///request an contact point information
|
||||
b3SharedMemoryCommandHandle b3InitRequestContactPointInformation(b3PhysicsClientHandle physClient);
|
||||
void b3SetContactFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdA);
|
||||
void b3SetContactFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB);
|
||||
void b3SetContactFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA);
|
||||
void b3SetContactFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB);
|
||||
void b3GetContactPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointInfo);
|
||||
|
||||
///compute the closest points between two bodies
|
||||
b3SharedMemoryCommandHandle b3InitClosestDistanceQuery(b3PhysicsClientHandle physClient);
|
||||
void b3SetClosestDistanceFilterBodyA(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdA);
|
||||
void b3SetClosestDistanceFilterLinkA(b3SharedMemoryCommandHandle commandHandle, int linkIndexA);
|
||||
void b3SetClosestDistanceFilterBodyB(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueIdB);
|
||||
void b3SetClosestDistanceFilterLinkB(b3SharedMemoryCommandHandle commandHandle, int linkIndexB);
|
||||
void b3SetClosestDistanceThreshold(b3SharedMemoryCommandHandle commandHandle, double distance);
|
||||
void b3GetClosestPointInformation(b3PhysicsClientHandle physClient, struct b3ContactInformation* contactPointInfo);
|
||||
|
||||
///get all the bodies that touch a given axis aligned bounding box specified in world space (min and max coordinates)
|
||||
b3SharedMemoryCommandHandle b3InitAABBOverlapQuery(b3PhysicsClientHandle physClient, const double aabbMin[3],const double aabbMax[3]);
|
||||
void b3GetAABBOverlapResults(b3PhysicsClientHandle physClient, struct b3AABBOverlapData* data);
|
||||
|
||||
//request visual shape information
|
||||
b3SharedMemoryCommandHandle b3InitRequestVisualShapeInformation(b3PhysicsClientHandle physClient, int bodyUniqueIdA);
|
||||
void b3GetVisualShapeInformation(b3PhysicsClientHandle physClient, struct b3VisualShapeInformation* visualShapeInfo);
|
||||
@@ -109,6 +166,9 @@ int b3PhysicsParamSetDefaultContactERP(b3SharedMemoryCommandHandle commandHandle
|
||||
int b3PhysicsParamSetNumSubSteps(b3SharedMemoryCommandHandle commandHandle, int numSubSteps);
|
||||
int b3PhysicsParamSetRealTimeSimulation(b3SharedMemoryCommandHandle commandHandle, int enableRealTimeSimulation);
|
||||
int b3PhysicsParamSetNumSolverIterations(b3SharedMemoryCommandHandle commandHandle, int numSolverIterations);
|
||||
int b3PhysicsParamSetUseSplitImpulse(b3SharedMemoryCommandHandle commandHandle, int useSplitImpulse);
|
||||
int b3PhysicsParamSetSplitImpulsePenetrationThreshold(b3SharedMemoryCommandHandle commandHandle, double splitImpulsePenetrationThreshold);
|
||||
|
||||
|
||||
//b3PhysicsParamSetInternalSimFlags is for internal/temporary/easter-egg/experimental demo purposes
|
||||
//Use at own risk: magic things may or my not happen when calling this API
|
||||
@@ -128,6 +188,11 @@ int b3LoadUrdfCommandSetStartOrientation(b3SharedMemoryCommandHandle commandHand
|
||||
int b3LoadUrdfCommandSetUseMultiBody(b3SharedMemoryCommandHandle commandHandle, int useMultiBody);
|
||||
int b3LoadUrdfCommandSetUseFixedBase(b3SharedMemoryCommandHandle commandHandle, int useFixedBase);
|
||||
|
||||
b3SharedMemoryCommandHandle b3LoadBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName);
|
||||
b3SharedMemoryCommandHandle b3SaveBulletCommandInit(b3PhysicsClientHandle physClient, const char* fileName);
|
||||
b3SharedMemoryCommandHandle b3LoadMJCFCommandInit(b3PhysicsClientHandle physClient, const char* fileName);
|
||||
|
||||
|
||||
|
||||
///compute the forces to achieve an acceleration, given a state q and qdot using inverse dynamics
|
||||
b3SharedMemoryCommandHandle b3CalculateInverseDynamicsCommandInit(b3PhysicsClientHandle physClient, int bodyIndex,
|
||||
@@ -199,6 +264,9 @@ int b3CreateBoxCommandSetColorRGBA(b3SharedMemoryCommandHandle commandHandle, do
|
||||
b3SharedMemoryCommandHandle b3CreatePoseCommandInit(b3PhysicsClientHandle physClient, int bodyIndex);
|
||||
int b3CreatePoseCommandSetBasePosition(b3SharedMemoryCommandHandle commandHandle, double startPosX,double startPosY,double startPosZ);
|
||||
int b3CreatePoseCommandSetBaseOrientation(b3SharedMemoryCommandHandle commandHandle, double startOrnX,double startOrnY,double startOrnZ, double startOrnW);
|
||||
int b3CreatePoseCommandSetBaseLinearVelocity(b3SharedMemoryCommandHandle commandHandle, double linVel[3]);
|
||||
int b3CreatePoseCommandSetBaseAngularVelocity(b3SharedMemoryCommandHandle commandHandle, double angVel[3]);
|
||||
|
||||
int b3CreatePoseCommandSetJointPositions(b3SharedMemoryCommandHandle commandHandle, int numJointPositions, const double* jointPositions);
|
||||
int b3CreatePoseCommandSetJointPosition(b3PhysicsClientHandle physClient, b3SharedMemoryCommandHandle commandHandle, int jointIndex, double jointPosition);
|
||||
|
||||
@@ -228,7 +296,11 @@ b3SharedMemoryCommandHandle b3ApplyExternalForceCommandInit(b3PhysicsClientHandl
|
||||
void b3ApplyExternalForce(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueId, int linkId, const double force[3], const double position[3], int flags);
|
||||
void b3ApplyExternalTorque(b3SharedMemoryCommandHandle commandHandle, int bodyUniqueId, int linkId, const double torque[3], int flags);
|
||||
|
||||
///experiments of robots interacting with non-rigid objects (such as btSoftBody)
|
||||
b3SharedMemoryCommandHandle b3LoadBunnyCommandInit(b3PhysicsClientHandle physClient);
|
||||
int b3LoadBunnySetScale(b3SharedMemoryCommandHandle commandHandle, double scale);
|
||||
int b3LoadBunnySetMass(b3SharedMemoryCommandHandle commandHandle, double mass);
|
||||
int b3LoadBunnySetCollisionMargin(b3SharedMemoryCommandHandle commandHandle, double collisionMargin);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
@@ -89,10 +89,10 @@ protected:
|
||||
|
||||
virtual void resetCamera()
|
||||
{
|
||||
float dist = 4;
|
||||
float pitch = 193;
|
||||
float yaw = 25;
|
||||
float targetPos[3]={0,0,0.5};//-3,2.8,-2.5};
|
||||
float dist = 4;
|
||||
float pitch = 193;
|
||||
float yaw = 25;
|
||||
float targetPos[3]={0,0,0.5};//-3,2.8,-2.5};
|
||||
m_guiHelper->resetCamera(dist,pitch,yaw,targetPos[0],targetPos[1],targetPos[2]);
|
||||
|
||||
}
|
||||
@@ -481,6 +481,22 @@ void PhysicsClientExample::prepareAndSubmitCommand(int commandId)
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_SET_SHADOW:
|
||||
{
|
||||
b3SharedMemoryCommandHandle commandHandle = b3InitRequestCameraImage(m_physicsClientHandle);
|
||||
float viewMatrix[16];
|
||||
float projectionMatrix[16];
|
||||
m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraProjectionMatrix(projectionMatrix);
|
||||
m_guiHelper->getRenderInterface()->getActiveCamera()->getCameraViewMatrix(viewMatrix);
|
||||
|
||||
b3RequestCameraImageSetCameraMatrices(commandHandle, viewMatrix,projectionMatrix);
|
||||
b3RequestCameraImageSetPixelResolution(commandHandle, camVisualizerWidth,camVisualizerHeight);
|
||||
bool hasShadow = true;
|
||||
b3RequestCameraImageSetShadow(commandHandle, hasShadow);
|
||||
b3SubmitClientCommand(m_physicsClientHandle, commandHandle);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
b3Error("Unknown buttonId");
|
||||
@@ -556,6 +572,7 @@ void PhysicsClientExample::createButtons()
|
||||
createButton("Load URDF",CMD_LOAD_URDF, isTrigger);
|
||||
createButton("Load SDF",CMD_LOAD_SDF, isTrigger);
|
||||
createButton("Save World",CMD_SAVE_WORLD, isTrigger);
|
||||
createButton("Set Shadow",CMD_SET_SHADOW, isTrigger);
|
||||
createButton("Get Camera Image",CMD_REQUEST_CAMERA_IMAGE_DATA,isTrigger);
|
||||
createButton("Step Sim",CMD_STEP_FORWARD_SIMULATION, isTrigger);
|
||||
createButton("Realtime Sim",CMD_CUSTOM_SET_REALTIME_SIMULATION, isTrigger);
|
||||
|
||||
@@ -40,7 +40,7 @@ struct PhysicsClientSharedMemoryInternalData {
|
||||
btAlignedObjectArray<int> m_cachedSegmentationMaskBuffer;
|
||||
|
||||
btAlignedObjectArray<b3ContactPointData> m_cachedContactPoints;
|
||||
|
||||
btAlignedObjectArray<b3OverlappingObject> m_cachedOverlappingObjects;
|
||||
btAlignedObjectArray<b3VisualShapeData> m_cachedVisualShapes;
|
||||
|
||||
btAlignedObjectArray<int> m_bodyIdsRequestInfo;
|
||||
@@ -100,6 +100,10 @@ bool PhysicsClientSharedMemory::getBodyInfo(int bodyUniqueId, struct b3BodyInfo&
|
||||
info.m_baseName = bodyJoints->m_baseName.c_str();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -124,8 +128,11 @@ bool PhysicsClientSharedMemory::getJointInfo(int bodyUniqueId, int jointIndex, b
|
||||
if (bodyJointsPtr && *bodyJointsPtr)
|
||||
{
|
||||
BodyJointInfoCache* bodyJoints = *bodyJointsPtr;
|
||||
info = bodyJoints->m_jointInfo[jointIndex];
|
||||
return true;
|
||||
if ((jointIndex >= 0) && (jointIndex < bodyJoints->m_jointInfo.size()))
|
||||
{
|
||||
info = bodyJoints->m_jointInfo[jointIndex];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -201,6 +208,32 @@ bool PhysicsClientSharedMemory::connect() {
|
||||
b3Error("Cannot connect to shared memory");
|
||||
return false;
|
||||
}
|
||||
#if 0
|
||||
if (m_data->m_isConnected)
|
||||
{
|
||||
//get all existing bodies and body info...
|
||||
|
||||
SharedMemoryCommand& command = m_data->m_testBlock1->m_clientCommands[0];
|
||||
//now transfer the information of the individual objects etc.
|
||||
command.m_type = CMD_REQUEST_BODY_INFO;
|
||||
command.m_sdfRequestInfoArgs.m_bodyUniqueId = 37;
|
||||
submitClientCommand(command);
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
|
||||
const SharedMemoryStatus* status = 0;
|
||||
|
||||
while ((status == 0) && (timeout-- > 0))
|
||||
{
|
||||
status = processServerStatus();
|
||||
|
||||
}
|
||||
|
||||
|
||||
//submitClientCommand(command);
|
||||
|
||||
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -210,7 +243,7 @@ void PhysicsClientSharedMemory::processBodyJointInfo(int bodyUniqueId, const Sha
|
||||
{
|
||||
bParse::btBulletFile bf(
|
||||
&this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[0],
|
||||
serverCmd.m_dataStreamArguments.m_streamChunkLength);
|
||||
serverCmd.m_numDataStreamBytes);
|
||||
bf.setFileDNAisMemoryDNA();
|
||||
bf.parse(false);
|
||||
|
||||
@@ -291,16 +324,17 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CMD_URDF_LOADING_COMPLETED: {
|
||||
|
||||
if (m_data->m_verboseOutput) {
|
||||
b3Printf("Server loading the URDF OK\n");
|
||||
}
|
||||
|
||||
if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0) {
|
||||
if (serverCmd.m_numDataStreamBytes > 0) {
|
||||
bParse::btBulletFile bf(
|
||||
this->m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor,
|
||||
serverCmd.m_dataStreamArguments.m_streamChunkLength);
|
||||
serverCmd.m_numDataStreamBytes);
|
||||
bf.setFileDNAisMemoryDNA();
|
||||
bf.parse(false);
|
||||
int bodyUniqueId = serverCmd.m_dataStreamArguments.m_bodyUniqueId;
|
||||
@@ -592,6 +626,30 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() {
|
||||
b3Warning("Inverse Dynamics computations failed");
|
||||
break;
|
||||
}
|
||||
case CMD_REQUEST_AABB_OVERLAP_FAILED:
|
||||
{
|
||||
b3Warning("Overlapping object query failed");
|
||||
break;
|
||||
}
|
||||
case CMD_REQUEST_AABB_OVERLAP_COMPLETED:
|
||||
{
|
||||
if (m_data->m_verboseOutput)
|
||||
{
|
||||
b3Printf("Overlapping object request completed");
|
||||
}
|
||||
|
||||
int startOverlapIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex;
|
||||
int numOverlapCopied = serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied;
|
||||
m_data->m_cachedOverlappingObjects.resize(startOverlapIndex + numOverlapCopied);
|
||||
b3OverlappingObject* objects = (b3OverlappingObject*)m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor;
|
||||
|
||||
for (int i = 0; i < numOverlapCopied; i++)
|
||||
{
|
||||
m_data->m_cachedOverlappingObjects[startOverlapIndex + i] = objects[i];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case CMD_CONTACT_POINT_INFORMATION_COMPLETED:
|
||||
{
|
||||
if (m_data->m_verboseOutput)
|
||||
@@ -675,6 +733,43 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() {
|
||||
b3Warning("Load texture failed");
|
||||
break;
|
||||
}
|
||||
case CMD_BULLET_LOADING_COMPLETED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_BULLET_LOADING_FAILED:
|
||||
{
|
||||
b3Warning("Load .bullet failed");
|
||||
break;
|
||||
}
|
||||
case CMD_BULLET_SAVING_FAILED:
|
||||
{
|
||||
b3Warning("Save .bullet failed");
|
||||
break;
|
||||
}
|
||||
case CMD_MJCF_LOADING_FAILED:
|
||||
{
|
||||
b3Warning("Load .mjcf failed");
|
||||
break;
|
||||
}
|
||||
case CMD_USER_DEBUG_DRAW_COMPLETED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_USER_DEBUG_DRAW_FAILED:
|
||||
{
|
||||
b3Warning("User debug draw failed");
|
||||
break;
|
||||
}
|
||||
case CMD_USER_CONSTRAINT_COMPLETED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_USER_CONSTRAINT_FAILED:
|
||||
{
|
||||
b3Warning("createConstraint failed");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
b3Error("Unknown server status %d\n", serverCmd.m_type);
|
||||
btAssert(0);
|
||||
@@ -736,6 +831,18 @@ const SharedMemoryStatus* PhysicsClientSharedMemory::processServerStatus() {
|
||||
m_data->m_lastServerStatus = m_data->m_tempBackupServerStatus;
|
||||
}
|
||||
}
|
||||
|
||||
if (serverCmd.m_type == CMD_REQUEST_AABB_OVERLAP_COMPLETED)
|
||||
{
|
||||
SharedMemoryCommand& command = m_data->m_testBlock1->m_clientCommands[0];
|
||||
if (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied)
|
||||
{
|
||||
command.m_type = CMD_REQUEST_AABB_OVERLAP;
|
||||
command.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex + serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied;
|
||||
submitClientCommand(command);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (serverCmd.m_type == CMD_CONTACT_POINT_INFORMATION_COMPLETED)
|
||||
{
|
||||
@@ -869,6 +976,14 @@ void PhysicsClientSharedMemory::getCachedContactPointInformation(struct b3Contac
|
||||
|
||||
}
|
||||
|
||||
void PhysicsClientSharedMemory::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects)
|
||||
{
|
||||
overlappingObjects->m_numOverlappingObjects = m_data->m_cachedOverlappingObjects.size();
|
||||
overlappingObjects->m_overlappingObjects = m_data->m_cachedOverlappingObjects.size() ?
|
||||
&m_data->m_cachedOverlappingObjects[0] : 0;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsClientSharedMemory::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo)
|
||||
{
|
||||
visualShapesInfo->m_numVisualShapes = m_data->m_cachedVisualShapes.size();
|
||||
|
||||
@@ -12,7 +12,7 @@ class PhysicsClientSharedMemory : public PhysicsClient {
|
||||
protected:
|
||||
virtual void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem);
|
||||
void processBodyJointInfo(int bodyUniqueId, const struct SharedMemoryStatus& serverCmd);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
PhysicsClientSharedMemory();
|
||||
@@ -57,6 +57,8 @@ public:
|
||||
|
||||
virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData);
|
||||
|
||||
virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects);
|
||||
|
||||
virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo);
|
||||
};
|
||||
|
||||
|
||||
27
examples/SharedMemory/PhysicsClientSharedMemory2.cpp
Normal file
27
examples/SharedMemory/PhysicsClientSharedMemory2.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
#include "PhysicsClientSharedMemory2.h"
|
||||
#include "PosixSharedMemory.h"
|
||||
#include "Win32SharedMemory.h"
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#include "Bullet3Common/b3Scalar.h"
|
||||
|
||||
#include "SharedMemoryCommandProcessor.h"
|
||||
|
||||
|
||||
PhysicsClientSharedMemory2::PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc)
|
||||
:PhysicsDirect(proc)
|
||||
{
|
||||
m_proc = proc;
|
||||
}
|
||||
PhysicsClientSharedMemory2::~PhysicsClientSharedMemory2()
|
||||
{
|
||||
}
|
||||
|
||||
void PhysicsClientSharedMemory2::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem)
|
||||
{
|
||||
if (m_proc)
|
||||
{
|
||||
m_proc->setSharedMemoryInterface(sharedMem);
|
||||
}
|
||||
}
|
||||
|
||||
18
examples/SharedMemory/PhysicsClientSharedMemory2.h
Normal file
18
examples/SharedMemory/PhysicsClientSharedMemory2.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
#define PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
|
||||
#include "PhysicsDirect.h"
|
||||
|
||||
class PhysicsClientSharedMemory2 : public PhysicsDirect
|
||||
{
|
||||
class SharedMemoryCommandProcessor* m_proc;
|
||||
|
||||
public:
|
||||
PhysicsClientSharedMemory2(SharedMemoryCommandProcessor* proc);
|
||||
virtual ~PhysicsClientSharedMemory2();
|
||||
|
||||
void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem);
|
||||
|
||||
};
|
||||
|
||||
#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
19
examples/SharedMemory/PhysicsClientSharedMemory2_C_API.cpp
Normal file
19
examples/SharedMemory/PhysicsClientSharedMemory2_C_API.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "PhysicsClientSharedMemory2_C_API.h"
|
||||
|
||||
#include "PhysicsDirect.h"
|
||||
#include "SharedMemoryCommandProcessor.h"
|
||||
|
||||
b3PhysicsClientHandle b3ConnectSharedMemory2(int key)
|
||||
{
|
||||
|
||||
SharedMemoryCommandProcessor* cmdProc = new SharedMemoryCommandProcessor();
|
||||
cmdProc->setSharedMemoryKey(key);
|
||||
PhysicsDirect* cl = new PhysicsDirect(cmdProc);
|
||||
|
||||
cl->setSharedMemoryKey(key);
|
||||
|
||||
cl->connect();
|
||||
|
||||
return (b3PhysicsClientHandle)cl;
|
||||
}
|
||||
|
||||
18
examples/SharedMemory/PhysicsClientSharedMemory2_C_API.h
Normal file
18
examples/SharedMemory/PhysicsClientSharedMemory2_C_API.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
#define PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
|
||||
#include "PhysicsClientC_API.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
b3PhysicsClientHandle b3ConnectSharedMemory2(int key);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //PHYSICS_CLIENT_SHARED_MEMORY2_H
|
||||
11
examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp
Normal file
11
examples/SharedMemory/PhysicsClientSharedMemory_C_API.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "PhysicsClientSharedMemory_C_API.h"
|
||||
|
||||
#include "PhysicsClientSharedMemory.h"
|
||||
|
||||
b3PhysicsClientHandle b3ConnectSharedMemory(int key)
|
||||
{
|
||||
PhysicsClientSharedMemory* cl = new PhysicsClientSharedMemory();
|
||||
cl->setSharedMemoryKey(key);
|
||||
cl->connect();
|
||||
return (b3PhysicsClientHandle)cl;
|
||||
}
|
||||
16
examples/SharedMemory/PhysicsClientSharedMemory_C_API.h
Normal file
16
examples/SharedMemory/PhysicsClientSharedMemory_C_API.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef PHYSICS_CLIENT_SHARED_MEMORY_H
|
||||
#define PHYSICS_CLIENT_SHARED_MEMORY_H
|
||||
|
||||
#include "PhysicsClientC_API.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
b3PhysicsClientHandle b3ConnectSharedMemory(int key);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //PHYSICS_CLIENT_SHARED_MEMORY_H
|
||||
592
examples/SharedMemory/PhysicsClientUDP.cpp
Normal file
592
examples/SharedMemory/PhysicsClientUDP.cpp
Normal file
@@ -0,0 +1,592 @@
|
||||
#include "PhysicsClientUDP.h"
|
||||
#include <enet/enet.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../Utils/b3Clock.h"
|
||||
#include "PhysicsClient.h"
|
||||
//#include "LinearMath/btVector3.h"
|
||||
#include "SharedMemoryCommands.h"
|
||||
#include <string>
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#include "../MultiThreading/b3ThreadSupportInterface.h"
|
||||
void UDPThreadFunc(void* userPtr, void* lsMemory);
|
||||
void* UDPlsMemoryFunc();
|
||||
bool gVerboseNetworkMessagesClient = false;
|
||||
|
||||
#ifndef _WIN32
|
||||
#include "../MultiThreading/b3PosixThreadSupport.h"
|
||||
|
||||
b3ThreadSupportInterface* createUDPThreadSupport(int numThreads)
|
||||
{
|
||||
b3PosixThreadSupport::ThreadConstructionInfo constructionInfo("UDPThread",
|
||||
UDPThreadFunc,
|
||||
UDPlsMemoryFunc,
|
||||
numThreads);
|
||||
b3ThreadSupportInterface* threadSupport = new b3PosixThreadSupport(constructionInfo);
|
||||
|
||||
return threadSupport;
|
||||
|
||||
}
|
||||
|
||||
|
||||
#elif defined( _WIN32)
|
||||
#include "../MultiThreading/b3Win32ThreadSupport.h"
|
||||
|
||||
b3ThreadSupportInterface* createUDPThreadSupport(int numThreads)
|
||||
{
|
||||
b3Win32ThreadSupport::Win32ThreadConstructionInfo threadConstructionInfo("UDPThread", UDPThreadFunc, UDPlsMemoryFunc, numThreads);
|
||||
b3Win32ThreadSupport* threadSupport = new b3Win32ThreadSupport(threadConstructionInfo);
|
||||
return threadSupport;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
struct UDPThreadLocalStorage
|
||||
{
|
||||
int threadId;
|
||||
};
|
||||
|
||||
|
||||
|
||||
unsigned int b3DeserializeInt(const unsigned char* input)
|
||||
{
|
||||
unsigned int tmp = (input[3] << 24) + (input[2] << 16) + (input[1] << 8) + input[0];
|
||||
return tmp;
|
||||
}
|
||||
|
||||
struct UdpNetworkedInternalData
|
||||
{
|
||||
ENetHost* m_client;
|
||||
ENetAddress m_address;
|
||||
ENetPeer* m_peer;
|
||||
ENetEvent m_event;
|
||||
bool m_isConnected;
|
||||
|
||||
b3ThreadSupportInterface* m_threadSupport;
|
||||
|
||||
b3CriticalSection* m_cs;
|
||||
|
||||
UdpNetworkedInternalData* m_udpInternalData;
|
||||
|
||||
|
||||
SharedMemoryCommand m_clientCmd;
|
||||
bool m_hasCommand;
|
||||
|
||||
bool m_hasStatus;
|
||||
SharedMemoryStatus m_lastStatus;
|
||||
b3AlignedObjectArray<char> m_stream;
|
||||
|
||||
std::string m_hostName;
|
||||
int m_port;
|
||||
|
||||
UdpNetworkedInternalData()
|
||||
:m_client(0),
|
||||
m_peer(0),
|
||||
m_isConnected(false),
|
||||
m_threadSupport(0),
|
||||
m_hasCommand(false),
|
||||
m_hasStatus(false)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool connectUDP()
|
||||
{
|
||||
if (m_isConnected)
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
if (enet_initialize() != 0)
|
||||
{
|
||||
fprintf(stderr, "Error initialising enet");
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
}
|
||||
|
||||
m_client = enet_host_create(NULL, /* create a client host */
|
||||
1, /* number of clients */
|
||||
2, /* number of channels */
|
||||
57600 / 8, /* incoming bandwith */
|
||||
14400 / 8); /* outgoing bandwith */
|
||||
|
||||
if (m_client == NULL) {
|
||||
fprintf(stderr, "Could not create client host");
|
||||
return false;
|
||||
}
|
||||
|
||||
enet_address_set_host(&m_address, m_hostName.c_str());
|
||||
m_address.port = m_port;
|
||||
|
||||
m_peer = enet_host_connect(m_client,
|
||||
&m_address, /* address to connect to */
|
||||
2, /* number of channels */
|
||||
0); /* user data supplied to
|
||||
the receiving host */
|
||||
|
||||
if (m_peer == NULL) {
|
||||
fprintf(stderr, "No available peers for initiating an ENet "
|
||||
"connection.\n");
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/* Try to connect to server within 5 seconds */
|
||||
if (enet_host_service(m_client, &m_event, 5000) > 0 &&
|
||||
m_event.type == ENET_EVENT_TYPE_CONNECT)
|
||||
{
|
||||
puts("Connection to server succeeded.");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Either the 5 seconds are up or a disconnect event was */
|
||||
/* received. Reset the peer in the event the 5 seconds */
|
||||
/* had run out without any significant event. */
|
||||
enet_peer_reset(m_peer);
|
||||
|
||||
fprintf(stderr, "Connection to server failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int serviceResult = enet_host_service(m_client, &m_event, 0);
|
||||
|
||||
if (serviceResult > 0)
|
||||
{
|
||||
switch (m_event.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
printf("A new client connected from %x:%u.\n",
|
||||
m_event.peer->address.host,
|
||||
m_event.peer->address.port);
|
||||
m_event.peer->data = (void*)"New User";
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
|
||||
if (gVerboseNetworkMessagesClient)
|
||||
{
|
||||
printf("A packet of length %u containing '%s' was "
|
||||
"received from %s on channel %u.\n",
|
||||
m_event.packet->dataLength,
|
||||
m_event.packet->data,
|
||||
m_event.peer->data,
|
||||
m_event.channelID);
|
||||
}
|
||||
/* Clean up the packet now that we're done using it.
|
||||
> */
|
||||
enet_packet_destroy(m_event.packet);
|
||||
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
printf("%s disconected.\n", m_event.peer->data);
|
||||
|
||||
break;
|
||||
default:
|
||||
{
|
||||
printf("unknown event type: %d.\n", m_event.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (serviceResult > 0)
|
||||
{
|
||||
puts("Error with servicing the client");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_isConnected = true;
|
||||
return m_isConnected;
|
||||
}
|
||||
|
||||
bool checkData()
|
||||
{
|
||||
bool hasStatus = false;
|
||||
|
||||
int serviceResult = enet_host_service(m_client, &m_event, 0);
|
||||
|
||||
if (serviceResult > 0)
|
||||
{
|
||||
switch (m_event.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
printf("A new client connected from %x:%u.\n",
|
||||
m_event.peer->address.host,
|
||||
m_event.peer->address.port);
|
||||
|
||||
m_event.peer->data = (void*)"New User";
|
||||
break;
|
||||
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
{
|
||||
if (gVerboseNetworkMessagesClient)
|
||||
{
|
||||
printf("A packet of length %u containing '%s' was "
|
||||
"received from %s on channel %u.\n",
|
||||
m_event.packet->dataLength,
|
||||
m_event.packet->data,
|
||||
m_event.peer->data,
|
||||
m_event.channelID);
|
||||
}
|
||||
|
||||
int packetSizeInBytes = b3DeserializeInt(m_event.packet->data);
|
||||
|
||||
if (packetSizeInBytes == m_event.packet->dataLength)
|
||||
{
|
||||
|
||||
SharedMemoryStatus* statPtr = (SharedMemoryStatus*)&m_event.packet->data[4];
|
||||
m_lastStatus = *statPtr;
|
||||
int streamOffsetInBytes = 4 + sizeof(SharedMemoryStatus);
|
||||
int numStreamBytes = packetSizeInBytes - streamOffsetInBytes;
|
||||
m_stream.resize(numStreamBytes);
|
||||
for (int i = 0; i < numStreamBytes; i++)
|
||||
{
|
||||
m_stream[i] = m_event.packet->data[i + streamOffsetInBytes];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("unknown status message received\n");
|
||||
}
|
||||
enet_packet_destroy(m_event.packet);
|
||||
hasStatus = true;
|
||||
break;
|
||||
}
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
{
|
||||
printf("%s disconected.\n", m_event.peer->data);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
printf("unknown event type: %d.\n", m_event.type);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (serviceResult > 0)
|
||||
{
|
||||
puts("Error with servicing the client");
|
||||
}
|
||||
|
||||
return hasStatus;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
enum UDPThreadEnums
|
||||
{
|
||||
eUDPRequestTerminate = 13,
|
||||
eUDPIsUnInitialized,
|
||||
eUDPIsInitialized,
|
||||
eUDPInitializationFailed,
|
||||
eUDPHasTerminated
|
||||
};
|
||||
|
||||
|
||||
|
||||
enum UDPCommandEnums
|
||||
{
|
||||
eUDPIdle = 13,
|
||||
eUDP_ConnectRequest,
|
||||
eUDP_Connected,
|
||||
eUDP_ConnectionFailed,
|
||||
eUDP_DisconnectRequest,
|
||||
eUDP_Disconnected,
|
||||
|
||||
};
|
||||
|
||||
void UDPThreadFunc(void* userPtr, void* lsMemory)
|
||||
{
|
||||
printf("UDPThreadFunc thread started\n");
|
||||
UDPThreadLocalStorage* localStorage = (UDPThreadLocalStorage*)lsMemory;
|
||||
|
||||
UdpNetworkedInternalData* args = (UdpNetworkedInternalData*)userPtr;
|
||||
int workLeft = true;
|
||||
b3Clock clock;
|
||||
clock.reset();
|
||||
bool init = true;
|
||||
if (init)
|
||||
{
|
||||
|
||||
args->m_cs->lock();
|
||||
args->m_cs->setSharedParam(0, eUDPIsInitialized);
|
||||
args->m_cs->unlock();
|
||||
|
||||
|
||||
double deltaTimeInSeconds = 0;
|
||||
|
||||
do
|
||||
{
|
||||
deltaTimeInSeconds += double(clock.getTimeMicroseconds()) / 1000000.;
|
||||
|
||||
if (deltaTimeInSeconds<(1. / 5000.))
|
||||
{
|
||||
// b3Clock::usleep(250);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
clock.reset();
|
||||
deltaTimeInSeconds = 0.f;
|
||||
switch (args->m_cs->getSharedParam(1))
|
||||
{
|
||||
case eUDP_ConnectRequest:
|
||||
{
|
||||
bool connected = args->connectUDP();
|
||||
if (connected)
|
||||
{
|
||||
args->m_cs->setSharedParam(1, eUDP_Connected);
|
||||
}
|
||||
else
|
||||
{
|
||||
args->m_cs->setSharedParam(1, eUDP_ConnectionFailed);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
if (args->m_isConnected)
|
||||
{
|
||||
|
||||
args->m_cs->lock();
|
||||
bool hasCommand = args->m_hasCommand;
|
||||
args->m_cs->unlock();
|
||||
|
||||
|
||||
if (hasCommand)
|
||||
{
|
||||
|
||||
int sz = sizeof(SharedMemoryCommand);
|
||||
ENetPacket *packet = enet_packet_create(&args->m_clientCmd, sz, ENET_PACKET_FLAG_RELIABLE);
|
||||
int res = enet_peer_send(args->m_peer, 0, packet);
|
||||
args->m_cs->lock();
|
||||
args->m_hasCommand = false;
|
||||
args->m_cs->unlock();
|
||||
}
|
||||
|
||||
|
||||
bool hasNewStatus = args->checkData();
|
||||
if (hasNewStatus)
|
||||
{
|
||||
if (args->m_hasStatus)
|
||||
{
|
||||
//overflow: last status hasn't been processed yet
|
||||
b3Assert(0);
|
||||
printf("Error: received new status but previous status not processed yet");
|
||||
}
|
||||
else
|
||||
{
|
||||
args->m_cs->lock();
|
||||
args->m_hasStatus = hasNewStatus;
|
||||
args->m_cs->unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} while (args->m_cs->getSharedParam(0) != eUDPRequestTerminate);
|
||||
}
|
||||
else
|
||||
{
|
||||
args->m_cs->lock();
|
||||
args->m_cs->setSharedParam(0, eUDPInitializationFailed);
|
||||
args->m_cs->unlock();
|
||||
}
|
||||
|
||||
|
||||
printf("finished\n");
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void* UDPlsMemoryFunc()
|
||||
{
|
||||
//don't create local store memory, just return 0
|
||||
return new UDPThreadLocalStorage;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
UdpNetworkedPhysicsProcessor::UdpNetworkedPhysicsProcessor(const char* hostName, int port)
|
||||
{
|
||||
m_data = new UdpNetworkedInternalData;
|
||||
if (hostName)
|
||||
{
|
||||
m_data->m_hostName = hostName;
|
||||
}
|
||||
m_data->m_port = port;
|
||||
|
||||
}
|
||||
|
||||
UdpNetworkedPhysicsProcessor::~UdpNetworkedPhysicsProcessor()
|
||||
{
|
||||
disconnect();
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
bool UdpNetworkedPhysicsProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
|
||||
{
|
||||
int sz = sizeof(SharedMemoryCommand);
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
|
||||
m_data->m_cs->lock();
|
||||
m_data->m_clientCmd = clientCmd;
|
||||
m_data->m_hasCommand = true;
|
||||
m_data->m_cs->unlock();
|
||||
|
||||
while (m_data->m_hasCommand && (timeout-- > 0))
|
||||
{
|
||||
// b3Clock::usleep(100);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
timeout = 1024 * 1024 * 1024;
|
||||
|
||||
bool hasStatus = false;
|
||||
|
||||
const SharedMemoryStatus* stat = 0;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
hasStatus = receiveStatus(serverStatusOut, bufferServerToClient, bufferSizeInBytes);
|
||||
b3Clock::usleep(100);
|
||||
}
|
||||
return hasStatus;
|
||||
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UdpNetworkedPhysicsProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
|
||||
{
|
||||
bool hasStatus = false;
|
||||
if (m_data->m_hasStatus)
|
||||
{
|
||||
hasStatus = true;
|
||||
serverStatusOut = m_data->m_lastStatus;
|
||||
int numStreamBytes = m_data->m_stream.size();
|
||||
|
||||
if (numStreamBytes < bufferSizeInBytes)
|
||||
{
|
||||
for (int i = 0; i < numStreamBytes; i++)
|
||||
{
|
||||
bufferServerToClient[i] = m_data->m_stream[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: steam buffer overflow\n");
|
||||
}
|
||||
|
||||
m_data->m_cs->lock();
|
||||
m_data->m_hasStatus = false;
|
||||
m_data->m_cs->unlock();
|
||||
}
|
||||
|
||||
|
||||
return hasStatus;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void UdpNetworkedPhysicsProcessor::renderScene()
|
||||
{
|
||||
}
|
||||
|
||||
void UdpNetworkedPhysicsProcessor::physicsDebugDraw(int debugDrawFlags)
|
||||
{
|
||||
}
|
||||
|
||||
void UdpNetworkedPhysicsProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper)
|
||||
{
|
||||
}
|
||||
|
||||
bool UdpNetworkedPhysicsProcessor::isConnected() const
|
||||
{
|
||||
return m_data->m_isConnected;
|
||||
}
|
||||
|
||||
|
||||
bool UdpNetworkedPhysicsProcessor::connect()
|
||||
{
|
||||
if (m_data->m_threadSupport==0)
|
||||
{
|
||||
m_data->m_threadSupport = createUDPThreadSupport(1);
|
||||
|
||||
m_data->m_cs = m_data->m_threadSupport->createCriticalSection();
|
||||
m_data->m_cs->setSharedParam(0, eUDPIsUnInitialized);
|
||||
m_data->m_threadSupport->runTask(B3_THREAD_SCHEDULE_TASK, (void*) m_data, 0);
|
||||
|
||||
while (m_data->m_cs->getSharedParam(0) == eUDPIsUnInitialized)
|
||||
{
|
||||
b3Clock::usleep(1000);
|
||||
}
|
||||
|
||||
m_data->m_cs->lock();
|
||||
m_data->m_cs->setSharedParam(1, eUDP_ConnectRequest);
|
||||
m_data->m_cs->unlock();
|
||||
|
||||
while (m_data->m_cs->getSharedParam(1) == eUDP_ConnectRequest)
|
||||
{
|
||||
b3Clock::usleep(1000);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UdpNetworkedPhysicsProcessor::disconnect()
|
||||
{
|
||||
if (m_data->m_threadSupport)
|
||||
{
|
||||
m_data->m_cs->lock();
|
||||
m_data->m_cs->setSharedParam(0, eUDPRequestTerminate);
|
||||
m_data->m_cs->unlock();
|
||||
|
||||
int numActiveThreads = 1;
|
||||
|
||||
while (numActiveThreads)
|
||||
{
|
||||
int arg0, arg1;
|
||||
if (m_data->m_threadSupport->isTaskCompleted(&arg0, &arg1, 0))
|
||||
{
|
||||
numActiveThreads--;
|
||||
printf("numActiveThreads = %d\n", numActiveThreads);
|
||||
}
|
||||
else
|
||||
{
|
||||
b3Clock::usleep(1000);
|
||||
}
|
||||
};
|
||||
|
||||
printf("stopping threads\n");
|
||||
|
||||
delete m_data->m_threadSupport;
|
||||
m_data->m_threadSupport = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
37
examples/SharedMemory/PhysicsClientUDP.h
Normal file
37
examples/SharedMemory/PhysicsClientUDP.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef PHYSICS_CLIENT_UDP_H
|
||||
#define PHYSICS_CLIENT_UDP_H
|
||||
|
||||
#include "PhysicsDirect.h"
|
||||
#include "PhysicsServerCommandProcessor.h"
|
||||
|
||||
class UdpNetworkedPhysicsProcessor : public PhysicsCommandProcessorInterface
|
||||
{
|
||||
|
||||
struct UdpNetworkedInternalData* m_data;
|
||||
|
||||
public:
|
||||
UdpNetworkedPhysicsProcessor(const char* hostName, int port);
|
||||
|
||||
virtual ~UdpNetworkedPhysicsProcessor();
|
||||
|
||||
virtual bool connect();
|
||||
|
||||
virtual void disconnect();
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
virtual void renderScene();
|
||||
|
||||
virtual void physicsDebugDraw(int debugDrawFlags);
|
||||
|
||||
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif //PHYSICS_CLIENT_UDP_H
|
||||
|
||||
21
examples/SharedMemory/PhysicsClientUDP_C_API.cpp
Normal file
21
examples/SharedMemory/PhysicsClientUDP_C_API.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
|
||||
#include "PhysicsClientUDP_C_API.h"
|
||||
#include "PhysicsClientUDP.h"
|
||||
#include "PhysicsDirect.h"
|
||||
#include <stdio.h>
|
||||
|
||||
//think more about naming. The b3ConnectPhysicsLoopback
|
||||
b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port)
|
||||
{
|
||||
|
||||
UdpNetworkedPhysicsProcessor* udp = new UdpNetworkedPhysicsProcessor(hostName, port);
|
||||
|
||||
PhysicsDirect* direct = new PhysicsDirect(udp);
|
||||
|
||||
bool connected = direct->connect();
|
||||
printf("direct!\n");
|
||||
return (b3PhysicsClientHandle)direct;
|
||||
}
|
||||
|
||||
|
||||
|
||||
19
examples/SharedMemory/PhysicsClientUDP_C_API.h
Normal file
19
examples/SharedMemory/PhysicsClientUDP_C_API.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef PHYSICS_CLIENT_UDP_C_API_H
|
||||
#define PHYSICS_CLIENT_UDP_C_API_H
|
||||
|
||||
#include "PhysicsClientC_API.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
///send physics commands using UDP networking
|
||||
b3PhysicsClientHandle b3ConnectPhysicsUDP(const char* hostName, int port);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif //PHYSICS_CLIENT_UDP_C_API_H
|
||||
27
examples/SharedMemory/PhysicsCommandProcessorInterface.h
Normal file
27
examples/SharedMemory/PhysicsCommandProcessorInterface.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef PHYSICS_COMMAND_PROCESSOR_INTERFACE_H
|
||||
#define PHYSICS_COMMAND_PROCESSOR_INTERFACE_H
|
||||
|
||||
class PhysicsCommandProcessorInterface
|
||||
{
|
||||
|
||||
public:
|
||||
virtual ~PhysicsCommandProcessorInterface() {}
|
||||
|
||||
virtual bool connect()=0;
|
||||
|
||||
virtual void disconnect() = 0;
|
||||
|
||||
virtual bool isConnected() const = 0;
|
||||
|
||||
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0;
|
||||
|
||||
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes) = 0;
|
||||
|
||||
virtual void renderScene() = 0;
|
||||
virtual void physicsDebugDraw(int debugDrawFlags) = 0;
|
||||
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //PHYSICS_COMMAND_PROCESSOR_INTERFACE_H
|
||||
@@ -3,7 +3,9 @@
|
||||
#include "PhysicsClientSharedMemory.h"
|
||||
#include "../CommonInterfaces/CommonGUIHelperInterface.h"
|
||||
#include "SharedMemoryCommands.h"
|
||||
#include "PhysicsServerCommandProcessor.h"
|
||||
#include "PhysicsCommandProcessorInterface.h"
|
||||
|
||||
|
||||
#include "LinearMath/btHashMap.h"
|
||||
#include "LinearMath/btAlignedObjectArray.h"
|
||||
#include "../../Extras/Serialize/BulletFileLoader/btBulletFile.h"
|
||||
@@ -21,6 +23,7 @@ struct PhysicsDirectInternalData
|
||||
{
|
||||
DummyGUIHelper m_noGfx;
|
||||
|
||||
btAlignedObjectArray<char> m_serverDNA;
|
||||
SharedMemoryCommand m_command;
|
||||
SharedMemoryStatus m_serverStatus;
|
||||
bool m_hasStatus;
|
||||
@@ -41,29 +44,38 @@ struct PhysicsDirectInternalData
|
||||
btAlignedObjectArray<int> m_cachedSegmentationMask;
|
||||
|
||||
btAlignedObjectArray<b3ContactPointData> m_cachedContactPoints;
|
||||
|
||||
btAlignedObjectArray<b3OverlappingObject> m_cachedOverlappingObjects;
|
||||
|
||||
btAlignedObjectArray<b3VisualShapeData> m_cachedVisualShapes;
|
||||
|
||||
PhysicsServerCommandProcessor* m_commandProcessor;
|
||||
PhysicsCommandProcessorInterface* m_commandProcessor;
|
||||
bool m_ownsCommandProcessor;
|
||||
|
||||
PhysicsDirectInternalData()
|
||||
:m_hasStatus(false),
|
||||
m_verboseOutput(false)
|
||||
m_verboseOutput(false),
|
||||
m_ownsCommandProcessor(false)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
PhysicsDirect::PhysicsDirect()
|
||||
PhysicsDirect::PhysicsDirect(PhysicsCommandProcessorInterface* physSdk)
|
||||
{
|
||||
m_data = new PhysicsDirectInternalData;
|
||||
m_data->m_commandProcessor = new PhysicsServerCommandProcessor;
|
||||
|
||||
|
||||
m_data->m_commandProcessor = physSdk;
|
||||
m_data->m_ownsCommandProcessor = false;
|
||||
}
|
||||
|
||||
PhysicsDirect::~PhysicsDirect()
|
||||
{
|
||||
delete m_data->m_commandProcessor;
|
||||
if (m_data->m_commandProcessor->isConnected())
|
||||
{
|
||||
m_data->m_commandProcessor->disconnect();
|
||||
}
|
||||
if (m_data->m_ownsCommandProcessor)
|
||||
{
|
||||
delete m_data->m_commandProcessor;
|
||||
}
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
@@ -71,23 +83,51 @@ PhysicsDirect::~PhysicsDirect()
|
||||
// return true if connection succesfull, can also check 'isConnected'
|
||||
bool PhysicsDirect::connect()
|
||||
{
|
||||
bool connected = m_data->m_commandProcessor->connect();
|
||||
m_data->m_commandProcessor->setGuiHelper(&m_data->m_noGfx);
|
||||
|
||||
return true;
|
||||
|
||||
//also request serialization data
|
||||
{
|
||||
SharedMemoryCommand command;
|
||||
command.m_type = CMD_REQUEST_INTERNAL_DATA;
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
if (hasStatus)
|
||||
{
|
||||
postProcessStatus(m_data->m_serverStatus);
|
||||
}
|
||||
else
|
||||
{
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return connected;
|
||||
}
|
||||
|
||||
// return true if connection succesfull, can also check 'isConnected'
|
||||
bool PhysicsDirect::connect(struct GUIHelperInterface* guiHelper)
|
||||
{
|
||||
bool connected = m_data->m_commandProcessor->connect();
|
||||
|
||||
m_data->m_commandProcessor->setGuiHelper(guiHelper);
|
||||
|
||||
return true;
|
||||
return connected;
|
||||
}
|
||||
|
||||
void PhysicsDirect::renderScene()
|
||||
{
|
||||
m_data->m_commandProcessor->renderScene();
|
||||
}
|
||||
|
||||
void PhysicsDirect::debugDraw(int debugDrawMode)
|
||||
{
|
||||
m_data->m_commandProcessor->physicsDebugDraw(debugDrawMode);
|
||||
@@ -96,21 +136,31 @@ void PhysicsDirect::debugDraw(int debugDrawMode)
|
||||
////todo: rename to 'disconnect'
|
||||
void PhysicsDirect::disconnectSharedMemory()
|
||||
{
|
||||
m_data->m_commandProcessor->disconnect();
|
||||
m_data->m_commandProcessor->setGuiHelper(0);
|
||||
}
|
||||
|
||||
bool PhysicsDirect::isConnected() const
|
||||
{
|
||||
return true;
|
||||
return m_data->m_commandProcessor->isConnected();
|
||||
}
|
||||
|
||||
// return non-null if there is a status, nullptr otherwise
|
||||
const SharedMemoryStatus* PhysicsDirect::processServerStatus()
|
||||
{
|
||||
|
||||
if (!m_data->m_hasStatus)
|
||||
{
|
||||
m_data->m_hasStatus = m_data->m_commandProcessor->receiveStatus(m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
SharedMemoryStatus* stat = 0;
|
||||
if (m_data->m_hasStatus)
|
||||
{
|
||||
stat = &m_data->m_serverStatus;
|
||||
|
||||
postProcessStatus(m_data->m_serverStatus);
|
||||
|
||||
m_data->m_hasStatus = false;
|
||||
}
|
||||
return stat;
|
||||
@@ -136,7 +186,19 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma
|
||||
{
|
||||
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
|
||||
if (hasStatus)
|
||||
{
|
||||
btAssert(m_data->m_serverStatus.m_type == CMD_DEBUG_LINES_COMPLETED);
|
||||
@@ -184,6 +246,8 @@ bool PhysicsDirect::processDebugLines(const struct SharedMemoryCommand& orgComma
|
||||
|
||||
if (serverCmd.m_sendDebugLinesArgs.m_numRemainingDebugLines > 0)
|
||||
{
|
||||
m_data->m_hasStatus = false;
|
||||
|
||||
command.m_type = CMD_REQUEST_DEBUG_LINES;
|
||||
command.m_requestDebugLinesArguments.m_startingLineIndex =
|
||||
serverCmd.m_sendDebugLinesArgs.m_numDebugLines +
|
||||
@@ -204,6 +268,17 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org
|
||||
do
|
||||
{
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
if (hasStatus)
|
||||
{
|
||||
@@ -223,6 +298,8 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org
|
||||
|
||||
if (serverCmd.m_sendVisualShapeArgs.m_numRemainingVisualShapes >0 && serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied)
|
||||
{
|
||||
m_data->m_hasStatus = false;
|
||||
|
||||
command.m_type = CMD_REQUEST_VISUAL_SHAPE_INFO;
|
||||
command.m_requestVisualShapeDataArguments.m_startingVisualShapeIndex = serverCmd.m_sendVisualShapeArgs.m_startingVisualShapeIndex + serverCmd.m_sendVisualShapeArgs.m_numVisualShapesCopied;
|
||||
command.m_requestVisualShapeDataArguments.m_bodyUniqueId = serverCmd.m_sendVisualShapeArgs.m_bodyUniqueId;
|
||||
@@ -233,6 +310,60 @@ bool PhysicsDirect::processVisualShapeData(const struct SharedMemoryCommand& org
|
||||
return m_data->m_hasStatus;
|
||||
}
|
||||
|
||||
bool PhysicsDirect::processOverlappingObjects(const struct SharedMemoryCommand& orgCommand)
|
||||
{
|
||||
SharedMemoryCommand command = orgCommand;
|
||||
|
||||
const SharedMemoryStatus& serverCmd = m_data->m_serverStatus;
|
||||
|
||||
do
|
||||
{
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command, m_data->m_serverStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
if (hasStatus)
|
||||
{
|
||||
if (m_data->m_verboseOutput)
|
||||
{
|
||||
b3Printf("Overlapping Objects Request OK\n");
|
||||
}
|
||||
|
||||
int startOverlapIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex;
|
||||
int numOverlapCopied = serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied;
|
||||
m_data->m_cachedOverlappingObjects.resize(startOverlapIndex + numOverlapCopied);
|
||||
b3OverlappingObject* objects = (b3OverlappingObject*)&m_data->m_bulletStreamDataServerToClient[0];
|
||||
|
||||
for (int i = 0; i < numOverlapCopied; i++)
|
||||
{
|
||||
m_data->m_cachedOverlappingObjects[startOverlapIndex + i] = objects[i];
|
||||
}
|
||||
|
||||
if (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied)
|
||||
{
|
||||
m_data->m_hasStatus = false;
|
||||
command.m_type = CMD_REQUEST_AABB_OVERLAP;
|
||||
command.m_requestOverlappingObjectsArgs.m_startingOverlappingObjectIndex = serverCmd.m_sendOverlappingObjectsArgs.m_startingOverlappingObjectIndex + serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied;
|
||||
}
|
||||
|
||||
}
|
||||
} while (serverCmd.m_sendOverlappingObjectsArgs.m_numRemainingOverlappingObjects > 0 && serverCmd.m_sendOverlappingObjectsArgs.m_numOverlappingObjectsCopied);
|
||||
|
||||
return m_data->m_hasStatus;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& orgCommand)
|
||||
{
|
||||
@@ -243,7 +374,19 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or
|
||||
do
|
||||
{
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
if (hasStatus)
|
||||
{
|
||||
if (m_data->m_verboseOutput)
|
||||
@@ -264,7 +407,10 @@ bool PhysicsDirect::processContactPointData(const struct SharedMemoryCommand& or
|
||||
|
||||
if (serverCmd.m_sendContactPointArgs.m_numRemainingContactPoints>0 && serverCmd.m_sendContactPointArgs.m_numContactPointsCopied)
|
||||
{
|
||||
command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION;
|
||||
|
||||
m_data->m_hasStatus = false;
|
||||
|
||||
command.m_type = CMD_REQUEST_CONTACT_POINT_INFORMATION;
|
||||
command.m_requestContactPointArguments.m_startingContactPointIndex = serverCmd.m_sendContactPointArgs.m_startingContactPointIndex+serverCmd.m_sendContactPointArgs.m_numContactPointsCopied;
|
||||
command.m_requestContactPointArguments.m_objectAIndexFilter = -1;
|
||||
command.m_requestContactPointArguments.m_objectBIndexFilter = -1;
|
||||
@@ -289,6 +435,18 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand)
|
||||
{
|
||||
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
const SharedMemoryStatus* stat = processServerStatus();
|
||||
if (stat)
|
||||
{
|
||||
hasStatus = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
if (hasStatus)
|
||||
{
|
||||
@@ -340,6 +498,7 @@ bool PhysicsDirect::processCamera(const struct SharedMemoryCommand& orgCommand)
|
||||
if (serverCmd.m_sendPixelDataArguments.m_numRemainingPixels > 0 && serverCmd.m_sendPixelDataArguments.m_numPixelsCopied)
|
||||
{
|
||||
|
||||
m_data->m_hasStatus = false;
|
||||
|
||||
// continue requesting remaining pixels
|
||||
command.m_type = CMD_REQUEST_CAMERA_IMAGE_DATA;
|
||||
@@ -365,8 +524,15 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta
|
||||
{
|
||||
bParse::btBulletFile bf(
|
||||
&m_data->m_bulletStreamDataServerToClient[0],
|
||||
serverCmd.m_dataStreamArguments.m_streamChunkLength);
|
||||
bf.setFileDNAisMemoryDNA();
|
||||
serverCmd.m_numDataStreamBytes);
|
||||
if (m_data->m_serverDNA.size())
|
||||
{
|
||||
bf.setFileDNA(false, &m_data->m_serverDNA[0], m_data->m_serverDNA.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
bf.setFileDNAisMemoryDNA();
|
||||
}
|
||||
bf.parse(false);
|
||||
|
||||
BodyJointInfoCache2* bodyJoints = new BodyJointInfoCache2;
|
||||
@@ -379,19 +545,27 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta
|
||||
{
|
||||
Bullet::btMultiBodyDoubleData* mb =
|
||||
(Bullet::btMultiBodyDoubleData*)bf.m_multiBodies[i];
|
||||
bodyJoints->m_baseName = mb->m_baseName;
|
||||
|
||||
|
||||
if (mb->m_baseName)
|
||||
{
|
||||
bodyJoints->m_baseName = mb->m_baseName;
|
||||
}
|
||||
addJointInfoFromMultiBodyData(mb,bodyJoints, m_data->m_verboseOutput);
|
||||
} else
|
||||
{
|
||||
Bullet::btMultiBodyFloatData* mb =
|
||||
(Bullet::btMultiBodyFloatData*)bf.m_multiBodies[i];
|
||||
|
||||
bodyJoints->m_baseName = mb->m_baseName;
|
||||
|
||||
if (mb->m_baseName)
|
||||
{
|
||||
bodyJoints->m_baseName = mb->m_baseName;
|
||||
}
|
||||
addJointInfoFromMultiBodyData(mb,bodyJoints, m_data->m_verboseOutput);
|
||||
}
|
||||
}
|
||||
if (bf.ok()) {
|
||||
if (bf.ok())
|
||||
{
|
||||
if (m_data->m_verboseOutput)
|
||||
{
|
||||
b3Printf("Received robot description ok!\n");
|
||||
@@ -402,6 +576,118 @@ void PhysicsDirect::processBodyJointInfo(int bodyUniqueId, const SharedMemorySta
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsDirect::postProcessStatus(const struct SharedMemoryStatus& serverCmd)
|
||||
{
|
||||
switch (serverCmd.m_type)
|
||||
{
|
||||
|
||||
case CMD_REQUEST_INTERNAL_DATA_COMPLETED:
|
||||
{
|
||||
if (serverCmd.m_numDataStreamBytes)
|
||||
{
|
||||
int numStreamBytes = serverCmd.m_numDataStreamBytes;
|
||||
m_data->m_serverDNA.resize(numStreamBytes);
|
||||
for (int i = 0; i < numStreamBytes; i++)
|
||||
{
|
||||
m_data->m_serverDNA[i] = m_data->m_bulletStreamDataServerToClient[i];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_RESET_SIMULATION_COMPLETED:
|
||||
{
|
||||
m_data->m_debugLinesFrom.clear();
|
||||
m_data->m_debugLinesTo.clear();
|
||||
m_data->m_debugLinesColor.clear();
|
||||
for (int i = 0; i<m_data->m_bodyJointMap.size(); i++)
|
||||
{
|
||||
BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i);
|
||||
if (bodyJointsPtr && *bodyJointsPtr)
|
||||
{
|
||||
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
|
||||
for (int j = 0; j<bodyJoints->m_jointInfo.size(); j++) {
|
||||
if (bodyJoints->m_jointInfo[j].m_jointName)
|
||||
{
|
||||
free(bodyJoints->m_jointInfo[j].m_jointName);
|
||||
}
|
||||
if (bodyJoints->m_jointInfo[j].m_linkName)
|
||||
{
|
||||
free(bodyJoints->m_jointInfo[j].m_linkName);
|
||||
}
|
||||
}
|
||||
delete (*bodyJointsPtr);
|
||||
}
|
||||
}
|
||||
m_data->m_bodyJointMap.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
case CMD_SDF_LOADING_COMPLETED:
|
||||
{
|
||||
//we'll stream further info from the physics server
|
||||
//so serverCmd will be invalid, make a copy
|
||||
|
||||
|
||||
int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies;
|
||||
for (int i = 0; i<numBodies; i++)
|
||||
{
|
||||
int bodyUniqueId = serverCmd.m_sdfLoadedArgs.m_bodyUniqueIds[i];
|
||||
SharedMemoryCommand infoRequestCommand;
|
||||
infoRequestCommand.m_type = CMD_REQUEST_BODY_INFO;
|
||||
infoRequestCommand.m_sdfRequestInfoArgs.m_bodyUniqueId = bodyUniqueId;
|
||||
SharedMemoryStatus infoStatus;
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(infoRequestCommand, infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
hasStatus = m_data->m_commandProcessor->receiveStatus(infoStatus, &m_data->m_bulletStreamDataServerToClient[0], SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
if (hasStatus)
|
||||
{
|
||||
processBodyJointInfo(bodyUniqueId, infoStatus);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_URDF_LOADING_COMPLETED:
|
||||
{
|
||||
|
||||
if (serverCmd.m_numDataStreamBytes > 0)
|
||||
{
|
||||
int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId;
|
||||
processBodyJointInfo(bodyIndex, serverCmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_BULLET_LOADING_FAILED:
|
||||
{
|
||||
b3Warning("Couldn't load .bullet file");
|
||||
break;
|
||||
}
|
||||
case CMD_BULLET_LOADING_COMPLETED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_USER_CONSTRAINT_COMPLETED:
|
||||
{
|
||||
break;
|
||||
}
|
||||
case CMD_USER_CONSTRAINT_FAILED:
|
||||
{
|
||||
b3Warning("createConstraint failed");
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
//b3Warning("Unknown server status type");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& command)
|
||||
{
|
||||
if (command.m_type==CMD_REQUEST_DEBUG_LINES)
|
||||
@@ -422,83 +708,16 @@ bool PhysicsDirect::submitClientCommand(const struct SharedMemoryCommand& comman
|
||||
{
|
||||
return processVisualShapeData(command);
|
||||
}
|
||||
if (command.m_type == CMD_REQUEST_AABB_OVERLAP)
|
||||
{
|
||||
return processOverlappingObjects(command);
|
||||
}
|
||||
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(command,m_data->m_serverStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
m_data->m_hasStatus = hasStatus;
|
||||
if (hasStatus)
|
||||
{
|
||||
const SharedMemoryStatus& serverCmd = m_data->m_serverStatus;
|
||||
|
||||
switch (m_data->m_serverStatus.m_type)
|
||||
{
|
||||
case CMD_RESET_SIMULATION_COMPLETED:
|
||||
{
|
||||
m_data->m_debugLinesFrom.clear();
|
||||
m_data->m_debugLinesTo.clear();
|
||||
m_data->m_debugLinesColor.clear();
|
||||
for (int i=0;i<m_data->m_bodyJointMap.size();i++)
|
||||
{
|
||||
BodyJointInfoCache2** bodyJointsPtr = m_data->m_bodyJointMap.getAtIndex(i);
|
||||
if (bodyJointsPtr && *bodyJointsPtr)
|
||||
{
|
||||
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
|
||||
for (int j=0;j<bodyJoints->m_jointInfo.size();j++) {
|
||||
if (bodyJoints->m_jointInfo[j].m_jointName)
|
||||
{
|
||||
free(bodyJoints->m_jointInfo[j].m_jointName);
|
||||
}
|
||||
if (bodyJoints->m_jointInfo[j].m_linkName)
|
||||
{
|
||||
free(bodyJoints->m_jointInfo[j].m_linkName);
|
||||
}
|
||||
}
|
||||
delete (*bodyJointsPtr);
|
||||
}
|
||||
}
|
||||
m_data->m_bodyJointMap.clear();
|
||||
|
||||
break;
|
||||
}
|
||||
case CMD_SDF_LOADING_COMPLETED:
|
||||
{
|
||||
//we'll stream further info from the physics server
|
||||
//so serverCmd will be invalid, make a copy
|
||||
|
||||
|
||||
int numBodies = serverCmd.m_sdfLoadedArgs.m_numBodies;
|
||||
for (int i=0;i<numBodies;i++)
|
||||
{
|
||||
int bodyUniqueId = serverCmd.m_sdfLoadedArgs.m_bodyUniqueIds[i];
|
||||
SharedMemoryCommand infoRequestCommand;
|
||||
infoRequestCommand.m_type = CMD_REQUEST_BODY_INFO;
|
||||
infoRequestCommand.m_sdfRequestInfoArgs.m_bodyUniqueId = bodyUniqueId;
|
||||
SharedMemoryStatus infoStatus;
|
||||
bool hasStatus = m_data->m_commandProcessor->processCommand(infoRequestCommand,infoStatus,&m_data->m_bulletStreamDataServerToClient[0],SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
if (hasStatus)
|
||||
{
|
||||
processBodyJointInfo(bodyUniqueId, infoStatus);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CMD_URDF_LOADING_COMPLETED:
|
||||
{
|
||||
|
||||
if (serverCmd.m_dataStreamArguments.m_streamChunkLength > 0)
|
||||
{
|
||||
int bodyIndex = serverCmd.m_dataStreamArguments.m_bodyUniqueId;
|
||||
processBodyJointInfo(bodyIndex,serverCmd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
// b3Error("Unknown server status type");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
postProcessStatus(m_data->m_serverStatus);
|
||||
}
|
||||
return hasStatus;
|
||||
}
|
||||
@@ -549,7 +768,7 @@ bool PhysicsDirect::getJointInfo(int bodyIndex, int jointIndex, struct b3JointIn
|
||||
if (bodyJointsPtr && *bodyJointsPtr)
|
||||
{
|
||||
BodyJointInfoCache2* bodyJoints = *bodyJointsPtr;
|
||||
if (jointIndex < bodyJoints->m_jointInfo.size())
|
||||
if ((jointIndex >=0) && (jointIndex < bodyJoints->m_jointInfo.size()))
|
||||
{
|
||||
info = bodyJoints->m_jointInfo[jointIndex];
|
||||
return true;
|
||||
@@ -619,6 +838,14 @@ void PhysicsDirect::getCachedContactPointInformation(struct b3ContactInformation
|
||||
|
||||
}
|
||||
|
||||
void PhysicsDirect::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects)
|
||||
{
|
||||
overlappingObjects->m_numOverlappingObjects = m_data->m_cachedOverlappingObjects.size();
|
||||
overlappingObjects->m_overlappingObjects = m_data->m_cachedOverlappingObjects.size() ?
|
||||
&m_data->m_cachedOverlappingObjects[0] : 0;
|
||||
}
|
||||
|
||||
|
||||
void PhysicsDirect::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo)
|
||||
{
|
||||
visualShapesInfo->m_numVisualShapes = m_data->m_cachedVisualShapes.size();
|
||||
|
||||
@@ -7,9 +7,6 @@
|
||||
#include "PhysicsClient.h"
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
///todo: the PhysicsClient API was designed with shared memory in mind,
|
||||
///now it become more general we need to move out the shared memory specifics away
|
||||
///for example naming [disconnectSharedMemory -> disconnect] [ move setSharedMemoryKey to shared memory specific subclass ]
|
||||
///PhysicsDirect executes the commands directly, without transporting them or having a separate server executing commands
|
||||
class PhysicsDirect : public PhysicsClient
|
||||
{
|
||||
@@ -23,13 +20,17 @@ protected:
|
||||
|
||||
bool processContactPointData(const struct SharedMemoryCommand& orgCommand);
|
||||
|
||||
bool processOverlappingObjects(const struct SharedMemoryCommand& orgCommand);
|
||||
|
||||
bool processVisualShapeData(const struct SharedMemoryCommand& orgCommand);
|
||||
|
||||
void processBodyJointInfo(int bodyUniqueId, const struct SharedMemoryStatus& serverCmd);
|
||||
|
||||
void postProcessStatus(const struct SharedMemoryStatus& serverCmd);
|
||||
|
||||
public:
|
||||
|
||||
PhysicsDirect();
|
||||
PhysicsDirect(class PhysicsCommandProcessorInterface* physSdk);
|
||||
|
||||
virtual ~PhysicsDirect();
|
||||
|
||||
@@ -76,8 +77,11 @@ public:
|
||||
|
||||
virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData);
|
||||
|
||||
virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects);
|
||||
|
||||
virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo);
|
||||
|
||||
|
||||
//those 2 APIs are for internal use for visualization
|
||||
virtual bool connect(struct GUIHelperInterface* guiHelper);
|
||||
virtual void renderScene();
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
#include "PhysicsDirect.h"
|
||||
|
||||
#include "PhysicsServerCommandProcessor.h"
|
||||
|
||||
|
||||
|
||||
//think more about naming. The b3ConnectPhysicsLoopback
|
||||
b3PhysicsClientHandle b3ConnectPhysicsDirect()
|
||||
{
|
||||
PhysicsDirect* direct = new PhysicsDirect();
|
||||
PhysicsServerCommandProcessor* sdk = new PhysicsServerCommandProcessor;
|
||||
|
||||
PhysicsDirect* direct = new PhysicsDirect(sdk);
|
||||
bool connected = direct->connect();
|
||||
return (b3PhysicsClientHandle )direct;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
|
||||
|
||||
@@ -144,4 +144,10 @@ void PhysicsLoopBack::getCachedContactPointInformation(struct b3ContactInformati
|
||||
void PhysicsLoopBack::getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo)
|
||||
{
|
||||
return m_data->m_physicsClient->getCachedVisualShapeInformation(visualShapesInfo);
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsLoopBack::getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects)
|
||||
{
|
||||
return m_data->m_physicsClient->getCachedOverlappingObjects(overlappingObjects);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ public:
|
||||
|
||||
virtual void getCachedContactPointInformation(struct b3ContactInformation* contactPointData);
|
||||
|
||||
virtual void getCachedOverlappingObjects(struct b3AABBOverlapData* overlappingObjects);
|
||||
|
||||
virtual void getCachedVisualShapeInformation(struct b3VisualShapeInformation* visualShapesInfo);
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,8 @@
|
||||
|
||||
#include "LinearMath/btVector3.h"
|
||||
|
||||
#include "PhysicsCommandProcessorInterface.h"
|
||||
|
||||
struct SharedMemLines
|
||||
{
|
||||
btVector3 m_from;
|
||||
@@ -10,8 +12,10 @@ struct SharedMemLines
|
||||
btVector3 m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
///todo: naming. Perhaps PhysicsSdkCommandprocessor?
|
||||
class PhysicsServerCommandProcessor
|
||||
class PhysicsServerCommandProcessor : public PhysicsCommandProcessorInterface
|
||||
{
|
||||
|
||||
struct PhysicsServerCommandProcessorInternalData* m_data;
|
||||
@@ -19,32 +23,53 @@ class PhysicsServerCommandProcessor
|
||||
//todo: move this to physics client side / Python
|
||||
void createDefaultRobotAssets();
|
||||
|
||||
void resetSimulation();
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
|
||||
|
||||
bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody);
|
||||
|
||||
bool loadSdf(const char* fileName, char* bufferServerToClient, int bufferSizeInBytes, bool useMultiBody);
|
||||
|
||||
bool loadUrdf(const char* fileName, const class btVector3& pos, const class btQuaternion& orn,
|
||||
bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
bool useMultiBody, bool useFixedBase, int* bodyUniqueIdPtr, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
bool supportsJointMotor(class btMultiBody* body, int linkIndex);
|
||||
|
||||
|
||||
int createBodyInfoStream(int bodyUniqueId, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
void deleteCachedInverseDynamicsBodies();
|
||||
void deleteCachedInverseKinematicsBodies();
|
||||
|
||||
public:
|
||||
PhysicsServerCommandProcessor();
|
||||
virtual ~PhysicsServerCommandProcessor();
|
||||
|
||||
void createJointMotors(class btMultiBody* body);
|
||||
|
||||
|
||||
virtual void createEmptyDynamicsWorld();
|
||||
virtual void deleteDynamicsWorld();
|
||||
|
||||
|
||||
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes );
|
||||
virtual bool connect()
|
||||
{
|
||||
return true;
|
||||
};
|
||||
|
||||
virtual void disconnect() {}
|
||||
|
||||
virtual bool isConnected() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
|
||||
virtual void renderScene();
|
||||
virtual void physicsDebugDraw(int debugDrawFlags);
|
||||
@@ -60,6 +85,7 @@ public:
|
||||
void replayFromLogFile(const char* fileName);
|
||||
void replayLogCommand(char* bufferServerToClient, int bufferSizeInBytes );
|
||||
void stepSimulationRealTime(double dtInSec);
|
||||
void enableRealTimeSimulation(bool enableRealTimeSim);
|
||||
void applyJointDamping(int bodyUniqueId);
|
||||
};
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -241,6 +241,12 @@ void PhysicsServerSharedMemory::stepSimulationRealTime(double dtInSec)
|
||||
m_data->m_commandProcessor->stepSimulationRealTime(dtInSec);
|
||||
}
|
||||
|
||||
void PhysicsServerSharedMemory::enableRealTimeSimulation(bool enableRealTimeSim)
|
||||
{
|
||||
m_data->m_commandProcessor->enableRealTimeSimulation(enableRealTimeSim);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PhysicsServerSharedMemory::processClientCommands()
|
||||
{
|
||||
|
||||
@@ -28,9 +28,11 @@ public:
|
||||
|
||||
virtual void stepSimulationRealTime(double dtInSec);
|
||||
|
||||
virtual void enableRealTimeSimulation(bool enableRealTimeSim);
|
||||
|
||||
//bool supportsJointMotor(class btMultiBody* body, int linkIndex);
|
||||
|
||||
//@todo(erwincoumans) Should we have shared memory commands for picking objects?
|
||||
|
||||
///The pickBody method will try to pick the first body along a ray, return true if succeeds, false otherwise
|
||||
virtual bool pickBody(const btVector3& rayFromWorld, const btVector3& rayToWorld);
|
||||
virtual bool movePickedBody(const btVector3& rayFromWorld, const btVector3& rayToWorld);
|
||||
|
||||
216
examples/SharedMemory/SharedMemoryCommandProcessor.cpp
Normal file
216
examples/SharedMemory/SharedMemoryCommandProcessor.cpp
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "SharedMemoryCommandProcessor.h"
|
||||
|
||||
#include "PosixSharedMemory.h"
|
||||
#include "Win32SharedMemory.h"
|
||||
#include "Bullet3Common/b3Logging.h"
|
||||
#include "Bullet3Common/b3Scalar.h"
|
||||
|
||||
#include "SharedMemoryBlock.h"
|
||||
|
||||
|
||||
struct SharedMemoryCommandProcessorInternalData
|
||||
{
|
||||
int m_sharedMemoryKey;
|
||||
bool m_isConnected;
|
||||
SharedMemoryInterface* m_sharedMemory;
|
||||
bool m_ownsSharedMemory;
|
||||
bool m_verboseOutput;
|
||||
bool m_waitingForServer;
|
||||
SharedMemoryStatus m_lastServerStatus;
|
||||
SharedMemoryBlock* m_testBlock1;
|
||||
|
||||
|
||||
SharedMemoryCommandProcessorInternalData()
|
||||
:m_sharedMemoryKey(SHARED_MEMORY_KEY),
|
||||
m_isConnected(false),
|
||||
m_sharedMemory(0),
|
||||
m_ownsSharedMemory(false),
|
||||
m_verboseOutput(false),
|
||||
m_waitingForServer(false),
|
||||
m_testBlock1(0)
|
||||
{
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
SharedMemoryCommandProcessor::SharedMemoryCommandProcessor()
|
||||
{
|
||||
m_data = new SharedMemoryCommandProcessorInternalData;
|
||||
m_data->m_sharedMemoryKey = SHARED_MEMORY_KEY;
|
||||
#ifdef _WIN32
|
||||
m_data->m_sharedMemory = new Win32SharedMemoryClient();
|
||||
#else
|
||||
m_data->m_sharedMemory = new PosixSharedMemory();
|
||||
#endif
|
||||
m_data->m_ownsSharedMemory = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
SharedMemoryCommandProcessor::~SharedMemoryCommandProcessor()
|
||||
{
|
||||
if (m_data->m_isConnected)
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
if (m_data->m_ownsSharedMemory)
|
||||
{
|
||||
delete m_data->m_sharedMemory;
|
||||
}
|
||||
delete m_data;
|
||||
|
||||
}
|
||||
|
||||
bool SharedMemoryCommandProcessor::connect()
|
||||
{
|
||||
|
||||
if (m_data->m_isConnected)
|
||||
return true;
|
||||
|
||||
bool allowCreation = false;
|
||||
m_data->m_testBlock1 = (SharedMemoryBlock*)m_data->m_sharedMemory->allocateSharedMemory(
|
||||
m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE, allowCreation);
|
||||
|
||||
if (m_data->m_testBlock1) {
|
||||
if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER) {
|
||||
b3Error("Error: please start server before client\n");
|
||||
m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey,
|
||||
SHARED_MEMORY_SIZE);
|
||||
m_data->m_testBlock1 = 0;
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
if (m_data->m_verboseOutput) {
|
||||
b3Printf("Connected to existing shared memory, status OK.\n");
|
||||
}
|
||||
m_data->m_isConnected = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
b3Error("Cannot connect to shared memory");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
void SharedMemoryCommandProcessor::disconnect()
|
||||
{
|
||||
if (m_data->m_isConnected && m_data->m_sharedMemory)
|
||||
{
|
||||
m_data->m_sharedMemory->releaseSharedMemory(m_data->m_sharedMemoryKey, SHARED_MEMORY_SIZE);
|
||||
}
|
||||
m_data->m_isConnected = false;
|
||||
|
||||
}
|
||||
|
||||
bool SharedMemoryCommandProcessor::isConnected() const
|
||||
{
|
||||
return m_data->m_isConnected;
|
||||
}
|
||||
|
||||
|
||||
bool SharedMemoryCommandProcessor::processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
|
||||
{
|
||||
if (!m_data->m_waitingForServer) {
|
||||
if (&m_data->m_testBlock1->m_clientCommands[0] != &clientCmd) {
|
||||
m_data->m_testBlock1->m_clientCommands[0] = clientCmd;
|
||||
}
|
||||
m_data->m_testBlock1->m_numClientCommands++;
|
||||
m_data->m_waitingForServer = true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SharedMemoryCommandProcessor::receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes)
|
||||
{
|
||||
SharedMemoryStatus* stat = 0;
|
||||
|
||||
m_data->m_lastServerStatus.m_dataStream = 0;
|
||||
m_data->m_lastServerStatus.m_numDataStreamBytes = 0;
|
||||
|
||||
if (!m_data->m_testBlock1)
|
||||
{
|
||||
//m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED;
|
||||
//return &m_data->m_lastServerStatus;
|
||||
//serverStatusOut = m_data->m_lastServerStatus;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!m_data->m_waitingForServer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_data->m_testBlock1->m_magicId != SHARED_MEMORY_MAGIC_NUMBER)
|
||||
{
|
||||
//m_data->m_lastServerStatus.m_type = CMD_SHARED_MEMORY_NOT_INITIALIZED;
|
||||
//return &m_data->m_lastServerStatus;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_data->m_testBlock1->m_numServerCommands >
|
||||
m_data->m_testBlock1->m_numProcessedServerCommands)
|
||||
{
|
||||
b3Assert(m_data->m_testBlock1->m_numServerCommands ==
|
||||
m_data->m_testBlock1->m_numProcessedServerCommands + 1);
|
||||
|
||||
const SharedMemoryStatus& serverCmd = m_data->m_testBlock1->m_serverCommands[0];
|
||||
m_data->m_lastServerStatus = serverCmd;
|
||||
m_data->m_lastServerStatus.m_dataStream = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor;
|
||||
|
||||
for (int i = 0; i < m_data->m_lastServerStatus.m_numDataStreamBytes; i++)
|
||||
{
|
||||
bufferServerToClient[i] = m_data->m_testBlock1->m_bulletStreamDataServerToClientRefactor[i];
|
||||
}
|
||||
|
||||
m_data->m_testBlock1->m_numProcessedServerCommands++;
|
||||
// we don't have more than 1 command outstanding (in total, either server or client)
|
||||
b3Assert(m_data->m_testBlock1->m_numProcessedServerCommands ==
|
||||
m_data->m_testBlock1->m_numServerCommands);
|
||||
|
||||
if (m_data->m_testBlock1->m_numServerCommands ==
|
||||
m_data->m_testBlock1->m_numProcessedServerCommands) {
|
||||
m_data->m_waitingForServer = false;
|
||||
}
|
||||
else {
|
||||
m_data->m_waitingForServer = true;
|
||||
}
|
||||
|
||||
serverStatusOut = m_data->m_lastServerStatus;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void SharedMemoryCommandProcessor::renderScene()
|
||||
{
|
||||
}
|
||||
|
||||
void SharedMemoryCommandProcessor::physicsDebugDraw(int debugDrawFlags)
|
||||
{
|
||||
}
|
||||
|
||||
void SharedMemoryCommandProcessor::setGuiHelper(struct GUIHelperInterface* guiHelper)
|
||||
{
|
||||
}
|
||||
|
||||
void SharedMemoryCommandProcessor::setSharedMemoryInterface(class SharedMemoryInterface* sharedMem)
|
||||
{
|
||||
if (m_data->m_sharedMemory && m_data->m_ownsSharedMemory)
|
||||
{
|
||||
delete m_data->m_sharedMemory;
|
||||
}
|
||||
m_data->m_ownsSharedMemory = false;
|
||||
m_data->m_sharedMemory = sharedMem;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void SharedMemoryCommandProcessor::setSharedMemoryKey(int key)
|
||||
{
|
||||
m_data->m_sharedMemoryKey = key;
|
||||
}
|
||||
|
||||
|
||||
37
examples/SharedMemory/SharedMemoryCommandProcessor.h
Normal file
37
examples/SharedMemory/SharedMemoryCommandProcessor.h
Normal file
@@ -0,0 +1,37 @@
|
||||
#ifndef SHARED_MEMORY_COMMAND_PROCESSOR_H
|
||||
#define SHARED_MEMORY_COMMAND_PROCESSOR_H
|
||||
|
||||
#include "PhysicsCommandProcessorInterface.h"
|
||||
|
||||
class SharedMemoryCommandProcessor : public PhysicsCommandProcessorInterface
|
||||
{
|
||||
|
||||
struct SharedMemoryCommandProcessorInternalData* m_data;
|
||||
|
||||
public:
|
||||
SharedMemoryCommandProcessor();
|
||||
|
||||
virtual ~SharedMemoryCommandProcessor();
|
||||
|
||||
virtual bool connect();
|
||||
|
||||
virtual void disconnect();
|
||||
|
||||
virtual bool isConnected() const;
|
||||
|
||||
virtual bool processCommand(const struct SharedMemoryCommand& clientCmd, struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
virtual bool receiveStatus(struct SharedMemoryStatus& serverStatusOut, char* bufferServerToClient, int bufferSizeInBytes);
|
||||
|
||||
virtual void renderScene();
|
||||
virtual void physicsDebugDraw(int debugDrawFlags);
|
||||
virtual void setGuiHelper(struct GUIHelperInterface* guiHelper);
|
||||
|
||||
void setSharedMemoryInterface(class SharedMemoryInterface* sharedMem);
|
||||
void setSharedMemoryKey(int key);
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif //SHARED_MEMORY_COMMAND_PROCESSOR_H
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
typedef unsigned long long int smUint64_t;
|
||||
#endif
|
||||
|
||||
#define SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE (256*1024)
|
||||
#define SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE (512*1024)
|
||||
|
||||
#define SHARED_MEMORY_SERVER_TEST_C
|
||||
#define MAX_DEGREE_OF_FREEDOM 128
|
||||
@@ -67,6 +67,11 @@ struct SdfArgs
|
||||
int m_useMultiBody;
|
||||
};
|
||||
|
||||
struct FileArgs
|
||||
{
|
||||
char m_fileName[MAX_URDF_FILENAME_LENGTH];
|
||||
};
|
||||
|
||||
enum EnumUrdfArgsUpdateFlags
|
||||
{
|
||||
URDF_ARGS_FILE_NAME=1,
|
||||
@@ -90,7 +95,6 @@ struct UrdfArgs
|
||||
struct BulletDataStreamArgs
|
||||
{
|
||||
char m_bulletFileName[MAX_FILENAME_LENGTH];
|
||||
int m_streamChunkLength;
|
||||
int m_bodyUniqueId;
|
||||
};
|
||||
|
||||
@@ -105,7 +109,9 @@ enum EnumInitPoseFlags
|
||||
{
|
||||
INIT_POSE_HAS_INITIAL_POSITION=1,
|
||||
INIT_POSE_HAS_INITIAL_ORIENTATION=2,
|
||||
INIT_POSE_HAS_JOINT_STATE=4
|
||||
INIT_POSE_HAS_JOINT_STATE=4,
|
||||
INIT_POSE_HAS_BASE_LINEAR_VELOCITY = 8,
|
||||
INIT_POSE_HAS_BASE_ANGULAR_VELOCITY = 16,
|
||||
};
|
||||
|
||||
|
||||
@@ -118,6 +124,8 @@ struct InitPoseArgs
|
||||
int m_bodyUniqueId;
|
||||
int m_hasInitialStateQ[MAX_DEGREE_OF_FREEDOM];
|
||||
double m_initialStateQ[MAX_DEGREE_OF_FREEDOM];
|
||||
int m_hasInitialStateQdot[MAX_DEGREE_OF_FREEDOM];
|
||||
double m_initialStateQdot[MAX_DEGREE_OF_FREEDOM];
|
||||
};
|
||||
|
||||
|
||||
@@ -134,21 +142,54 @@ struct RequestPixelDataArgs
|
||||
int m_startPixelIndex;
|
||||
int m_pixelWidth;
|
||||
int m_pixelHeight;
|
||||
float m_lightDirection[3];
|
||||
float m_lightColor[3];
|
||||
float m_lightDistance;
|
||||
float m_lightAmbientCoeff;
|
||||
float m_lightDiffuseCoeff;
|
||||
float m_lightSpecularCoeff;
|
||||
int m_hasShadow;
|
||||
};
|
||||
|
||||
enum EnumRequestPixelDataUpdateFlags
|
||||
{
|
||||
REQUEST_PIXEL_ARGS_HAS_CAMERA_MATRICES=1,
|
||||
REQUEST_PIXEL_ARGS_SET_PIXEL_WIDTH_HEIGHT=4,
|
||||
REQUEST_PIXEL_ARGS_SET_PIXEL_WIDTH_HEIGHT=2,
|
||||
REQUEST_PIXEL_ARGS_SET_LIGHT_DIRECTION=4,
|
||||
REQUEST_PIXEL_ARGS_SET_LIGHT_COLOR=8,
|
||||
REQUEST_PIXEL_ARGS_SET_LIGHT_DISTANCE=16,
|
||||
REQUEST_PIXEL_ARGS_SET_SHADOW=32,
|
||||
REQUEST_PIXEL_ARGS_SET_AMBIENT_COEFF=64,
|
||||
REQUEST_PIXEL_ARGS_SET_DIFFUSE_COEFF=128,
|
||||
REQUEST_PIXEL_ARGS_SET_SPECULAR_COEFF=256,
|
||||
//don't exceed (1<<15), because this enum is shared with EnumRenderer in SharedMemoryPublic.h
|
||||
|
||||
};
|
||||
|
||||
enum EnumRequestContactDataUpdateFlags
|
||||
{
|
||||
CMD_REQUEST_CONTACT_POINT_HAS_QUERY_MODE=1,
|
||||
CMD_REQUEST_CONTACT_POINT_HAS_CLOSEST_DISTANCE_THRESHOLD=2,
|
||||
CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_A_FILTER = 4,
|
||||
CMD_REQUEST_CONTACT_POINT_HAS_LINK_INDEX_B_FILTER = 8,
|
||||
};
|
||||
|
||||
struct RequestContactDataArgs
|
||||
{
|
||||
int m_startingContactPointIndex;
|
||||
int m_objectAIndexFilter;
|
||||
int m_objectBIndexFilter;
|
||||
int m_linkIndexAIndexFilter;
|
||||
int m_linkIndexBIndexFilter;
|
||||
double m_closestDistanceThreshold;
|
||||
int m_mode;
|
||||
};
|
||||
|
||||
struct RequestOverlappingObjectsArgs
|
||||
{
|
||||
int m_startingOverlappingObjectIndex;
|
||||
double m_aabbQueryMin[3];
|
||||
double m_aabbQueryMax[3];
|
||||
};
|
||||
|
||||
struct RequestVisualShapeDataArgs
|
||||
@@ -252,7 +293,16 @@ enum EnumSimParamUpdateFlags
|
||||
SIM_PARAM_UPDATE_NUM_SIMULATION_SUB_STEPS=8,
|
||||
SIM_PARAM_UPDATE_REAL_TIME_SIMULATION = 16,
|
||||
SIM_PARAM_UPDATE_DEFAULT_CONTACT_ERP=32,
|
||||
SIM_PARAM_UPDATE_INTERNAL_SIMULATION_FLAGS=64
|
||||
SIM_PARAM_UPDATE_INTERNAL_SIMULATION_FLAGS=64,
|
||||
SIM_PARAM_UPDATE_USE_SPLIT_IMPULSE=128,
|
||||
SIM_PARAM_UPDATE_SPLIT_IMPULSE_PENETRATION_THRESHOLD = 256,
|
||||
};
|
||||
|
||||
enum EnumLoadBunnyUpdateFlags
|
||||
{
|
||||
LOAD_BUNNY_UPDATE_SCALE=1,
|
||||
LOAD_BUNNY_UPDATE_MASS=2,
|
||||
LOAD_BUNNY_UPDATE_COLLISION_MARGIN=4
|
||||
};
|
||||
|
||||
enum EnumSimParamInternalSimFlags
|
||||
@@ -270,10 +320,19 @@ struct SendPhysicsSimulationParameters
|
||||
int m_numSimulationSubSteps;
|
||||
int m_numSolverIterations;
|
||||
bool m_allowRealTimeSimulation;
|
||||
int m_useSplitImpulse;
|
||||
double m_splitImpulsePenetrationThreshold;
|
||||
int m_internalSimFlags;
|
||||
double m_defaultContactERP;
|
||||
};
|
||||
|
||||
struct LoadBunnyArgs
|
||||
{
|
||||
double m_scale;
|
||||
double m_mass;
|
||||
double m_collisionMargin;
|
||||
};
|
||||
|
||||
struct RequestActualStateArgs
|
||||
{
|
||||
int m_bodyUniqueId;
|
||||
@@ -455,7 +514,14 @@ struct CalculateInverseKinematicsResultArgs
|
||||
double m_jointPositions[MAX_DEGREE_OF_FREEDOM];
|
||||
};
|
||||
|
||||
struct CreateJointArgs
|
||||
enum EnumUserConstraintFlags
|
||||
{
|
||||
USER_CONSTRAINT_ADD_CONSTRAINT=1,
|
||||
USER_CONSTRAINT_REMOVE_CONSTRAINT=2,
|
||||
USER_CONSTRAINT_CHANGE_CONSTRAINT=4
|
||||
};
|
||||
|
||||
struct UserConstraintArgs
|
||||
{
|
||||
int m_parentBodyIndex;
|
||||
int m_parentJointIndex;
|
||||
@@ -465,8 +531,53 @@ struct CreateJointArgs
|
||||
double m_childFrame[7];
|
||||
double m_jointAxis[3];
|
||||
int m_jointType;
|
||||
int m_userConstraintUniqueId;
|
||||
};
|
||||
|
||||
struct UserConstraintResultArgs
|
||||
{
|
||||
int m_userConstraintUniqueId;
|
||||
};
|
||||
|
||||
enum EnumUserDebugDrawFlags
|
||||
{
|
||||
USER_DEBUG_HAS_LINE=1,
|
||||
USER_DEBUG_HAS_TEXT=2,
|
||||
USER_DEBUG_REMOVE_ONE_ITEM=4,
|
||||
USER_DEBUG_REMOVE_ALL=8,
|
||||
USER_DEBUG_SET_CUSTOM_OBJECT_COLOR = 16,
|
||||
USER_DEBUG_REMOVE_CUSTOM_OBJECT_COLOR = 32,
|
||||
|
||||
};
|
||||
|
||||
struct UserDebugDrawArgs
|
||||
{
|
||||
double m_debugLineFromXYZ[3];
|
||||
double m_debugLineToXYZ[3];
|
||||
double m_debugLineColorRGB[3];
|
||||
double m_lineWidth;
|
||||
|
||||
double m_lifeTime;
|
||||
int m_removeItemUniqueId;
|
||||
|
||||
char m_text[MAX_FILENAME_LENGTH];
|
||||
double m_textPositionXYZ[3];
|
||||
double m_textColorRGB[3];
|
||||
double m_textSize;
|
||||
|
||||
double m_objectDebugColorRGB[3];
|
||||
int m_objectUniqueId;
|
||||
int m_linkIndex;
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct UserDebugDrawResultArgs
|
||||
{
|
||||
int m_debugItemUniqueId;
|
||||
};
|
||||
|
||||
|
||||
struct SharedMemoryCommand
|
||||
{
|
||||
int m_type;
|
||||
@@ -481,6 +592,7 @@ struct SharedMemoryCommand
|
||||
{
|
||||
struct UrdfArgs m_urdfArguments;
|
||||
struct SdfArgs m_sdfArguments;
|
||||
struct FileArgs m_fileArguments;
|
||||
struct SdfRequestInfoArgs m_sdfRequestInfoArgs;
|
||||
struct InitPoseArgs m_initPoseArgs;
|
||||
struct SendPhysicsSimulationParameters m_physSimParamArgs;
|
||||
@@ -495,12 +607,15 @@ struct SharedMemoryCommand
|
||||
struct ExternalForceArgs m_externalForceArguments;
|
||||
struct CalculateInverseDynamicsArgs m_calculateInverseDynamicsArguments;
|
||||
struct CalculateJacobianArgs m_calculateJacobianArguments;
|
||||
struct CreateJointArgs m_createJointArguments;
|
||||
struct UserConstraintArgs m_userConstraintArguments;
|
||||
struct RequestContactDataArgs m_requestContactPointArguments;
|
||||
struct RequestOverlappingObjectsArgs m_requestOverlappingObjectsArgs;
|
||||
struct RequestVisualShapeDataArgs m_requestVisualShapeDataArguments;
|
||||
struct UpdateVisualShapeDataArgs m_updateVisualShapeDataArguments;
|
||||
struct LoadTextureArgs m_loadTextureArguments;
|
||||
struct CalculateInverseKinematicsArgs m_calculateInverseKinematicsArguments;
|
||||
struct UserDebugDrawArgs m_userDebugDrawArgs;
|
||||
struct LoadBunnyArgs m_loadBunnyArguments;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -516,6 +631,13 @@ struct SendContactDataArgs
|
||||
int m_numRemainingContactPoints;
|
||||
};
|
||||
|
||||
struct SendOverlappingObjectsArgs
|
||||
{
|
||||
int m_startingOverlappingObjectIndex;
|
||||
int m_numOverlappingObjectsCopied;
|
||||
int m_numRemainingOverlappingObjects;
|
||||
};
|
||||
|
||||
struct SharedMemoryStatus
|
||||
{
|
||||
int m_type;
|
||||
@@ -523,6 +645,10 @@ struct SharedMemoryStatus
|
||||
smUint64_t m_timeStamp;
|
||||
int m_sequenceNumber;
|
||||
|
||||
//m_streamBytes is only for internal purposes
|
||||
int m_numDataStreamBytes;
|
||||
char* m_dataStream;
|
||||
|
||||
union
|
||||
{
|
||||
struct BulletDataStreamArgs m_dataStreamArguments;
|
||||
@@ -534,8 +660,11 @@ struct SharedMemoryStatus
|
||||
struct CalculateInverseDynamicsResultArgs m_inverseDynamicsResultArgs;
|
||||
struct CalculateJacobianResultArgs m_jacobianResultArgs;
|
||||
struct SendContactDataArgs m_sendContactPointArgs;
|
||||
struct SendOverlappingObjectsArgs m_sendOverlappingObjectsArgs;
|
||||
struct CalculateInverseKinematicsResultArgs m_inverseKinematicsResultArgs;
|
||||
struct SendVisualShapeDataArgs m_sendVisualShapeArgs;
|
||||
struct UserDebugDrawResultArgs m_userDebugDrawArgs;
|
||||
struct UserConstraintResultArgs m_userConstraintResultArgs;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -7,20 +7,22 @@ enum EnumSharedMemoryClientCommand
|
||||
{
|
||||
CMD_LOAD_SDF,
|
||||
CMD_LOAD_URDF,
|
||||
CMD_LOAD_BULLET,
|
||||
CMD_SAVE_BULLET,
|
||||
CMD_LOAD_MJCF,
|
||||
CMD_LOAD_BUNNY,
|
||||
CMD_SEND_BULLET_DATA_STREAM,
|
||||
CMD_CREATE_BOX_COLLISION_SHAPE,
|
||||
// CMD_DELETE_BOX_COLLISION_SHAPE,
|
||||
CMD_CREATE_RIGID_BODY,
|
||||
CMD_DELETE_RIGID_BODY,
|
||||
CMD_CREATE_SENSOR,///enable or disable joint feedback for force/torque sensors
|
||||
// CMD_REQUEST_SENSOR_MEASUREMENTS,//see CMD_REQUEST_ACTUAL_STATE/CMD_ACTUAL_STATE_UPDATE_COMPLETED
|
||||
CMD_INIT_POSE,
|
||||
CMD_SEND_PHYSICS_SIMULATION_PARAMETERS,
|
||||
CMD_SEND_DESIRED_STATE,//todo: reconsider naming, for example SET_JOINT_CONTROL_VARIABLE?
|
||||
CMD_REQUEST_ACTUAL_STATE,
|
||||
CMD_REQUEST_DEBUG_LINES,
|
||||
CMD_SEND_BULLET_DATA_STREAM,
|
||||
CMD_CREATE_BOX_COLLISION_SHAPE,
|
||||
CMD_CREATE_RIGID_BODY,
|
||||
CMD_DELETE_RIGID_BODY,
|
||||
CMD_CREATE_SENSOR,///enable or disable joint feedback for force/torque sensors
|
||||
CMD_INIT_POSE,
|
||||
CMD_SEND_PHYSICS_SIMULATION_PARAMETERS,
|
||||
CMD_SEND_DESIRED_STATE,//todo: reconsider naming, for example SET_JOINT_CONTROL_VARIABLE?
|
||||
CMD_REQUEST_ACTUAL_STATE,
|
||||
CMD_REQUEST_DEBUG_LINES,
|
||||
CMD_REQUEST_BODY_INFO,
|
||||
CMD_REQUEST_INTERNAL_DATA,
|
||||
CMD_STEP_FORWARD_SIMULATION,
|
||||
CMD_RESET_SIMULATION,
|
||||
CMD_PICK_BODY,
|
||||
@@ -31,12 +33,16 @@ enum EnumSharedMemoryClientCommand
|
||||
CMD_CALCULATE_INVERSE_DYNAMICS,
|
||||
CMD_CALCULATE_INVERSE_KINEMATICS,
|
||||
CMD_CALCULATE_JACOBIAN,
|
||||
CMD_CREATE_JOINT,
|
||||
CMD_USER_CONSTRAINT,
|
||||
CMD_REQUEST_CONTACT_POINT_INFORMATION,
|
||||
CMD_REQUEST_AABB_OVERLAP,
|
||||
CMD_SAVE_WORLD,
|
||||
CMD_REQUEST_VISUAL_SHAPE_INFO,
|
||||
CMD_UPDATE_VISUAL_SHAPE,
|
||||
CMD_LOAD_TEXTURE,
|
||||
CMD_SET_SHADOW,
|
||||
CMD_USER_DEBUG_DRAW,
|
||||
|
||||
//don't go beyond this command!
|
||||
CMD_MAX_CLIENT_COMMANDS,
|
||||
|
||||
@@ -54,6 +60,14 @@ enum EnumSharedMemoryServerStatus
|
||||
CMD_SDF_LOADING_FAILED,
|
||||
CMD_URDF_LOADING_COMPLETED,
|
||||
CMD_URDF_LOADING_FAILED,
|
||||
CMD_BULLET_LOADING_COMPLETED,
|
||||
CMD_BULLET_LOADING_FAILED,
|
||||
CMD_BULLET_SAVING_COMPLETED,
|
||||
CMD_BULLET_SAVING_FAILED,
|
||||
CMD_MJCF_LOADING_COMPLETED,
|
||||
CMD_MJCF_LOADING_FAILED,
|
||||
CMD_REQUEST_INTERNAL_DATA_COMPLETED,
|
||||
CMD_REQUEST_INTERNAL_DATA_FAILED,
|
||||
CMD_BULLET_DATA_STREAM_RECEIVED_COMPLETED,
|
||||
CMD_BULLET_DATA_STREAM_RECEIVED_FAILED,
|
||||
CMD_BOX_COLLISION_SHAPE_CREATION_COMPLETED,
|
||||
@@ -77,6 +91,8 @@ enum EnumSharedMemoryServerStatus
|
||||
CMD_CALCULATED_JACOBIAN_FAILED,
|
||||
CMD_CONTACT_POINT_INFORMATION_COMPLETED,
|
||||
CMD_CONTACT_POINT_INFORMATION_FAILED,
|
||||
CMD_REQUEST_AABB_OVERLAP_COMPLETED,
|
||||
CMD_REQUEST_AABB_OVERLAP_FAILED,
|
||||
CMD_CALCULATE_INVERSE_KINEMATICS_COMPLETED,
|
||||
CMD_CALCULATE_INVERSE_KINEMATICS_FAILED,
|
||||
CMD_SAVE_WORLD_COMPLETED,
|
||||
@@ -87,6 +103,10 @@ enum EnumSharedMemoryServerStatus
|
||||
CMD_VISUAL_SHAPE_UPDATE_FAILED,
|
||||
CMD_LOAD_TEXTURE_COMPLETED,
|
||||
CMD_LOAD_TEXTURE_FAILED,
|
||||
CMD_USER_DEBUG_DRAW_COMPLETED,
|
||||
CMD_USER_DEBUG_DRAW_FAILED,
|
||||
CMD_USER_CONSTRAINT_COMPLETED,
|
||||
CMD_USER_CONSTRAINT_FAILED,
|
||||
//don't go beyond 'CMD_MAX_SERVER_COMMANDS!
|
||||
CMD_MAX_SERVER_COMMANDS
|
||||
};
|
||||
@@ -110,10 +130,12 @@ enum
|
||||
|
||||
// copied from btMultiBodyLink.h
|
||||
enum JointType {
|
||||
eRevoluteType = 0,
|
||||
ePrismaticType = 1,
|
||||
eFixedType = 2,
|
||||
ePoint2PointType = 3,
|
||||
eRevoluteType = 0,
|
||||
ePrismaticType = 1,
|
||||
eSphericalType = 2,
|
||||
ePlanarType = 3,
|
||||
eFixedType = 4,
|
||||
ePoint2PointType = 5,
|
||||
};
|
||||
|
||||
struct b3JointInfo
|
||||
@@ -155,6 +177,18 @@ struct b3DebugLines
|
||||
const float* m_linesColor;//float red,green,blue times 'm_numDebugLines'.
|
||||
};
|
||||
|
||||
struct b3OverlappingObject
|
||||
{
|
||||
int m_objectUniqueId;
|
||||
int m_linkIndex;
|
||||
};
|
||||
|
||||
struct b3AABBOverlapData
|
||||
{
|
||||
int m_numOverlappingObjects;
|
||||
struct b3OverlappingObject* m_overlappingObjects;
|
||||
};
|
||||
|
||||
struct b3CameraImageData
|
||||
{
|
||||
int m_pixelWidth;
|
||||
@@ -189,6 +223,13 @@ struct b3ContactPointData
|
||||
// double m_angularFrictionForce;
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CONTACT_QUERY_MODE_REPORT_EXISTING_CONTACT_POINTS = 0,
|
||||
CONTACT_QUERY_MODE_COMPUTE_CLOSEST_POINTS = 1,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct b3ContactInformation
|
||||
{
|
||||
@@ -207,6 +248,7 @@ struct b3VisualShapeData
|
||||
char m_meshAssetFileName[VISUAL_SHAPE_MAX_PATH_LEN];
|
||||
double m_localInertiaFrame[7];//pos[3], orn[4]
|
||||
//todo: add more data if necessary (material color etc, although material can be in asset file .obj file)
|
||||
double m_rgbaColor[4];
|
||||
};
|
||||
|
||||
struct b3VisualShapeInformation
|
||||
|
||||
@@ -36,7 +36,6 @@ subject to the following restrictions:
|
||||
#include "../TinyRenderer/model.h"
|
||||
#include "../ThirdPartyLibs/stb_image/stb_image.h"
|
||||
|
||||
|
||||
enum MyFileType
|
||||
{
|
||||
MY_FILE_STL=1,
|
||||
@@ -72,17 +71,35 @@ struct TinyRendererVisualShapeConverterInternalData
|
||||
TGAImage m_rgbColorBuffer;
|
||||
b3AlignedObjectArray<MyTexture2> m_textures;
|
||||
b3AlignedObjectArray<float> m_depthBuffer;
|
||||
b3AlignedObjectArray<float> m_shadowBuffer;
|
||||
b3AlignedObjectArray<int> m_segmentationMaskBuffer;
|
||||
|
||||
btVector3 m_lightDirection;
|
||||
bool m_hasLightDirection;
|
||||
btVector3 m_lightColor;
|
||||
bool m_hasLightColor;
|
||||
float m_lightDistance;
|
||||
bool m_hasLightDistance;
|
||||
float m_lightAmbientCoeff;
|
||||
bool m_hasLightAmbientCoeff;
|
||||
float m_lightDiffuseCoeff;
|
||||
bool m_hasLightDiffuseCoeff;
|
||||
float m_lightSpecularCoeff;
|
||||
bool m_hasLightSpecularCoeff;
|
||||
bool m_hasShadow;
|
||||
SimpleCamera m_camera;
|
||||
|
||||
|
||||
TinyRendererVisualShapeConverterInternalData()
|
||||
:m_upAxis(2),
|
||||
m_swWidth(START_WIDTH),
|
||||
m_swHeight(START_HEIGHT),
|
||||
m_rgbColorBuffer(START_WIDTH,START_HEIGHT,TGAImage::RGB)
|
||||
m_rgbColorBuffer(START_WIDTH,START_HEIGHT,TGAImage::RGB),
|
||||
m_hasLightDirection(false),
|
||||
m_hasLightColor(false),
|
||||
m_hasShadow(false)
|
||||
{
|
||||
m_depthBuffer.resize(m_swWidth*m_swHeight);
|
||||
m_shadowBuffer.resize(m_swWidth*m_swHeight);
|
||||
m_segmentationMaskBuffer.resize(m_swWidth*m_swHeight,-1);
|
||||
}
|
||||
|
||||
@@ -108,8 +125,46 @@ TinyRendererVisualShapeConverter::~TinyRendererVisualShapeConverter()
|
||||
delete m_data;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightDirection(float x, float y, float z)
|
||||
{
|
||||
m_data->m_lightDirection.setValue(x, y, z);
|
||||
m_data->m_hasLightDirection = true;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightColor(float x, float y, float z)
|
||||
{
|
||||
m_data->m_lightColor.setValue(x, y, z);
|
||||
m_data->m_hasLightColor = true;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightDistance(float dist)
|
||||
{
|
||||
m_data->m_lightDistance = dist;
|
||||
m_data->m_hasLightDistance = true;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setShadow(bool hasShadow)
|
||||
{
|
||||
m_data->m_hasShadow = hasShadow;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightAmbientCoeff(float ambientCoeff)
|
||||
{
|
||||
m_data->m_lightAmbientCoeff = ambientCoeff;
|
||||
m_data->m_hasLightAmbientCoeff = true;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightDiffuseCoeff(float diffuseCoeff)
|
||||
{
|
||||
m_data->m_lightDiffuseCoeff = diffuseCoeff;
|
||||
m_data->m_hasLightDiffuseCoeff = true;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::setLightSpecularCoeff(float specularCoeff)
|
||||
{
|
||||
m_data->m_lightSpecularCoeff = specularCoeff;
|
||||
m_data->m_hasLightSpecularCoeff = true;
|
||||
}
|
||||
|
||||
void convertURDFToVisualShape(const UrdfVisual* visual, const char* urdfPathPrefix, const btTransform& visualTransform, btAlignedObjectArray<GLInstanceVertex>& verticesOut, btAlignedObjectArray<int>& indicesOut, btAlignedObjectArray<MyTexture2>& texturesOut, b3VisualShapeData& visualShapeOut)
|
||||
{
|
||||
@@ -527,13 +582,17 @@ void TinyRendererVisualShapeConverter::convertVisualShapes(int linkIndex, const
|
||||
visualShape.m_localInertiaFrame[4] = localInertiaFrame.getRotation()[1];
|
||||
visualShape.m_localInertiaFrame[5] = localInertiaFrame.getRotation()[2];
|
||||
visualShape.m_localInertiaFrame[6] = localInertiaFrame.getRotation()[3];
|
||||
|
||||
visualShape.m_rgbaColor[0] = rgbaColor[0];
|
||||
visualShape.m_rgbaColor[1] = rgbaColor[1];
|
||||
visualShape.m_rgbaColor[2] = rgbaColor[2];
|
||||
visualShape.m_rgbaColor[3] = rgbaColor[3];
|
||||
|
||||
convertURDFToVisualShape(&vis, pathPrefix, localInertiaFrame.inverse()*childTrans, vertices, indices,textures, visualShape);
|
||||
m_data->m_visualShapes.push_back(visualShape);
|
||||
|
||||
if (vertices.size() && indices.size())
|
||||
{
|
||||
TinyRenderObjectData* tinyObj = new TinyRenderObjectData(m_data->m_rgbColorBuffer,m_data->m_depthBuffer, &m_data->m_segmentationMaskBuffer, bodyUniqueId);
|
||||
TinyRenderObjectData* tinyObj = new TinyRenderObjectData(m_data->m_rgbColorBuffer,m_data->m_depthBuffer, &m_data->m_shadowBuffer, &m_data->m_segmentationMaskBuffer, bodyUniqueId);
|
||||
unsigned char* textureImage=0;
|
||||
int textureWidth=0;
|
||||
int textureHeight=0;
|
||||
@@ -639,6 +698,7 @@ void TinyRendererVisualShapeConverter::clearBuffers(TGAColor& clearColor)
|
||||
{
|
||||
m_data->m_rgbColorBuffer.set(x,y,clearColor);
|
||||
m_data->m_depthBuffer[x+y*m_data->m_swWidth] = -1e30f;
|
||||
m_data->m_shadowBuffer[x+y*m_data->m_swWidth] = -1e30f;
|
||||
m_data->m_segmentationMaskBuffer[x+y*m_data->m_swWidth] = -1;
|
||||
}
|
||||
}
|
||||
@@ -673,28 +733,110 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo
|
||||
|
||||
|
||||
btVector3 lightDirWorld(-5,200,-40);
|
||||
switch (m_data->m_upAxis)
|
||||
{
|
||||
case 1:
|
||||
lightDirWorld = btVector3(-50.f,100,30);
|
||||
break;
|
||||
case 2:
|
||||
lightDirWorld = btVector3(-50.f,30,100);
|
||||
break;
|
||||
default:{}
|
||||
};
|
||||
if (m_data->m_hasLightDirection)
|
||||
{
|
||||
lightDirWorld = m_data->m_lightDirection;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (m_data->m_upAxis)
|
||||
{
|
||||
case 1:
|
||||
lightDirWorld = btVector3(-50.f, 100, 30);
|
||||
break;
|
||||
case 2:
|
||||
lightDirWorld = btVector3(-50.f, 30, 100);
|
||||
break;
|
||||
default: {}
|
||||
};
|
||||
}
|
||||
|
||||
lightDirWorld.normalize();
|
||||
|
||||
// printf("num m_swRenderInstances = %d\n", m_data->m_swRenderInstances.size());
|
||||
for (int i=0;i<m_data->m_swRenderInstances.size();i++)
|
||||
btVector3 lightColor(1.0,1.0,1.0);
|
||||
if (m_data->m_hasLightColor)
|
||||
{
|
||||
TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(i);
|
||||
lightColor = m_data->m_lightColor;
|
||||
}
|
||||
|
||||
float lightDistance = 2.0;
|
||||
if (m_data->m_hasLightDistance)
|
||||
{
|
||||
lightDistance = m_data->m_lightDistance;
|
||||
}
|
||||
|
||||
float lightAmbientCoeff = 0.6;
|
||||
if (m_data->m_hasLightAmbientCoeff)
|
||||
{
|
||||
lightAmbientCoeff = m_data->m_lightAmbientCoeff;
|
||||
}
|
||||
|
||||
float lightDiffuseCoeff = 0.35;
|
||||
if (m_data->m_hasLightDiffuseCoeff)
|
||||
{
|
||||
lightDiffuseCoeff = m_data->m_lightDiffuseCoeff;
|
||||
}
|
||||
|
||||
float lightSpecularCoeff = 0.05;
|
||||
if (m_data->m_hasLightSpecularCoeff)
|
||||
{
|
||||
lightSpecularCoeff = m_data->m_lightSpecularCoeff;
|
||||
}
|
||||
|
||||
if (m_data->m_hasShadow)
|
||||
{
|
||||
for (int n=0;n<m_data->m_swRenderInstances.size();n++)
|
||||
{
|
||||
TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(n);
|
||||
if (0==visualArrayPtr)
|
||||
continue;//can this ever happen?
|
||||
TinyRendererObjectArray* visualArray = *visualArrayPtr;
|
||||
|
||||
btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(n);
|
||||
|
||||
|
||||
const btCollisionObject* colObj = (btCollisionObject*) colObjHash.getPointer();
|
||||
|
||||
for (int v=0;v<visualArray->m_renderObjects.size();v++)
|
||||
{
|
||||
|
||||
TinyRenderObjectData* renderObj = visualArray->m_renderObjects[v];
|
||||
|
||||
|
||||
//sync the object transform
|
||||
const btTransform& tr = colObj->getWorldTransform();
|
||||
tr.getOpenGLMatrix(modelMat);
|
||||
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
for (int j=0;j<4;j++)
|
||||
{
|
||||
|
||||
renderObj->m_projectionMatrix[i][j] = projMat[i+4*j];
|
||||
renderObj->m_modelMatrix[i][j] = modelMat[i+4*j];
|
||||
renderObj->m_viewMatrix[i][j] = viewMat[i+4*j];
|
||||
}
|
||||
}
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
renderObj->m_lightColor = lightColor;
|
||||
renderObj->m_lightDistance = lightDistance;
|
||||
renderObj->m_lightAmbientCoeff = lightAmbientCoeff;
|
||||
renderObj->m_lightDiffuseCoeff = lightDiffuseCoeff;
|
||||
renderObj->m_lightSpecularCoeff = lightSpecularCoeff;
|
||||
TinyRenderer::renderObjectDepth(*renderObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int n=0;n<m_data->m_swRenderInstances.size();n++)
|
||||
{
|
||||
TinyRendererObjectArray** visualArrayPtr = m_data->m_swRenderInstances.getAtIndex(n);
|
||||
if (0==visualArrayPtr)
|
||||
continue;//can this ever happen?
|
||||
TinyRendererObjectArray* visualArray = *visualArrayPtr;
|
||||
|
||||
btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(i);
|
||||
|
||||
btHashPtr colObjHash = m_data->m_swRenderInstances.getKeyAtIndex(n);
|
||||
|
||||
|
||||
const btCollisionObject* colObj = (btCollisionObject*) colObjHash.getPointer();
|
||||
@@ -704,11 +846,11 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo
|
||||
|
||||
TinyRenderObjectData* renderObj = visualArray->m_renderObjects[v];
|
||||
|
||||
|
||||
|
||||
//sync the object transform
|
||||
const btTransform& tr = colObj->getWorldTransform();
|
||||
tr.getOpenGLMatrix(modelMat);
|
||||
|
||||
|
||||
for (int i=0;i<4;i++)
|
||||
{
|
||||
for (int j=0;j<4;j++)
|
||||
@@ -717,10 +859,15 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo
|
||||
renderObj->m_projectionMatrix[i][j] = projMat[i+4*j];
|
||||
renderObj->m_modelMatrix[i][j] = modelMat[i+4*j];
|
||||
renderObj->m_viewMatrix[i][j] = viewMat[i+4*j];
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
}
|
||||
}
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
renderObj->m_lightColor = lightColor;
|
||||
renderObj->m_lightDistance = lightDistance;
|
||||
renderObj->m_lightAmbientCoeff = lightAmbientCoeff;
|
||||
renderObj->m_lightDiffuseCoeff = lightDiffuseCoeff;
|
||||
renderObj->m_lightSpecularCoeff = lightSpecularCoeff;
|
||||
TinyRenderer::renderObject(*renderObj);
|
||||
}
|
||||
}
|
||||
@@ -739,6 +886,7 @@ void TinyRendererVisualShapeConverter::render(const float viewMat[16], const flo
|
||||
for (int i=0;i<m_data->m_swWidth;i++)
|
||||
{
|
||||
btSwap(m_data->m_depthBuffer[l1+i],m_data->m_depthBuffer[l2+i]);
|
||||
btSwap(m_data->m_shadowBuffer[l1+i],m_data->m_shadowBuffer[l2+i]);
|
||||
btSwap(m_data->m_segmentationMaskBuffer[l1+i],m_data->m_segmentationMaskBuffer[l2+i]);
|
||||
}
|
||||
}
|
||||
@@ -758,6 +906,7 @@ void TinyRendererVisualShapeConverter::setWidthAndHeight(int width, int height)
|
||||
m_data->m_swHeight = height;
|
||||
|
||||
m_data->m_depthBuffer.resize(m_data->m_swWidth*m_data->m_swHeight);
|
||||
m_data->m_shadowBuffer.resize(m_data->m_swWidth*m_data->m_swHeight);
|
||||
m_data->m_segmentationMaskBuffer.resize(m_data->m_swWidth*m_data->m_swHeight);
|
||||
m_data->m_rgbColorBuffer = TGAImage(width, height, TGAImage::RGB);
|
||||
|
||||
@@ -872,10 +1021,14 @@ int TinyRendererVisualShapeConverter::registerTexture(unsigned char* texels, int
|
||||
return m_data->m_textures.size()-1;
|
||||
}
|
||||
|
||||
void TinyRendererVisualShapeConverter::loadTextureFile(const char* filename)
|
||||
int TinyRendererVisualShapeConverter::loadTextureFile(const char* filename)
|
||||
{
|
||||
int width,height,n;
|
||||
unsigned char* image=0;
|
||||
image = stbi_load(filename, &width, &height, &n, 3);
|
||||
registerTexture(image, width, height);
|
||||
}
|
||||
if (image && (width>=0) && (height>=0))
|
||||
{
|
||||
return registerTexture(image, width, height);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -32,13 +32,20 @@ struct TinyRendererVisualShapeConverter : public LinkVisualShapesConverter
|
||||
|
||||
void getWidthAndHeight(int& width, int& height);
|
||||
void setWidthAndHeight(int width, int height);
|
||||
|
||||
void setLightDirection(float x, float y, float z);
|
||||
void setLightColor(float x, float y, float z);
|
||||
void setLightDistance(float dist);
|
||||
void setLightAmbientCoeff(float ambientCoeff);
|
||||
void setLightDiffuseCoeff(float diffuseCoeff);
|
||||
void setLightSpecularCoeff(float specularCoeff);
|
||||
void setShadow(bool hasShadow);
|
||||
|
||||
void copyCameraImageData(unsigned char* pixelsRGBA, int rgbaBufferSizeInPixels, float* depthBuffer, int depthBufferSizeInPixels,int* segmentationMaskBuffer, int segmentationMaskSizeInPixels, int startPixelIndex, int* widthPtr, int* heightPtr, int* numPixelsCopied);
|
||||
|
||||
void render();
|
||||
void render(const float viewMat[16], const float projMat[16]);
|
||||
|
||||
void loadTextureFile(const char* filename);
|
||||
int loadTextureFile(const char* filename);
|
||||
int registerTexture(unsigned char* texels, int width, int height);
|
||||
void activateShapeTexture(int shapeUniqueId, int textureUniqueId);
|
||||
void activateShapeTexture(int objectUniqueId, int jointIndex, int shapeIndex, int textureUniqueId);
|
||||
|
||||
@@ -42,6 +42,14 @@ myfiles =
|
||||
"PhysicsLoopBack.h",
|
||||
"PhysicsLoopBackC_API.cpp",
|
||||
"PhysicsLoopBackC_API.h",
|
||||
"PhysicsClientSharedMemory_C_API.cpp",
|
||||
"PhysicsClientSharedMemory_C_API.h",
|
||||
"PhysicsClientSharedMemory2_C_API.cpp",
|
||||
"PhysicsClientSharedMemory2_C_API.h",
|
||||
"PhysicsClientSharedMemory2.cpp",
|
||||
"PhysicsClientSharedMemory2.h",
|
||||
"SharedMemoryCommandProcessor.cpp",
|
||||
"SharedMemoryCommandProcessor.h",
|
||||
"PhysicsServerCommandProcessor.cpp",
|
||||
"PhysicsServerCommandProcessor.h",
|
||||
"TinyRendererVisualShapeConverter.cpp",
|
||||
@@ -146,6 +154,37 @@ links {
|
||||
|
||||
language "C++"
|
||||
|
||||
if _OPTIONS["midi"] then
|
||||
|
||||
defines {"B3_USE_MIDI"}
|
||||
|
||||
|
||||
|
||||
includedirs{"../ThirdPartyLibs/midi"}
|
||||
|
||||
files {
|
||||
"../ThirdPartyLibs/midi/RtMidi.cpp",
|
||||
"../ThirdPartyLibs/midi/RtMidi.h",
|
||||
"../ThirdPartyLibs/midi/RtError.h",
|
||||
}
|
||||
if os.is("Windows") then
|
||||
links {"winmm"}
|
||||
defines {"__WINDOWS_MM__", "WIN32"}
|
||||
end
|
||||
|
||||
if os.is("Linux") then
|
||||
defines {"__LINUX_ALSA__"}
|
||||
links {"asound","pthread"}
|
||||
end
|
||||
|
||||
if os.is("MacOSX") then
|
||||
links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"}
|
||||
defines {"__MACOSX_CORE__"}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
files {
|
||||
myfiles,
|
||||
"../StandaloneMain/main_opengl_single_example.cpp",
|
||||
@@ -205,7 +244,37 @@ if os.is("Windows") then
|
||||
else
|
||||
kind "ConsoleApp"
|
||||
end
|
||||
|
||||
if _OPTIONS["midi"] then
|
||||
|
||||
defines {"B3_USE_MIDI"}
|
||||
|
||||
|
||||
|
||||
includedirs{"../ThirdPartyLibs/midi"}
|
||||
|
||||
files {
|
||||
"../ThirdPartyLibs/midi/RtMidi.cpp",
|
||||
"../ThirdPartyLibs/midi/RtMidi.h",
|
||||
"../ThirdPartyLibs/midi/RtError.h",
|
||||
}
|
||||
if os.is("Windows") then
|
||||
links {"winmm"}
|
||||
defines {"__WINDOWS_MM__", "WIN32"}
|
||||
end
|
||||
|
||||
if os.is("Linux") then
|
||||
defines {"__LINUX_ALSA__"}
|
||||
links {"asound","pthread"}
|
||||
end
|
||||
|
||||
if os.is("MacOSX") then
|
||||
links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"}
|
||||
defines {"__MACOSX_CORE__"}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
includedirs {
|
||||
".","../../src", "../ThirdPartyLibs",
|
||||
"../ThirdPartyLibs/openvr/headers",
|
||||
@@ -288,4 +357,7 @@ if os.is("Windows") then
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
include "udp"
|
||||
|
||||
209
examples/SharedMemory/udp/main.cpp
Normal file
209
examples/SharedMemory/udp/main.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
/* server.cpp */
|
||||
#include <stdio.h>
|
||||
#include <enet/enet.h>
|
||||
#include "../../CommonInterfaces/CommonGUIHelperInterface.h"
|
||||
#ifdef NO_SHARED_MEMORY
|
||||
#include "PhysicsServerCommandProcessor.h"
|
||||
typedef PhysicsServerCommandProcessor MyCommandProcessor;
|
||||
#else
|
||||
#include "SharedMemoryCommandProcessor.h"
|
||||
typedef SharedMemoryCommandProcessor MyCommandProcessor ;
|
||||
#endif //NO_SHARED_MEMORY
|
||||
#include "SharedMemoryCommands.h"
|
||||
#include "Bullet3Common/b3AlignedObjectArray.h"
|
||||
#include "PhysicsServerCommandProcessor.h"
|
||||
|
||||
|
||||
bool gVerboseNetworkMessagesServer = false;
|
||||
|
||||
void MySerializeInt(unsigned int sz, unsigned char* output)
|
||||
{
|
||||
unsigned int tmp = sz;
|
||||
output[0] = tmp & 255;
|
||||
tmp = tmp >> 8;
|
||||
output[1] = tmp & 255;
|
||||
tmp = tmp >> 8;
|
||||
output[2] = tmp & 255;
|
||||
tmp = tmp >> 8;
|
||||
output[3] = tmp & 255;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
DummyGUIHelper guiHelper;
|
||||
PhysicsCommandProcessorInterface* sm = new MyCommandProcessor;
|
||||
sm->setGuiHelper(&guiHelper);
|
||||
|
||||
// PhysicsDirect* sm = new PhysicsDirect(sdk);
|
||||
|
||||
//PhysicsClientSharedMemory* sm = new PhysicsClientSharedMemory();
|
||||
|
||||
bool isPhysicsClientConnected = sm->connect();
|
||||
|
||||
if (isPhysicsClientConnected)
|
||||
{
|
||||
|
||||
ENetAddress address;
|
||||
ENetHost *server;
|
||||
ENetEvent event;
|
||||
int serviceResult;
|
||||
|
||||
puts("Starting server");
|
||||
|
||||
if (enet_initialize() != 0)
|
||||
{
|
||||
puts("Error initialising enet");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
/* Bind the server to the default localhost. */
|
||||
/* A specific host address can be specified by */
|
||||
/* enet_address_set_host (& address, "x.x.x.x"); */
|
||||
address.host = ENET_HOST_ANY;
|
||||
/* Bind the server to port 1234. */
|
||||
address.port = 1234;
|
||||
|
||||
server = enet_host_create(&address,
|
||||
32, /* number of clients */
|
||||
2, /* number of channels */
|
||||
0, /* Any incoming bandwith */
|
||||
0); /* Any outgoing bandwith */
|
||||
|
||||
if (server == NULL)
|
||||
{
|
||||
puts("Could not create server host");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
while (true)
|
||||
{
|
||||
serviceResult = 1;
|
||||
|
||||
/* Keep doing host_service until no events are left */
|
||||
while (serviceResult > 0)
|
||||
{
|
||||
/* Wait up to 1000 milliseconds for an event. */
|
||||
serviceResult = enet_host_service(server, &event, 0);
|
||||
if (serviceResult > 0)
|
||||
{
|
||||
|
||||
switch (event.type)
|
||||
{
|
||||
case ENET_EVENT_TYPE_CONNECT:
|
||||
{
|
||||
printf("A new client connected from %x:%u.\n",
|
||||
event.peer->address.host,
|
||||
event.peer->address.port);
|
||||
|
||||
/* Store any relevant client information here. */
|
||||
event.peer->data = (void*)"Client information";
|
||||
|
||||
break;
|
||||
}
|
||||
case ENET_EVENT_TYPE_RECEIVE:
|
||||
{
|
||||
if (gVerboseNetworkMessagesServer)
|
||||
{
|
||||
printf("A packet of length %u containing '%s' was "
|
||||
"received from %s on channel %u.\n",
|
||||
event.packet->dataLength,
|
||||
event.packet->data,
|
||||
event.peer->data,
|
||||
event.channelID);
|
||||
}
|
||||
if (event.packet->dataLength == sizeof(SharedMemoryCommand))
|
||||
{
|
||||
SharedMemoryCommand* cmdPtr = (SharedMemoryCommand*)event.packet->data;
|
||||
SharedMemoryStatus serverStatus;
|
||||
b3AlignedObjectArray<char> buffer;
|
||||
buffer.resize(SHARED_MEMORY_MAX_STREAM_CHUNK_SIZE);
|
||||
|
||||
bool hasStatus = sm->processCommand(*cmdPtr,serverStatus, &buffer[0], buffer.size());
|
||||
|
||||
int timeout = 1024 * 1024 * 1024;
|
||||
while ((!hasStatus) && (timeout-- > 0))
|
||||
{
|
||||
hasStatus = sm->receiveStatus(serverStatus, &buffer[0], buffer.size());
|
||||
|
||||
}
|
||||
if (gVerboseNetworkMessagesServer)
|
||||
{
|
||||
printf("buffer.size = %d\n", buffer.size());
|
||||
printf("serverStatus.m_numDataStreamBytes = %d\n", serverStatus.m_numDataStreamBytes);
|
||||
}
|
||||
if (hasStatus)
|
||||
{
|
||||
//create packetData with [int packetSizeInBytes, status, streamBytes)
|
||||
unsigned char* statBytes = (unsigned char*)&serverStatus;
|
||||
b3AlignedObjectArray<unsigned char> packetData;
|
||||
packetData.resize(4 + sizeof(SharedMemoryStatus) + serverStatus.m_numDataStreamBytes);
|
||||
int sz = packetData.size();
|
||||
int curPos = 0;
|
||||
|
||||
MySerializeInt(sz, &packetData[curPos]);
|
||||
curPos += 4;
|
||||
for (int i = 0; i < sizeof(SharedMemoryStatus); i++)
|
||||
{
|
||||
packetData[i + curPos] = statBytes[i];
|
||||
}
|
||||
curPos += sizeof(SharedMemoryStatus);
|
||||
|
||||
for (int i = 0; i < serverStatus.m_numDataStreamBytes; i++)
|
||||
{
|
||||
packetData[i + curPos] = buffer[i];
|
||||
}
|
||||
|
||||
ENetPacket *packet = enet_packet_create(&packetData[0], packetData.size() , ENET_PACKET_FLAG_RELIABLE);
|
||||
enet_peer_send(event.peer, 0, packet);
|
||||
//enet_host_broadcast(server, 0, packet);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("received packet with unknown contents\n");
|
||||
}
|
||||
|
||||
|
||||
/* Tell all clients about this message */
|
||||
//enet_host_broadcast(server, 0, event.packet);
|
||||
|
||||
break;
|
||||
}
|
||||
case ENET_EVENT_TYPE_DISCONNECT:
|
||||
{
|
||||
printf("%s disconnected.\n", event.peer->data);
|
||||
|
||||
/* Reset the peer's client information. */
|
||||
|
||||
event.peer->data = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (serviceResult > 0)
|
||||
{
|
||||
puts("Error with servicing the server");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
enet_host_destroy(server);
|
||||
enet_deinitialize();
|
||||
}
|
||||
delete sm;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
126
examples/SharedMemory/udp/premake4.lua
Normal file
126
examples/SharedMemory/udp/premake4.lua
Normal file
@@ -0,0 +1,126 @@
|
||||
|
||||
project ("App_PhysicsServerSharedMemoryBridgeUDP")
|
||||
|
||||
language "C++"
|
||||
|
||||
kind "ConsoleApp"
|
||||
|
||||
includedirs {"../../ThirdPartyLibs/enet/include","../../../src",".."}
|
||||
|
||||
if os.is("Windows") then
|
||||
defines { "WIN32" }
|
||||
|
||||
|
||||
links {"Ws2_32","Winmm"}
|
||||
end
|
||||
if os.is("Linux") then
|
||||
end
|
||||
if os.is("MacOSX") then
|
||||
end
|
||||
|
||||
|
||||
links {
|
||||
"enet",
|
||||
"BulletFileLoader",
|
||||
"Bullet3Common",
|
||||
"LinearMath"
|
||||
}
|
||||
|
||||
files {
|
||||
"main.cpp",
|
||||
"../PhysicsClient.cpp",
|
||||
"../PhysicsClient.h",
|
||||
"../PhysicsDirect.cpp",
|
||||
"../PhysicsDirect.h",
|
||||
"../PhysicsCommandProcessorInterface.h",
|
||||
"../SharedMemoryCommandProcessor.cpp",
|
||||
"../SharedMemoryCommandProcessor.h",
|
||||
"../PhysicsClientC_API.cpp",
|
||||
"../PhysicsClientC_API.h",
|
||||
"../Win32SharedMemory.cpp",
|
||||
"../Win32SharedMemory.h",
|
||||
"../PosixSharedMemory.cpp",
|
||||
"../PosixSharedMemory.h",
|
||||
"../../Utils/b3ResourcePath.cpp",
|
||||
"../../Utils/b3ResourcePath.h",
|
||||
}
|
||||
|
||||
|
||||
project "App_PhysicsServerUDP"
|
||||
|
||||
if _OPTIONS["ios"] then
|
||||
kind "WindowedApp"
|
||||
else
|
||||
kind "ConsoleApp"
|
||||
end
|
||||
|
||||
defines { "NO_SHARED_MEMORY" }
|
||||
|
||||
includedirs {"..","../../../src", "../../ThirdPartyLibs","../../ThirdPartyLibs/enet/include"}
|
||||
|
||||
links {
|
||||
"enet","Bullet3Common","BulletInverseDynamicsUtils", "BulletInverseDynamics", "BulletDynamics","BulletCollision", "LinearMath", "BussIK"
|
||||
}
|
||||
|
||||
if os.is("Windows") then
|
||||
defines { "WIN32" }
|
||||
links {"Ws2_32","Winmm"}
|
||||
end
|
||||
|
||||
language "C++"
|
||||
|
||||
myfiles =
|
||||
{
|
||||
"../IKTrajectoryHelper.cpp",
|
||||
"../IKTrajectoryHelper.h",
|
||||
"../SharedMemoryCommands.h",
|
||||
"../SharedMemoryPublic.h",
|
||||
"../PhysicsServerCommandProcessor.cpp",
|
||||
"../PhysicsServerCommandProcessor.h",
|
||||
"../TinyRendererVisualShapeConverter.cpp",
|
||||
"../TinyRendererVisualShapeConverter.h",
|
||||
"../../TinyRenderer/geometry.cpp",
|
||||
"../../TinyRenderer/model.cpp",
|
||||
"../../TinyRenderer/tgaimage.cpp",
|
||||
"../../TinyRenderer/our_gl.cpp",
|
||||
"../../TinyRenderer/TinyRenderer.cpp",
|
||||
"../../OpenGLWindow/SimpleCamera.cpp",
|
||||
"../../OpenGLWindow/SimpleCamera.h",
|
||||
"../../Importers/ImportURDFDemo/ConvertRigidBodies2MultiBody.h",
|
||||
"../../Importers/ImportURDFDemo/MultiBodyCreationInterface.h",
|
||||
"../../Importers/ImportURDFDemo/MyMultiBodyCreator.cpp",
|
||||
"../../Importers/ImportURDFDemo/MyMultiBodyCreator.h",
|
||||
"../../Importers/ImportURDFDemo/BulletUrdfImporter.cpp",
|
||||
"../../Importers/ImportURDFDemo/BulletUrdfImporter.h",
|
||||
"../../Importers/ImportURDFDemo/UrdfParser.cpp",
|
||||
"../../Importers/ImportURDFDemo/urdfStringSplit.cpp",
|
||||
"../../Importers/ImportURDFDemo/UrdfParser.cpp",
|
||||
"../../Importers/ImportURDFDemo/UrdfParser.h",
|
||||
"../../Importers/ImportURDFDemo/URDF2Bullet.cpp",
|
||||
"../../Importers/ImportURDFDemo/URDF2Bullet.h",
|
||||
"../../Utils/b3ResourcePath.cpp",
|
||||
"../../Utils/b3Clock.cpp",
|
||||
"../../../Extras/Serialize/BulletWorldImporter/*",
|
||||
"../../../Extras/Serialize/BulletFileLoader/*",
|
||||
"../../Importers/ImportURDFDemo/URDFImporterInterface.h",
|
||||
"../../Importers/ImportURDFDemo/URDFJointTypes.h",
|
||||
"../../Importers/ImportObjDemo/Wavefront2GLInstanceGraphicsShape.cpp",
|
||||
"../../Importers/ImportObjDemo/LoadMeshFromObj.cpp",
|
||||
"../../Importers/ImportSTLDemo/ImportSTLSetup.h",
|
||||
"../../Importers/ImportSTLDemo/LoadMeshFromSTL.h",
|
||||
"../../Importers/ImportColladaDemo/LoadMeshFromCollada.cpp",
|
||||
"../../Importers/ImportColladaDemo/ColladaGraphicsInstance.h",
|
||||
"../../ThirdPartyLibs/Wavefront/tiny_obj_loader.cpp",
|
||||
"../../ThirdPartyLibs/tinyxml/tinystr.cpp",
|
||||
"../../ThirdPartyLibs/tinyxml/tinyxml.cpp",
|
||||
"../../ThirdPartyLibs/tinyxml/tinyxmlerror.cpp",
|
||||
"../../ThirdPartyLibs/tinyxml/tinyxmlparser.cpp",
|
||||
"../../Importers/ImportMeshUtility/b3ImportMeshUtility.cpp",
|
||||
"../../ThirdPartyLibs/stb_image/stb_image.cpp",
|
||||
}
|
||||
|
||||
files {
|
||||
myfiles,
|
||||
"main.cpp",
|
||||
}
|
||||
|
||||
@@ -2131,12 +2131,12 @@ void SoftDemo::initPhysics()
|
||||
for (int j=0;j<NUM_VERTS_Y-1;j++)
|
||||
{
|
||||
gGroundIndices[index++] = j*NUM_VERTS_X+i;
|
||||
gGroundIndices[index++] = j*NUM_VERTS_X+i+1;
|
||||
gGroundIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
||||
gGroundIndices[index++] = j*NUM_VERTS_X+i+1;;
|
||||
|
||||
gGroundIndices[index++] = j*NUM_VERTS_X+i;
|
||||
gGroundIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
||||
gGroundIndices[index++] = (j+1)*NUM_VERTS_X+i;
|
||||
gGroundIndices[index++] = (j+1)*NUM_VERTS_X+i+1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
#ifdef BT_ENABLE_VR
|
||||
//#define BT_USE_CUSTOM_PROFILER
|
||||
#ifdef BT_USE_CUSTOM_PROFILER
|
||||
#endif
|
||||
|
||||
//========= Copyright Valve Corporation ============//
|
||||
|
||||
#include "../OpenGLWindow/SimpleOpenGL3App.h"
|
||||
#include "../OpenGLWindow/OpenGLInclude.h"
|
||||
#include "Bullet3Common/b3Quaternion.h"
|
||||
#include "Bullet3Common/b3Transform.h"
|
||||
#include "Bullet3Common/b3CommandLineArgs.h"
|
||||
|
||||
|
||||
#include "../ExampleBrowser/OpenGLGuiHelper.h"
|
||||
@@ -673,7 +676,7 @@ bool CMainApplication::HandleInput()
|
||||
for( vr::TrackedDeviceIndex_t unDevice = 0; unDevice < vr::k_unMaxTrackedDeviceCount; unDevice++ )
|
||||
{
|
||||
vr::VRControllerState_t state;
|
||||
if( m_pHMD->GetControllerState( unDevice, &state ) )
|
||||
if( m_pHMD->GetControllerState( unDevice, &state ,sizeof(vr::VRControllerState_t)) )
|
||||
{
|
||||
//we need to have the 'move' events, so no early out here
|
||||
//if (sPrevStates[unDevice].unPacketNum != state.unPacketNum)
|
||||
@@ -776,12 +779,14 @@ void CMainApplication::RunMainLoop()
|
||||
|
||||
while ( !bQuit && !m_app->m_window->requestedExit())
|
||||
{
|
||||
{
|
||||
B3_PROFILE("main");
|
||||
|
||||
bQuit = HandleInput();
|
||||
|
||||
RenderFrame();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -844,7 +849,7 @@ void CMainApplication::RenderFrame()
|
||||
// happen right before and after the vsync causing all kinds of jittering issues. This glFinish()
|
||||
// appears to clear that up. Temporary fix while I try to get nvidia to investigate this problem.
|
||||
// 1/29/2014 mikesart
|
||||
glFinish();
|
||||
//glFinish();
|
||||
}
|
||||
|
||||
// SwapWindow
|
||||
@@ -1282,6 +1287,8 @@ void CMainApplication::AddCubeToScene( Matrix4 mat, std::vector<float> &vertdata
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Draw all of the controllers as X/Y/Z lines
|
||||
//-----------------------------------------------------------------------------
|
||||
extern int gGraspingController;
|
||||
|
||||
void CMainApplication::DrawControllers()
|
||||
{
|
||||
// don't draw controllers if somebody else has input focus
|
||||
@@ -1295,6 +1302,8 @@ void CMainApplication::DrawControllers()
|
||||
|
||||
for ( vr::TrackedDeviceIndex_t unTrackedDevice = vr::k_unTrackedDeviceIndex_Hmd + 1; unTrackedDevice < vr::k_unMaxTrackedDeviceCount; ++unTrackedDevice )
|
||||
{
|
||||
|
||||
|
||||
if ( !m_pHMD->IsTrackedDeviceConnected( unTrackedDevice ) )
|
||||
continue;
|
||||
|
||||
@@ -1479,8 +1488,9 @@ void CMainApplication::SetupDistortion()
|
||||
u = x*w; v = 1-y*h;
|
||||
vert.position = Vector2( Xoffset+u, -1+2*y*h );
|
||||
|
||||
vr::DistortionCoordinates_t dc0 = m_pHMD->ComputeDistortion(vr::Eye_Left, u, v);
|
||||
|
||||
vr::DistortionCoordinates_t dc0;
|
||||
bool result = m_pHMD->ComputeDistortion(vr::Eye_Left, u, v,&dc0);
|
||||
btAssert(result);
|
||||
vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]);
|
||||
vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]);
|
||||
vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]);
|
||||
@@ -1498,8 +1508,9 @@ void CMainApplication::SetupDistortion()
|
||||
u = x*w; v = 1-y*h;
|
||||
vert.position = Vector2( Xoffset+u, -1+2*y*h );
|
||||
|
||||
vr::DistortionCoordinates_t dc0 = m_pHMD->ComputeDistortion( vr::Eye_Right, u, v );
|
||||
|
||||
vr::DistortionCoordinates_t dc0;
|
||||
bool result = m_pHMD->ComputeDistortion( vr::Eye_Right, u, v,&dc0 );
|
||||
btAssert(result);
|
||||
vert.texCoordRed = Vector2(dc0.rfRed[0], 1 - dc0.rfRed[1]);
|
||||
vert.texCoordGreen = Vector2(dc0.rfGreen[0], 1 - dc0.rfGreen[1]);
|
||||
vert.texCoordBlue = Vector2(dc0.rfBlue[0], 1 - dc0.rfBlue[1]);
|
||||
@@ -2183,9 +2194,11 @@ void CGLRenderModel::Draw()
|
||||
//-----------------------------------------------------------------------------
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
|
||||
|
||||
#ifdef BT_USE_CUSTOM_PROFILER
|
||||
//b3SetCustomEnterProfileZoneFunc(...);
|
||||
//b3SetCustomLeaveProfileZoneFunc(...);
|
||||
b3SetCustomEnterProfileZoneFunc(dcEnter);
|
||||
b3SetCustomLeaveProfileZoneFunc(dcLeave);
|
||||
#endif
|
||||
|
||||
|
||||
@@ -2223,7 +2236,6 @@ int main(int argc, char *argv[])
|
||||
pMainApplication->Shutdown();
|
||||
|
||||
#ifdef BT_USE_CUSTOM_PROFILER
|
||||
//...
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -83,8 +83,11 @@ int main(int argc, char* argv[])
|
||||
//DummyGUIHelper gui;
|
||||
|
||||
CommonExampleOptions options(&gui);
|
||||
|
||||
|
||||
example = StandaloneExampleCreateFunc(options);
|
||||
example->processCommandLineArgs(argc, argv);
|
||||
|
||||
example->initPhysics();
|
||||
example->resetCamera();
|
||||
|
||||
|
||||
@@ -209,10 +209,13 @@ public:
|
||||
renderObj->m_projectionMatrix[i][j] = projMat[i+4*j];
|
||||
renderObj->m_modelMatrix[i][j] = modelMat[i+4*j];
|
||||
renderObj->m_viewMatrix[i][j] = viewMat[i+4*j];
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
}
|
||||
}
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
renderObj->m_lightAmbientCoeff = 0.6;
|
||||
renderObj->m_lightDiffuseCoeff = 0.35;
|
||||
renderObj->m_lightSpecularCoeff = 0.05;
|
||||
TinyRenderer::renderObject(*renderObj);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,10 +230,13 @@ struct TinyRendererGUIHelper : public GUIHelperInterface
|
||||
renderObj->m_projectionMatrix[i][j] = projMat[i+4*j];
|
||||
renderObj->m_modelMatrix[i][j] = modelMat[i+4*j];
|
||||
renderObj->m_viewMatrix[i][j] = viewMat[i+4*j];
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
}
|
||||
}
|
||||
renderObj->m_localScaling = colObj->getCollisionShape()->getLocalScaling();
|
||||
renderObj->m_lightDirWorld = lightDirWorld;
|
||||
renderObj->m_lightAmbientCoeff = 0.6;
|
||||
renderObj->m_lightDiffuseCoeff = 0.35;
|
||||
renderObj->m_lightSpecularCoeff = 0.05;
|
||||
TinyRenderer::renderObject(*renderObj);
|
||||
}
|
||||
}
|
||||
@@ -379,6 +382,20 @@ struct TinyRendererGUIHelper : public GUIHelperInterface
|
||||
|
||||
virtual void drawText3D( const char* txt, float posX, float posZY, float posZ, float size)
|
||||
{
|
||||
}
|
||||
virtual int addUserDebugText3D( const char* txt, const double positionXYZ[3], const double textColorRGB[3], double size, double lifeTime)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual int addUserDebugLine(const double debugLineFromXYZ[3], const double debugLineToXYZ[3], const double debugLineColorRGB[3], double lineWidth, double lifeTime )
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
virtual void removeUserDebugItem( int debugItemUniqueId)
|
||||
{
|
||||
}
|
||||
virtual void removeAllUserDebugItems( )
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -98,10 +98,10 @@ Node* Tree::SearchJoint(Node* node, int index)
|
||||
if (node->seqNumJoint == index) {
|
||||
return node;
|
||||
} else {
|
||||
if (ret = SearchJoint(node->left, index)) {
|
||||
if ((ret = SearchJoint(node->left, index))) {
|
||||
return ret;
|
||||
}
|
||||
if (ret = SearchJoint(node->right, index)) {
|
||||
if ((ret = SearchJoint(node->right, index))) {
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
@@ -127,10 +127,10 @@ Node* Tree::SearchEffector(Node* node, int index)
|
||||
if (node->seqNumEffector == index) {
|
||||
return node;
|
||||
} else {
|
||||
if (ret = SearchEffector(node->left, index)) {
|
||||
if ((ret = SearchEffector(node->left, index))) {
|
||||
return ret;
|
||||
}
|
||||
if (ret = SearchEffector(node->right, index)) {
|
||||
if ((ret = SearchEffector(node->right, index))) {
|
||||
return ret;
|
||||
}
|
||||
return NULL;
|
||||
@@ -214,4 +214,4 @@ void Tree::UnFreezeTree(Node* node)
|
||||
void Tree::UnFreeze(void)
|
||||
{
|
||||
UnFreezeTree(root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,7 @@
|
||||
files{"unix.c"}
|
||||
end
|
||||
|
||||
targetdir "../../../lib"
|
||||
|
||||
|
||||
includedirs {
|
||||
".","include"
|
||||
}
|
||||
|
||||
29
examples/ThirdPartyLibs/midi/LICENSE.txt
Normal file
29
examples/ThirdPartyLibs/midi/LICENSE.txt
Normal file
@@ -0,0 +1,29 @@
|
||||
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
|
||||
|
||||
RtMidi: realtime MIDI i/o C++ classes
|
||||
Copyright (c) 2003-2012 Gary P. Scavone
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
asked to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version. This is,
|
||||
however, not a binding provision of this license.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
60
examples/ThirdPartyLibs/midi/RtError.h
Normal file
60
examples/ThirdPartyLibs/midi/RtError.h
Normal file
@@ -0,0 +1,60 @@
|
||||
/************************************************************************/
|
||||
/*! \class RtError
|
||||
\brief Exception handling class for RtAudio & RtMidi.
|
||||
|
||||
The RtError class is quite simple but it does allow errors to be
|
||||
"caught" by RtError::Type. See the RtAudio and RtMidi
|
||||
documentation to know which methods can throw an RtError.
|
||||
|
||||
*/
|
||||
/************************************************************************/
|
||||
|
||||
#ifndef RTERROR_H
|
||||
#define RTERROR_H
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
class RtError : public std::exception
|
||||
{
|
||||
public:
|
||||
//! Defined RtError types.
|
||||
enum Type {
|
||||
WARNING, /*!< A non-critical error. */
|
||||
DEBUG_WARNING, /*!< A non-critical error which might be useful for debugging. */
|
||||
UNSPECIFIED, /*!< The default, unspecified error type. */
|
||||
NO_DEVICES_FOUND, /*!< No devices found on system. */
|
||||
INVALID_DEVICE, /*!< An invalid device ID was specified. */
|
||||
MEMORY_ERROR, /*!< An error occured during memory allocation. */
|
||||
INVALID_PARAMETER, /*!< An invalid parameter was specified to a function. */
|
||||
INVALID_USE, /*!< The function was called incorrectly. */
|
||||
DRIVER_ERROR, /*!< A system driver error occured. */
|
||||
SYSTEM_ERROR, /*!< A system error occured. */
|
||||
THREAD_ERROR /*!< A thread error occured. */
|
||||
};
|
||||
|
||||
//! The constructor.
|
||||
RtError(const std::string& message, Type type = RtError::UNSPECIFIED) throw() : message_(message), type_(type) {}
|
||||
|
||||
//! The destructor.
|
||||
virtual ~RtError(void) throw() {}
|
||||
|
||||
//! Prints thrown error message to stderr.
|
||||
virtual void printMessage(void) const throw() { std::cerr << '\n' << message_ << "\n\n"; }
|
||||
|
||||
//! Returns the thrown error message type.
|
||||
virtual const Type& getType(void) const throw() { return type_; }
|
||||
|
||||
//! Returns the thrown error message string.
|
||||
virtual const std::string& getMessage(void) const throw() { return message_; }
|
||||
|
||||
//! Returns the thrown error message as a c-style string.
|
||||
virtual const char* what(void) const throw() { return message_.c_str(); }
|
||||
|
||||
protected:
|
||||
std::string message_;
|
||||
Type type_;
|
||||
};
|
||||
|
||||
#endif
|
||||
3803
examples/ThirdPartyLibs/midi/RtMidi.cpp
Normal file
3803
examples/ThirdPartyLibs/midi/RtMidi.cpp
Normal file
File diff suppressed because it is too large
Load Diff
675
examples/ThirdPartyLibs/midi/RtMidi.h
Normal file
675
examples/ThirdPartyLibs/midi/RtMidi.h
Normal file
@@ -0,0 +1,675 @@
|
||||
/**********************************************************************/
|
||||
/*! \class RtMidi
|
||||
\brief An abstract base class for realtime MIDI input/output.
|
||||
|
||||
This class implements some common functionality for the realtime
|
||||
MIDI input/output subclasses RtMidiIn and RtMidiOut.
|
||||
|
||||
RtMidi WWW site: http://music.mcgill.ca/~gary/rtmidi/
|
||||
|
||||
RtMidi: realtime MIDI i/o C++ classes
|
||||
Copyright (c) 2003-2012 Gary P. Scavone
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation files
|
||||
(the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
Any person wishing to distribute modifications to the Software is
|
||||
asked to send the modifications to the original developer so that
|
||||
they can be incorporated into the canonical version. This is,
|
||||
however, not a binding provision of this license.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
|
||||
ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
|
||||
CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
/**********************************************************************/
|
||||
|
||||
/*!
|
||||
\file RtMidi.h
|
||||
*/
|
||||
|
||||
// RtMidi: Version 2.0.1
|
||||
|
||||
#ifndef RTMIDI_H
|
||||
#define RTMIDI_H
|
||||
|
||||
#include "RtError.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class RtMidi
|
||||
{
|
||||
public:
|
||||
|
||||
//! MIDI API specifier arguments.
|
||||
enum Api {
|
||||
UNSPECIFIED, /*!< Search for a working compiled API. */
|
||||
MACOSX_CORE, /*!< Macintosh OS-X Core Midi API. */
|
||||
LINUX_ALSA, /*!< The Advanced Linux Sound Architecture API. */
|
||||
UNIX_JACK, /*!< The Jack Low-Latency MIDI Server API. */
|
||||
WINDOWS_MM, /*!< The Microsoft Multimedia MIDI API. */
|
||||
WINDOWS_KS, /*!< The Microsoft Kernel Streaming MIDI API. */
|
||||
RTMIDI_DUMMY /*!< A compilable but non-functional API. */
|
||||
};
|
||||
|
||||
//! A static function to determine the available compiled MIDI APIs.
|
||||
/*!
|
||||
The values returned in the std::vector can be compared against
|
||||
the enumerated list values. Note that there can be more than one
|
||||
API compiled for certain operating systems.
|
||||
*/
|
||||
static void getCompiledApi( std::vector<RtMidi::Api> &apis );
|
||||
|
||||
//! Pure virtual openPort() function.
|
||||
virtual void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi" ) ) = 0;
|
||||
|
||||
//! Pure virtual openVirtualPort() function.
|
||||
virtual void openVirtualPort( const std::string portName = std::string( "RtMidi" ) ) = 0;
|
||||
|
||||
//! Pure virtual getPortCount() function.
|
||||
virtual unsigned int getPortCount() = 0;
|
||||
|
||||
//! Pure virtual getPortName() function.
|
||||
virtual std::string getPortName( unsigned int portNumber = 0 ) = 0;
|
||||
|
||||
//! Pure virtual closePort() function.
|
||||
virtual void closePort( void ) = 0;
|
||||
|
||||
//! A basic error reporting function for RtMidi classes.
|
||||
static void error( RtError::Type type, std::string errorString );
|
||||
|
||||
protected:
|
||||
|
||||
RtMidi() {};
|
||||
virtual ~RtMidi() {};
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
/*! \class RtMidiIn
|
||||
\brief A realtime MIDI input class.
|
||||
|
||||
This class provides a common, platform-independent API for
|
||||
realtime MIDI input. It allows access to a single MIDI input
|
||||
port. Incoming MIDI messages are either saved to a queue for
|
||||
retrieval using the getMessage() function or immediately passed to
|
||||
a user-specified callback function. Create multiple instances of
|
||||
this class to connect to more than one MIDI device at the same
|
||||
time. With the OS-X and Linux ALSA MIDI APIs, it is also possible
|
||||
to open a virtual input port to which other MIDI software clients
|
||||
can connect.
|
||||
|
||||
by Gary P. Scavone, 2003-2012.
|
||||
*/
|
||||
/**********************************************************************/
|
||||
|
||||
// **************************************************************** //
|
||||
//
|
||||
// RtMidiIn and RtMidiOut class declarations.
|
||||
//
|
||||
// RtMidiIn / RtMidiOut are "controllers" used to select an available
|
||||
// MIDI input or output interface. They present common APIs for the
|
||||
// user to call but all functionality is implemented by the classes
|
||||
// MidiInApi, MidiOutApi and their subclasses. RtMidiIn and RtMidiOut
|
||||
// each create an instance of a MidiInApi or MidiOutApi subclass based
|
||||
// on the user's API choice. If no choice is made, they attempt to
|
||||
// make a "logical" API selection.
|
||||
//
|
||||
// **************************************************************** //
|
||||
|
||||
class MidiInApi;
|
||||
class MidiOutApi;
|
||||
|
||||
class RtMidiIn : public RtMidi
|
||||
{
|
||||
public:
|
||||
|
||||
//! User callback function type definition.
|
||||
typedef void (*RtMidiCallback)( double timeStamp, std::vector<unsigned char> *message, void *userData);
|
||||
|
||||
//! Default constructor that allows an optional api, client name and queue size.
|
||||
/*!
|
||||
An assert will be fired if a MIDI system initialization
|
||||
error occurs. The queue size defines the maximum number of
|
||||
messages that can be held in the MIDI queue (when not using a
|
||||
callback function). If the queue size limit is reached,
|
||||
incoming messages will be ignored.
|
||||
|
||||
If no API argument is specified and multiple API support has been
|
||||
compiled, the default order of use is JACK, ALSA (Linux) and CORE,
|
||||
Jack (OS-X).
|
||||
*/
|
||||
RtMidiIn( RtMidi::Api api=UNSPECIFIED,
|
||||
const std::string clientName = std::string( "RtMidi Input Client"),
|
||||
unsigned int queueSizeLimit = 100 );
|
||||
|
||||
//! If a MIDI connection is still open, it will be closed by the destructor.
|
||||
~RtMidiIn ( void );
|
||||
|
||||
//! Returns the MIDI API specifier for the current instance of RtMidiIn.
|
||||
RtMidi::Api getCurrentApi( void );
|
||||
|
||||
//! Open a MIDI input connection.
|
||||
/*!
|
||||
An optional port number greater than 0 can be specified.
|
||||
Otherwise, the default or first port found is opened.
|
||||
*/
|
||||
void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Input" ) );
|
||||
|
||||
//! Create a virtual input port, with optional name, to allow software connections (OS X and ALSA only).
|
||||
/*!
|
||||
This function creates a virtual MIDI input port to which other
|
||||
software applications can connect. This type of functionality
|
||||
is currently only supported by the Macintosh OS-X and Linux ALSA
|
||||
APIs (the function does nothing for the other APIs).
|
||||
*/
|
||||
void openVirtualPort( const std::string portName = std::string( "RtMidi Input" ) );
|
||||
|
||||
//! Set a callback function to be invoked for incoming MIDI messages.
|
||||
/*!
|
||||
The callback function will be called whenever an incoming MIDI
|
||||
message is received. While not absolutely necessary, it is best
|
||||
to set the callback function before opening a MIDI port to avoid
|
||||
leaving some messages in the queue.
|
||||
*/
|
||||
void setCallback( RtMidiCallback callback, void *userData = 0 );
|
||||
|
||||
//! Cancel use of the current callback function (if one exists).
|
||||
/*!
|
||||
Subsequent incoming MIDI messages will be written to the queue
|
||||
and can be retrieved with the \e getMessage function.
|
||||
*/
|
||||
void cancelCallback();
|
||||
|
||||
//! Close an open MIDI connection (if one exists).
|
||||
void closePort( void );
|
||||
|
||||
//! Return the number of available MIDI input ports.
|
||||
unsigned int getPortCount();
|
||||
|
||||
//! Return a string identifier for the specified MIDI input port number.
|
||||
/*!
|
||||
An empty string is returned if an invalid port specifier is provided.
|
||||
*/
|
||||
std::string getPortName( unsigned int portNumber = 0 );
|
||||
|
||||
//! Specify whether certain MIDI message types should be queued or ignored during input.
|
||||
/*!
|
||||
o By default, MIDI timing and active sensing messages are ignored
|
||||
during message input because of their relative high data rates.
|
||||
MIDI sysex messages are ignored by default as well. Variable
|
||||
values of "true" imply that the respective message type will be
|
||||
ignored.
|
||||
*/
|
||||
void ignoreTypes( bool midiSysex = true, bool midiTime = true, bool midiSense = true );
|
||||
|
||||
//! Fill the user-provided vector with the data bytes for the next available MIDI message in the input queue and return the event delta-time in seconds.
|
||||
/*!
|
||||
This function returns immediately whether a new message is
|
||||
available or not. A valid message is indicated by a non-zero
|
||||
vector size. An assert is fired if an error occurs during
|
||||
message retrieval or an input connection was not previously
|
||||
established.
|
||||
*/
|
||||
double getMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void openMidiApi( RtMidi::Api api, const std::string clientName, unsigned int queueSizeLimit );
|
||||
MidiInApi *rtapi_;
|
||||
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
/*! \class RtMidiOut
|
||||
\brief A realtime MIDI output class.
|
||||
|
||||
This class provides a common, platform-independent API for MIDI
|
||||
output. It allows one to probe available MIDI output ports, to
|
||||
connect to one such port, and to send MIDI bytes immediately over
|
||||
the connection. Create multiple instances of this class to
|
||||
connect to more than one MIDI device at the same time. With the
|
||||
OS-X and Linux ALSA MIDI APIs, it is also possible to open a
|
||||
virtual port to which other MIDI software clients can connect.
|
||||
|
||||
by Gary P. Scavone, 2003-2012.
|
||||
*/
|
||||
/**********************************************************************/
|
||||
|
||||
class RtMidiOut : public RtMidi
|
||||
{
|
||||
public:
|
||||
|
||||
//! Default constructor that allows an optional client name.
|
||||
/*!
|
||||
An exception will be thrown if a MIDI system initialization error occurs.
|
||||
|
||||
If no API argument is specified and multiple API support has been
|
||||
compiled, the default order of use is JACK, ALSA (Linux) and CORE,
|
||||
Jack (OS-X).
|
||||
*/
|
||||
RtMidiOut( RtMidi::Api api=UNSPECIFIED,
|
||||
const std::string clientName = std::string( "RtMidi Output Client") );
|
||||
|
||||
//! The destructor closes any open MIDI connections.
|
||||
~RtMidiOut( void );
|
||||
|
||||
//! Returns the MIDI API specifier for the current instance of RtMidiOut.
|
||||
RtMidi::Api getCurrentApi( void );
|
||||
|
||||
//! Open a MIDI output connection.
|
||||
/*!
|
||||
An optional port number greater than 0 can be specified.
|
||||
Otherwise, the default or first port found is opened. An
|
||||
exception is thrown if an error occurs while attempting to make
|
||||
the port connection.
|
||||
*/
|
||||
void openPort( unsigned int portNumber = 0, const std::string portName = std::string( "RtMidi Output" ) );
|
||||
|
||||
//! Close an open MIDI connection (if one exists).
|
||||
void closePort( void );
|
||||
|
||||
//! Create a virtual output port, with optional name, to allow software connections (OS X and ALSA only).
|
||||
/*!
|
||||
This function creates a virtual MIDI output port to which other
|
||||
software applications can connect. This type of functionality
|
||||
is currently only supported by the Macintosh OS-X and Linux ALSA
|
||||
APIs (the function does nothing with the other APIs). An
|
||||
exception is thrown if an error occurs while attempting to create
|
||||
the virtual port.
|
||||
*/
|
||||
void openVirtualPort( const std::string portName = std::string( "RtMidi Output" ) );
|
||||
|
||||
//! Return the number of available MIDI output ports.
|
||||
unsigned int getPortCount( void );
|
||||
|
||||
//! Return a string identifier for the specified MIDI port type and number.
|
||||
/*!
|
||||
An empty string is returned if an invalid port specifier is provided.
|
||||
*/
|
||||
std::string getPortName( unsigned int portNumber = 0 );
|
||||
|
||||
//! Immediately send a single message out an open MIDI output port.
|
||||
/*!
|
||||
An exception is thrown if an error occurs during output or an
|
||||
output connection was not previously established.
|
||||
*/
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void openMidiApi( RtMidi::Api api, const std::string clientName );
|
||||
MidiOutApi *rtapi_;
|
||||
};
|
||||
|
||||
|
||||
// **************************************************************** //
|
||||
//
|
||||
// MidiInApi / MidiOutApi class declarations.
|
||||
//
|
||||
// Subclasses of MidiInApi and MidiOutApi contain all API- and
|
||||
// OS-specific code necessary to fully implement the RtMidi API.
|
||||
//
|
||||
// Note that MidiInApi and MidiOutApi are abstract base classes and
|
||||
// cannot be explicitly instantiated. RtMidiIn and RtMidiOut will
|
||||
// create instances of a MidiInApi or MidiOutApi subclass.
|
||||
//
|
||||
// **************************************************************** //
|
||||
|
||||
class MidiInApi
|
||||
{
|
||||
public:
|
||||
|
||||
MidiInApi( unsigned int queueSizeLimit );
|
||||
virtual ~MidiInApi( void );
|
||||
virtual RtMidi::Api getCurrentApi( void ) = 0;
|
||||
virtual void openPort( unsigned int portNumber, const std::string portName ) = 0;
|
||||
virtual void openVirtualPort( const std::string portName ) = 0;
|
||||
virtual void closePort( void ) = 0;
|
||||
void setCallback( RtMidiIn::RtMidiCallback callback, void *userData );
|
||||
void cancelCallback( void );
|
||||
virtual unsigned int getPortCount( void ) = 0;
|
||||
virtual std::string getPortName( unsigned int portNumber ) = 0;
|
||||
virtual void ignoreTypes( bool midiSysex, bool midiTime, bool midiSense );
|
||||
double getMessage( std::vector<unsigned char> *message );
|
||||
|
||||
// A MIDI structure used internally by the class to store incoming
|
||||
// messages. Each message represents one and only one MIDI message.
|
||||
struct MidiMessage {
|
||||
std::vector<unsigned char> bytes;
|
||||
double timeStamp;
|
||||
|
||||
// Default constructor.
|
||||
MidiMessage()
|
||||
:bytes(0), timeStamp(0.0) {}
|
||||
};
|
||||
|
||||
struct MidiQueue {
|
||||
unsigned int front;
|
||||
unsigned int back;
|
||||
unsigned int size;
|
||||
unsigned int ringSize;
|
||||
MidiMessage *ring;
|
||||
|
||||
// Default constructor.
|
||||
MidiQueue()
|
||||
:front(0), back(0), size(0), ringSize(0) {}
|
||||
};
|
||||
|
||||
// The RtMidiInData structure is used to pass private class data to
|
||||
// the MIDI input handling function or thread.
|
||||
struct RtMidiInData {
|
||||
MidiQueue queue;
|
||||
MidiMessage message;
|
||||
unsigned char ignoreFlags;
|
||||
bool doInput;
|
||||
bool firstMessage;
|
||||
void *apiData;
|
||||
bool usingCallback;
|
||||
void *userCallback;
|
||||
void *userData;
|
||||
bool continueSysex;
|
||||
|
||||
// Default constructor.
|
||||
RtMidiInData()
|
||||
: ignoreFlags(7), doInput(false), firstMessage(true),
|
||||
apiData(0), usingCallback(false), userCallback(0), userData(0),
|
||||
continueSysex(false) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
virtual void initialize( const std::string& clientName ) = 0;
|
||||
RtMidiInData inputData_;
|
||||
|
||||
void *apiData_;
|
||||
bool connected_;
|
||||
std::string errorString_;
|
||||
};
|
||||
|
||||
class MidiOutApi
|
||||
{
|
||||
public:
|
||||
|
||||
MidiOutApi( void );
|
||||
virtual ~MidiOutApi( void );
|
||||
virtual RtMidi::Api getCurrentApi( void ) = 0;
|
||||
virtual void openPort( unsigned int portNumber, const std::string portName ) = 0;
|
||||
virtual void openVirtualPort( const std::string portName ) = 0;
|
||||
virtual void closePort( void ) = 0;
|
||||
virtual unsigned int getPortCount( void ) = 0;
|
||||
virtual std::string getPortName( unsigned int portNumber ) = 0;
|
||||
virtual void sendMessage( std::vector<unsigned char> *message ) = 0;
|
||||
|
||||
protected:
|
||||
virtual void initialize( const std::string& clientName ) = 0;
|
||||
|
||||
void *apiData_;
|
||||
bool connected_;
|
||||
std::string errorString_;
|
||||
};
|
||||
|
||||
// **************************************************************** //
|
||||
//
|
||||
// Inline RtMidiIn and RtMidiOut definitions.
|
||||
//
|
||||
// **************************************************************** //
|
||||
|
||||
inline RtMidi::Api RtMidiIn :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); }
|
||||
inline void RtMidiIn :: openPort( unsigned int portNumber, const std::string portName ) { return rtapi_->openPort( portNumber, portName ); }
|
||||
inline void RtMidiIn :: openVirtualPort( const std::string portName ) { return rtapi_->openVirtualPort( portName ); }
|
||||
inline void RtMidiIn :: closePort( void ) { return rtapi_->closePort(); }
|
||||
inline void RtMidiIn :: setCallback( RtMidiCallback callback, void *userData ) { return rtapi_->setCallback( callback, userData ); }
|
||||
inline void RtMidiIn :: cancelCallback( void ) { return rtapi_->cancelCallback(); }
|
||||
inline unsigned int RtMidiIn :: getPortCount( void ) { return rtapi_->getPortCount(); }
|
||||
inline std::string RtMidiIn :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
|
||||
inline void RtMidiIn :: ignoreTypes( bool midiSysex, bool midiTime, bool midiSense ) { return rtapi_->ignoreTypes( midiSysex, midiTime, midiSense ); }
|
||||
inline double RtMidiIn :: getMessage( std::vector<unsigned char> *message ) { return rtapi_->getMessage( message ); }
|
||||
|
||||
inline RtMidi::Api RtMidiOut :: getCurrentApi( void ) { return rtapi_->getCurrentApi(); }
|
||||
inline void RtMidiOut :: openPort( unsigned int portNumber, const std::string portName ) { return rtapi_->openPort( portNumber, portName ); }
|
||||
inline void RtMidiOut :: openVirtualPort( const std::string portName ) { return rtapi_->openVirtualPort( portName ); }
|
||||
inline void RtMidiOut :: closePort( void ) { return rtapi_->closePort(); }
|
||||
inline unsigned int RtMidiOut :: getPortCount( void ) { return rtapi_->getPortCount(); }
|
||||
inline std::string RtMidiOut :: getPortName( unsigned int portNumber ) { return rtapi_->getPortName( portNumber ); }
|
||||
inline void RtMidiOut :: sendMessage( std::vector<unsigned char> *message ) { return rtapi_->sendMessage( message ); }
|
||||
|
||||
// **************************************************************** //
|
||||
//
|
||||
// MidiInApi and MidiOutApi subclass prototypes.
|
||||
//
|
||||
// **************************************************************** //
|
||||
|
||||
#if !defined(__LINUX_ALSA__) && !defined(__UNIX_JACK__) && !defined(__MACOSX_CORE__) && !defined(__WINDOWS_MM__) && !defined(__WINDOWS_KS__)
|
||||
#define __RTMIDI_DUMMY__
|
||||
#endif
|
||||
|
||||
#if defined(__MACOSX_CORE__)
|
||||
|
||||
class MidiInCore: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInCore( const std::string clientName, unsigned int queueSizeLimit );
|
||||
~MidiInCore( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
class MidiOutCore: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutCore( const std::string clientName );
|
||||
~MidiOutCore( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::MACOSX_CORE; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__UNIX_JACK__)
|
||||
|
||||
class MidiInJack: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInJack( const std::string clientName, unsigned int queueSizeLimit );
|
||||
~MidiInJack( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
class MidiOutJack: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutJack( const std::string clientName );
|
||||
~MidiOutJack( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::UNIX_JACK; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__LINUX_ALSA__)
|
||||
|
||||
class MidiInAlsa: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInAlsa( const std::string clientName, unsigned int queueSizeLimit );
|
||||
~MidiInAlsa( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
class MidiOutAlsa: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutAlsa( const std::string clientName );
|
||||
~MidiOutAlsa( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::LINUX_ALSA; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__WINDOWS_MM__)
|
||||
|
||||
class MidiInWinMM: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInWinMM( const std::string clientName, unsigned int queueSizeLimit );
|
||||
~MidiInWinMM( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
class MidiOutWinMM: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutWinMM( const std::string clientName );
|
||||
~MidiOutWinMM( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_MM; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__WINDOWS_KS__)
|
||||
|
||||
class MidiInWinKS: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInWinKS( const std::string clientName, unsigned int queueSizeLimit );
|
||||
~MidiInWinKS( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_KS; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
class MidiOutWinKS: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutWinKS( const std::string clientName );
|
||||
~MidiOutWinKS( void );
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::WINDOWS_KS; };
|
||||
void openPort( unsigned int portNumber, const std::string portName );
|
||||
void openVirtualPort( const std::string portName );
|
||||
void closePort( void );
|
||||
unsigned int getPortCount( void );
|
||||
std::string getPortName( unsigned int portNumber );
|
||||
void sendMessage( std::vector<unsigned char> *message );
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName );
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__RTMIDI_DUMMY__)
|
||||
|
||||
class MidiInDummy: public MidiInApi
|
||||
{
|
||||
public:
|
||||
MidiInDummy( const std::string clientName, unsigned int queueSizeLimit ) : MidiInApi( queueSizeLimit ) { errorString_ = "MidiInDummy: This class provides no functionality."; RtMidi::error( RtError::WARNING, errorString_ ); };
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; };
|
||||
void openPort( unsigned int portNumber, const std::string portName ) {};
|
||||
void openVirtualPort( const std::string portName ) {};
|
||||
void closePort( void ) {};
|
||||
unsigned int getPortCount( void ) { return 0; };
|
||||
std::string getPortName( unsigned int portNumber ) { return ""; };
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName ) {};
|
||||
};
|
||||
|
||||
class MidiOutDummy: public MidiOutApi
|
||||
{
|
||||
public:
|
||||
MidiOutDummy( const std::string clientName ) { errorString_ = "MidiOutDummy: This class provides no functionality."; RtMidi::error( RtError::WARNING, errorString_ ); };
|
||||
RtMidi::Api getCurrentApi( void ) { return RtMidi::RTMIDI_DUMMY; };
|
||||
void openPort( unsigned int portNumber, const std::string portName ) {};
|
||||
void openVirtualPort( const std::string portName ) {};
|
||||
void closePort( void ) {};
|
||||
unsigned int getPortCount( void ) { return 0; };
|
||||
std::string getPortName( unsigned int portNumber ) { return ""; };
|
||||
void sendMessage( std::vector<unsigned char> *message ) {};
|
||||
|
||||
protected:
|
||||
void initialize( const std::string& clientName ) {};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
112
examples/ThirdPartyLibs/midi/cmidiin.cpp
Normal file
112
examples/ThirdPartyLibs/midi/cmidiin.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
//*****************************************//
|
||||
// cmidiin.cpp
|
||||
// by Gary Scavone, 2003-2004.
|
||||
//
|
||||
// Simple program to test MIDI input and
|
||||
// use of a user callback function.
|
||||
//
|
||||
//*****************************************//
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdlib>
|
||||
#include "RtMidi.h"
|
||||
|
||||
void usage( void ) {
|
||||
// Error function in case of incorrect command-line
|
||||
// argument specifications.
|
||||
std::cout << "\nuseage: cmidiin <port>\n";
|
||||
std::cout << " where port = the device to use (default = 0).\n\n";
|
||||
exit( 0 );
|
||||
}
|
||||
|
||||
void mycallback( double deltatime, std::vector< unsigned char > *message, void *userData )
|
||||
{
|
||||
unsigned int nBytes = message->size();
|
||||
for ( unsigned int i=0; i<nBytes; i++ )
|
||||
std::cout << "Byte " << i << " = " << (int)message->at(i) << ", ";
|
||||
if ( nBytes > 0 )
|
||||
std::cout << "stamp = " << deltatime << std::endl;
|
||||
}
|
||||
|
||||
// This function should be embedded in a try/catch block in case of
|
||||
// an exception. It offers the user a choice of MIDI ports to open.
|
||||
// It returns false if there are no ports available.
|
||||
bool chooseMidiPort( RtMidiIn *rtmidi );
|
||||
|
||||
int main( int argc, char *argv[] )
|
||||
{
|
||||
RtMidiIn *midiin = 0;
|
||||
|
||||
// Minimal command-line check.
|
||||
if ( argc > 2 ) usage();
|
||||
|
||||
|
||||
// RtMidiIn constructor
|
||||
midiin = new RtMidiIn();
|
||||
|
||||
// Call function to select port.
|
||||
if ( chooseMidiPort( midiin ) == false ) goto cleanup;
|
||||
|
||||
// Set our callback function. This should be done immediately after
|
||||
// opening the port to avoid having incoming messages written to the
|
||||
// queue instead of sent to the callback function.
|
||||
midiin->setCallback( &mycallback );
|
||||
|
||||
// Don't ignore sysex, timing, or active sensing messages.
|
||||
midiin->ignoreTypes( false, false, false );
|
||||
|
||||
std::cout << "\nReading MIDI input ... press <enter> to quit.\n";
|
||||
char input;
|
||||
std::cin.get(input);
|
||||
std::cin.get(input);
|
||||
|
||||
|
||||
|
||||
cleanup:
|
||||
|
||||
delete midiin;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool chooseMidiPort( RtMidiIn *rtmidi )
|
||||
{
|
||||
/*
|
||||
|
||||
std::cout << "\nWould you like to open a virtual input port? [y/N] ";
|
||||
|
||||
std::string keyHit;
|
||||
std::getline( std::cin, keyHit );
|
||||
if ( keyHit == "y" ) {
|
||||
rtmidi->openVirtualPort();
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
std::string portName;
|
||||
unsigned int i = 0, nPorts = rtmidi->getPortCount();
|
||||
if ( nPorts == 0 ) {
|
||||
std::cout << "No input ports available!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( nPorts == 1 ) {
|
||||
std::cout << "\nOpening " << rtmidi->getPortName() << std::endl;
|
||||
}
|
||||
else {
|
||||
for ( i=0; i<nPorts; i++ ) {
|
||||
portName = rtmidi->getPortName(i);
|
||||
std::cout << " Input port #" << i << ": " << portName << '\n';
|
||||
}
|
||||
|
||||
do {
|
||||
std::cout << "\nChoose a port number: ";
|
||||
std::cin >> i;
|
||||
} while ( i >= nPorts );
|
||||
}
|
||||
|
||||
// std::getline( std::cin, keyHit ); // used to clear out stdin
|
||||
rtmidi->openPort( i );
|
||||
|
||||
return true;
|
||||
}
|
||||
35
examples/ThirdPartyLibs/midi/premake4.lua
Normal file
35
examples/ThirdPartyLibs/midi/premake4.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
project "rtMidiTest"
|
||||
|
||||
kind "ConsoleApp"
|
||||
|
||||
-- defines { }
|
||||
|
||||
|
||||
includedirs
|
||||
{
|
||||
".",
|
||||
}
|
||||
|
||||
|
||||
-- links { }
|
||||
|
||||
|
||||
files {
|
||||
"**.cpp",
|
||||
"**.h"
|
||||
}
|
||||
if os.is("Windows") then
|
||||
links {"winmm"}
|
||||
defines {"__WINDOWS_MM__", "WIN32"}
|
||||
end
|
||||
|
||||
if os.is("Linux") then
|
||||
defines {"__LINUX_ALSA__"}
|
||||
links {"asound","pthread"}
|
||||
end
|
||||
|
||||
if os.is("MacOSX") then
|
||||
links{"CoreAudio.framework", "coreMIDI.framework", "Cocoa.framework"}
|
||||
defines {"__MACOSX_CORE__"}
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user