From 8e496036c6a402edf52bd9b594807adf46e8ed91 Mon Sep 17 00:00:00 2001 From: erwincoumans Date: Sat, 23 Sep 2017 18:05:23 -0700 Subject: [PATCH] More work on the C/C++ plugin system for pybullet/C-API: Add preTickPluginCallback/postTickPluginCallback User pointer for b3PluginContext, to store objects (class/struct instances) Pass ints and floats as optional argument for plugin executePluginCommand --- examples/SharedMemory/PhysicsClientC_API.cpp | 55 ++++++-- examples/SharedMemory/PhysicsClientC_API.h | 7 +- .../PhysicsServerCommandProcessor.cpp | 83 ++++++------ .../PhysicsServerCommandProcessor.h | 1 + examples/SharedMemory/SharedMemoryCommands.h | 4 +- examples/SharedMemory/SharedMemoryPublic.h | 13 ++ examples/SharedMemory/b3PluginManager.cpp | 121 ++++++++++++++++-- examples/SharedMemory/b3PluginManager.h | 8 +- examples/SharedMemory/plugins/b3PluginAPI.h | 8 +- .../SharedMemory/plugins/b3PluginContext.h | 10 +- .../plugins/testPlugin/testplugin.cpp | 113 +++++++++++++++- .../plugins/testPlugin/testplugin.h | 13 +- examples/pybullet/pybullet.c | 41 ++++-- 13 files changed, 380 insertions(+), 97 deletions(-) diff --git a/examples/SharedMemory/PhysicsClientC_API.cpp b/examples/SharedMemory/PhysicsClientC_API.cpp index 5dfaa4e33..c82cd247f 100644 --- a/examples/SharedMemory/PhysicsClientC_API.cpp +++ b/examples/SharedMemory/PhysicsClientC_API.cpp @@ -1748,7 +1748,7 @@ B3_SHARED_API b3SharedMemoryCommandHandle b3CreateCustomCommand(b3PhysicsClientH return (b3SharedMemoryCommandHandle)command; } -B3_SHARED_API void b3CustomCommandLoadPlugin(b3SharedMemoryCommandHandle commandHandle, const char* pluginPath, int options) +B3_SHARED_API void b3CustomCommandLoadPlugin(b3SharedMemoryCommandHandle commandHandle, const char* pluginPath) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; b3Assert(command->m_type == CMD_CUSTOM_COMMAND); @@ -1756,7 +1756,7 @@ B3_SHARED_API void b3CustomCommandLoadPlugin(b3SharedMemoryCommandHandle command { command->m_updateFlags |= CMD_CUSTOM_COMMAND_LOAD_PLUGIN; command->m_customCommandArgs.m_pluginPath[0] = 0; - command->m_customCommandArgs.m_options = options; + int len = strlen(pluginPath); if (lenm_customCommandArgs.m_pluginUniqueId = pluginUniqueId; } } -B3_SHARED_API void b3CustomCommandExecutePluginCommand(b3SharedMemoryCommandHandle commandHandle, int pluginUniqueId, int commandUniqueId, const char* arguments) +B3_SHARED_API void b3CustomCommandExecutePluginCommand(b3SharedMemoryCommandHandle commandHandle, int pluginUniqueId, const char* textArguments) { struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; @@ -1815,18 +1815,55 @@ B3_SHARED_API void b3CustomCommandExecutePluginCommand(b3SharedMemoryCommandHand { command->m_updateFlags |= CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND; command->m_customCommandArgs.m_pluginUniqueId = pluginUniqueId; - command->m_customCommandArgs.m_commandUniqueId = commandUniqueId; - command->m_customCommandArgs.m_pluginArguments[0] = 0; - int len = strlen(arguments); + + command->m_customCommandArgs.m_arguments.m_numInts = 0; + command->m_customCommandArgs.m_arguments.m_numFloats = 0; + command->m_customCommandArgs.m_arguments.m_text[0] = 0; + + int len = strlen(textArguments); + if (lenm_customCommandArgs.m_pluginArguments, arguments); + strcpy(command->m_customCommandArgs.m_arguments.m_text, textArguments); } - - } } +B3_SHARED_API void b3CustomCommandExecuteAddIntArgument(b3SharedMemoryCommandHandle commandHandle, int intVal) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_CUSTOM_COMMAND); + b3Assert(command->m_updateFlags & CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND); + if (command->m_type == CMD_CUSTOM_COMMAND && (command->m_updateFlags & CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND)) + { + int numInts = command->m_customCommandArgs.m_arguments.m_numInts; + if (numIntsm_customCommandArgs.m_arguments.m_ints[numInts]=intVal; + command->m_customCommandArgs.m_arguments.m_numInts++; + } + } +} + +B3_SHARED_API void b3CustomCommandExecuteAddFloatArgument(b3SharedMemoryCommandHandle commandHandle, float floatVal) +{ + struct SharedMemoryCommand* command = (struct SharedMemoryCommand*) commandHandle; + b3Assert(command->m_type == CMD_CUSTOM_COMMAND); + b3Assert(command->m_updateFlags & CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND); + if (command->m_type == CMD_CUSTOM_COMMAND && (command->m_updateFlags & CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND)) + { + int numFloats = command->m_customCommandArgs.m_arguments.m_numFloats; + if (numFloatsm_customCommandArgs.m_arguments.m_floats[numFloats]=floatVal; + command->m_customCommandArgs.m_arguments.m_numFloats++; + } + } +} + + + + B3_SHARED_API b3SharedMemoryCommandHandle b3GetDynamicsInfoCommandInit(b3PhysicsClientHandle physClient, int bodyUniqueId, int linkIndex) { diff --git a/examples/SharedMemory/PhysicsClientC_API.h b/examples/SharedMemory/PhysicsClientC_API.h index 4dc6624dd..f1e4056f1 100644 --- a/examples/SharedMemory/PhysicsClientC_API.h +++ b/examples/SharedMemory/PhysicsClientC_API.h @@ -62,12 +62,15 @@ B3_SHARED_API int b3GetStatusType(b3SharedMemoryStatusHandle statusHandle); ///Plugin system, load and unload a plugin, execute a command B3_SHARED_API b3SharedMemoryCommandHandle b3CreateCustomCommand(b3PhysicsClientHandle physClient); -B3_SHARED_API void b3CustomCommandLoadPlugin(b3SharedMemoryCommandHandle commandHandle, const char* pluginPath, int options); +B3_SHARED_API void b3CustomCommandLoadPlugin(b3SharedMemoryCommandHandle commandHandle, const char* pluginPath); B3_SHARED_API int b3GetStatusPluginUniqueId(b3SharedMemoryStatusHandle statusHandle); B3_SHARED_API int b3GetStatusPluginCommandResult(b3SharedMemoryStatusHandle statusHandle); B3_SHARED_API void b3CustomCommandUnloadPlugin(b3SharedMemoryCommandHandle commandHandle, int pluginUniqueId); -B3_SHARED_API void b3CustomCommandExecutePluginCommand(b3SharedMemoryCommandHandle commandHandle, int pluginUniqueId, int commandUniqueId, const char* arguments); +B3_SHARED_API void b3CustomCommandExecutePluginCommand(b3SharedMemoryCommandHandle commandHandle, int pluginUniqueId, const char* textArguments); +B3_SHARED_API void b3CustomCommandExecuteAddIntArgument(b3SharedMemoryCommandHandle commandHandle, int intVal); +B3_SHARED_API void b3CustomCommandExecuteAddFloatArgument(b3SharedMemoryCommandHandle commandHandle, float floatVal); + B3_SHARED_API int b3GetStatusBodyIndices(b3SharedMemoryStatusHandle statusHandle, int* bodyIndicesOut, int bodyIndicesCapacity); diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp index 4d95946ad..8fe802ce7 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.cpp +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.cpp @@ -1,5 +1,6 @@ #include "PhysicsServerCommandProcessor.h" + #include "../Importers/ImportURDFDemo/BulletUrdfImporter.h" #include "../Importers/ImportURDFDemo/MyMultiBodyCreator.h" #include "../Importers/ImportURDFDemo/URDF2Bullet.h" @@ -1488,7 +1489,7 @@ struct PhysicsServerCommandProcessorInternalData btAlignedObjectArray m_sdfRecentLoadedBodies; - + btAlignedObjectArray m_stateLoggers; int m_stateLoggersUniqueId; int m_profileTimingLoggingUid; @@ -1541,6 +1542,16 @@ struct PhysicsServerCommandProcessorInternalData m_pickedConstraint(0), m_pickingMultiBodyPoint2Point(0) { + + + + { + //test to statically link a plugin + //#include "plugins/testPlugin/testplugin.h" + //register static plugins: + //m_pluginManager.registerStaticLinkedPlugin("path", initPlugin, exitPlugin, executePluginCommand); + } + m_vrControllerEvents.init(); m_bodyHandles.exitHandles(); @@ -1671,13 +1682,23 @@ PhysicsServerCommandProcessor::~PhysicsServerCommandProcessor() delete m_data; } + +void preTickCallback(btDynamicsWorld *world, btScalar timeStep) +{ + PhysicsServerCommandProcessor* proc = (PhysicsServerCommandProcessor*) world->getWorldUserInfo(); + bool isPreTick = true; + proc->tickPlugins(timeStep, isPreTick); +} + void logCallback(btDynamicsWorld *world, btScalar timeStep) { //handle the logging and playing sounds PhysicsServerCommandProcessor* proc = (PhysicsServerCommandProcessor*) world->getWorldUserInfo(); proc->processCollisionForces(timeStep); - proc->logObjectStates(timeStep); + + bool isPreTick = false; + proc->tickPlugins(timeStep, isPreTick); } @@ -1786,6 +1807,12 @@ void PhysicsServerCommandProcessor::processCollisionForces(btScalar timeStep) #endif//B3_ENABLE_TINY_AUDIO } +void PhysicsServerCommandProcessor::tickPlugins(btScalar timeStep, bool isPreTick) +{ + m_data->m_pluginManager.tickPlugins(timeStep, isPreTick); +} + + void PhysicsServerCommandProcessor::logObjectStates(btScalar timeStep) { for (int i=0;im_stateLoggers.size();i++) @@ -2149,7 +2176,11 @@ void PhysicsServerCommandProcessor::createEmptyDynamicsWorld() { m_data->m_guiHelper->createPhysicsDebugDrawer(m_data->m_dynamicsWorld); } - m_data->m_dynamicsWorld->setInternalTickCallback(logCallback,this); + bool isPreTick=false; + m_data->m_dynamicsWorld->setInternalTickCallback(logCallback,this,isPreTick); + isPreTick = true; + m_data->m_dynamicsWorld->setInternalTickCallback(preTickCallback,this,isPreTick); + #ifdef B3_ENABLE_TINY_AUDIO m_data->m_soundEngine.init(16,true); @@ -2966,27 +2997,11 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm bool hasStatus = false; { - ///we ignore overflow of integer for now - { - - //until we implement a proper ring buffer, we assume always maximum of 1 outstanding commands - - - //const SharedMemoryCommand& clientCmd =m_data->m_testBlock1->m_clientCommands[0]; -#if 1 if (m_data->m_commandLogger) { m_data->m_commandLogger->logCommand(clientCmd); } -#endif - - //m_data->m_testBlock1->m_numProcessedClientCommands++; - - //no timestamp yet - //int timeStamp = 0; - - //catch uninitialized cases serverStatusOut.m_type = CMD_INVALID_STATUS; serverStatusOut.m_numDataStreamBytes = 0; serverStatusOut.m_dataStream = 0; @@ -2994,32 +3009,7 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm //consume the command switch (clientCmd.m_type) { -#if 0 - case CMD_SEND_BULLET_DATA_STREAM: - { - if (m_data->m_verboseOutput) - { - b3Printf("Processed CMD_SEND_BULLET_DATA_STREAM length %d",clientCmd.m_dataStreamArguments.m_streamChunkLength); - } - btBulletWorldImporter* worldImporter = new btBulletWorldImporter(m_data->m_dynamicsWorld); - m_data->m_worldImporters.push_back(worldImporter); - bool completedOk = worldImporter->loadFileFromMemory(m_data->m_testBlock1->m_bulletStreamDataClientToServer,clientCmd.m_dataStreamArguments.m_streamChunkLength); - - if (completedOk) - { - SharedMemoryStatus& status = m_data->createServerStatus(CMD_BULLET_DATA_STREAM_RECEIVED_COMPLETED,clientCmd.m_sequenceNumber,timeStamp); - m_data->m_guiHelper->autogenerateGraphicsObjects(this->m_data->m_dynamicsWorld); - m_data->submitServerStatus(status); - } else - { - SharedMemoryStatus& status = m_data->createServerStatus(CMD_BULLET_DATA_STREAM_RECEIVED_FAILED,clientCmd.m_sequenceNumber,timeStamp); - m_data->submitServerStatus(status); - } - - break; - } -#endif case CMD_STATE_LOGGING: { BT_PROFILE("CMD_STATE_LOGGING"); @@ -7996,7 +7986,8 @@ bool PhysicsServerCommandProcessor::processCommand(const struct SharedMemoryComm } if (clientCmd.m_updateFlags & CMD_CUSTOM_COMMAND_EXECUTE_PLUGIN_COMMAND) { - int result = m_data->m_pluginManager.executePluginCommand(clientCmd.m_customCommandArgs.m_pluginUniqueId, clientCmd.m_customCommandArgs.m_pluginArguments); + + int result = m_data->m_pluginManager.executePluginCommand(clientCmd.m_customCommandArgs.m_pluginUniqueId, &clientCmd.m_customCommandArgs.m_arguments); serverCmd.m_customCommandResultArgs.m_executeCommandResult = result; serverCmd.m_type = CMD_CUSTOM_COMMAND_COMPLETED; @@ -8245,6 +8236,8 @@ bool PhysicsServerCommandProcessor::isRealTimeSimulationEnabled() const void PhysicsServerCommandProcessor::stepSimulationRealTime(double dtInSec,const struct b3VRControllerEvent* vrControllerEvents, int numVRControllerEvents, const struct b3KeyboardEvent* keyEvents, int numKeyEvents, const struct b3MouseEvent* mouseEvents, int numMouseEvents) { m_data->m_vrControllerEvents.addNewVREvents(vrControllerEvents,numVRControllerEvents); + + for (int i=0;im_stateLoggers.size();i++) { if (m_data->m_stateLoggers[i]->m_loggingType==STATE_LOGGING_VR_CONTROLLERS) diff --git a/examples/SharedMemory/PhysicsServerCommandProcessor.h b/examples/SharedMemory/PhysicsServerCommandProcessor.h index 65bb0bb6d..d46203419 100644 --- a/examples/SharedMemory/PhysicsServerCommandProcessor.h +++ b/examples/SharedMemory/PhysicsServerCommandProcessor.h @@ -91,6 +91,7 @@ public: virtual void replayLogCommand(char* bufferServerToClient, int bufferSizeInBytes ); //logging of object states (position etc) + void tickPlugins(btScalar timeStep, bool isPreTick); void logObjectStates(btScalar timeStep); void processCollisionForces(btScalar timeStep); diff --git a/examples/SharedMemory/SharedMemoryCommands.h b/examples/SharedMemory/SharedMemoryCommands.h index cdd2f720c..49098e0a0 100644 --- a/examples/SharedMemory/SharedMemoryCommands.h +++ b/examples/SharedMemory/SharedMemoryCommands.h @@ -119,10 +119,8 @@ enum CustomCommandEnum struct b3CustomCommand { int m_pluginUniqueId; - int m_commandUniqueId; - int m_options; + b3PluginArguments m_arguments; char m_pluginPath[MAX_FILENAME_LENGTH]; - char m_pluginArguments[MAX_FILENAME_LENGTH]; }; struct b3CustomCommandResultArgs diff --git a/examples/SharedMemory/SharedMemoryPublic.h b/examples/SharedMemory/SharedMemoryPublic.h index 10ada7c50..2186f3a78 100644 --- a/examples/SharedMemory/SharedMemoryPublic.h +++ b/examples/SharedMemory/SharedMemoryPublic.h @@ -620,6 +620,19 @@ enum eStateLoggingFlags STATE_LOG_JOINT_TORQUES = STATE_LOG_JOINT_MOTOR_TORQUES+STATE_LOG_JOINT_USER_TORQUES, }; +#define B3_MAX_PLUGIN_ARG_SIZE 128 +#define B3_MAX_PLUGIN_ARG_TEXT_LEN 1024 + +struct b3PluginArguments +{ + char m_text[B3_MAX_PLUGIN_ARG_TEXT_LEN]; + int m_numInts; + int m_ints[B3_MAX_PLUGIN_ARG_SIZE]; + int m_numFloats; + int m_floats[B3_MAX_PLUGIN_ARG_SIZE]; + + +}; #endif//SHARED_MEMORY_PUBLIC_H diff --git a/examples/SharedMemory/b3PluginManager.cpp b/examples/SharedMemory/b3PluginManager.cpp index 7a665b1e4..3210e94b2 100644 --- a/examples/SharedMemory/b3PluginManager.cpp +++ b/examples/SharedMemory/b3PluginManager.cpp @@ -2,7 +2,6 @@ #include "b3PluginManager.h" #include "Bullet3Common/b3HashMap.h" #include "Bullet3Common/b3ResizablePool.h" -#include "plugins/b3PluginAPI.h" #include "SharedMemoryPublic.h" #include "PhysicsDirect.h" #include "plugins/b3PluginContext.h" @@ -30,19 +29,43 @@ struct b3Plugin { B3_DYNLIB_HANDLE m_pluginHandle; + bool m_ownsPluginHandle; std::string m_pluginPath; - + int m_pluginUniqueId; PFN_INIT m_initFunc; PFN_EXIT m_exitFunc; PFN_EXECUTE m_executeCommandFunc; + + PFN_TICK m_preTickFunc; + PFN_TICK m_postTickFunc; + void* m_userPointer; + + b3Plugin() + :m_pluginHandle(0), + m_ownsPluginHandle(false), + m_pluginUniqueId(-1), + m_initFunc(0), + m_exitFunc(0), + m_executeCommandFunc(0), + m_postTickFunc(0), + m_preTickFunc(0), + m_userPointer(0) + { + } void clear() { - B3_DYNLIB_CLOSE(m_pluginHandle); + if (m_ownsPluginHandle) + { + B3_DYNLIB_CLOSE(m_pluginHandle); + } m_pluginHandle = 0; m_initFunc = 0; m_exitFunc = 0; m_executeCommandFunc = 0; + m_preTickFunc = 0; + m_postTickFunc = 0; + m_userPointer = 0; } }; @@ -64,26 +87,33 @@ b3PluginManager::b3PluginManager(class PhysicsCommandProcessorInterface* physSdk b3PluginManager::~b3PluginManager() { + while (m_data->m_pluginMap.size()) + { + b3PluginHandle* plugin = m_data->m_pluginMap.getAtIndex(0); + unloadPlugin(plugin->m_pluginUniqueId); + } delete m_data->m_physicsDirect; m_data->m_pluginMap.clear(); m_data->m_plugins.exitHandles(); delete m_data; } - + + int b3PluginManager::loadPlugin(const char* pluginPath) { int pluginUniqueId = -1; - b3Plugin* plugin = m_data->m_pluginMap.find(pluginPath); - if (plugin) + b3Plugin* pluginOrg = m_data->m_pluginMap.find(pluginPath); + if (pluginOrg) { //already loaded + pluginUniqueId = pluginOrg->m_pluginUniqueId; } else { pluginUniqueId = m_data->m_plugins.allocHandle(); b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId); - + plugin->m_pluginUniqueId = pluginUniqueId; B3_DYNLIB_HANDLE pluginHandle = B3_DYNLIB_OPEN(pluginPath); bool ok = false; if (pluginHandle) @@ -92,13 +122,22 @@ int b3PluginManager::loadPlugin(const char* pluginPath) plugin->m_initFunc = (PFN_INIT)B3_DYNLIB_IMPORT(pluginHandle, "initPlugin"); plugin->m_exitFunc = (PFN_EXIT)B3_DYNLIB_IMPORT(pluginHandle, "exitPlugin"); plugin->m_executeCommandFunc = (PFN_EXECUTE)B3_DYNLIB_IMPORT(pluginHandle, "executePluginCommand"); - + plugin->m_preTickFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, "preTickPluginCallback"); + plugin->m_postTickFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, "postTickPluginCallback"); + if (plugin->m_initFunc && plugin->m_exitFunc && plugin->m_executeCommandFunc) { - int version = plugin->m_initFunc(); + + b3PluginContext context; + context.m_userPointer = plugin->m_userPointer; + context.m_physClient = (b3PhysicsClientHandle) m_data->m_physicsDirect; + int version = plugin->m_initFunc(&context); + //keep the user pointer persistent + plugin->m_userPointer = context.m_userPointer; if (version == SHARED_MEMORY_MAGIC_NUMBER) { ok = true; + plugin->m_ownsPluginHandle = true; plugin->m_pluginHandle = pluginHandle; plugin->m_pluginPath = pluginPath; m_data->m_pluginMap.insert(pluginPath, *plugin); @@ -137,14 +176,35 @@ void b3PluginManager::unloadPlugin(int pluginUniqueId) b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId); if (plugin) { - plugin->m_exitFunc(); + b3PluginContext context; + context.m_userPointer = plugin->m_userPointer; + context.m_physClient = (b3PhysicsClientHandle) m_data->m_physicsDirect; + + plugin->m_exitFunc(&context); m_data->m_pluginMap.remove(plugin->m_pluginPath.c_str()); m_data->m_plugins.freeHandle(pluginUniqueId); } } +void b3PluginManager::tickPlugins(double timeStep, bool isPreTick) +{ + for (int i=0;im_pluginMap.size();i++) + { + b3PluginHandle* plugin = m_data->m_pluginMap.getAtIndex(i); -int b3PluginManager::executePluginCommand(int pluginUniqueId, const char* arguments) + PFN_TICK tick = isPreTick? plugin->m_preTickFunc : plugin->m_postTickFunc; + if (tick) + { + b3PluginContext context; + context.m_userPointer = plugin->m_userPointer; + context.m_physClient = (b3PhysicsClientHandle) m_data->m_physicsDirect; + int result = tick(&context); + plugin->m_userPointer = context.m_userPointer; + } + } +} + +int b3PluginManager::executePluginCommand(int pluginUniqueId, const b3PluginArguments* arguments) { int result = -1; @@ -152,9 +212,44 @@ int b3PluginManager::executePluginCommand(int pluginUniqueId, const char* argume if (plugin) { b3PluginContext context; - context.m_arguments = arguments; + context.m_userPointer = plugin->m_userPointer; context.m_physClient = (b3PhysicsClientHandle) m_data->m_physicsDirect; - result = plugin->m_executeCommandFunc(&context); + + result = plugin->m_executeCommandFunc(&context, arguments); + plugin->m_userPointer = context.m_userPointer; } return result; } + + +int b3PluginManager::registerStaticLinkedPlugin(const char* pluginPath, PFN_INIT initFunc,PFN_EXIT exitFunc, PFN_EXECUTE executeCommandFunc, PFN_TICK preTickFunc, PFN_TICK postTickFunc) +{ + + b3Plugin orgPlugin; + + + int pluginUniqueId = m_data->m_plugins.allocHandle(); + b3PluginHandle* pluginHandle = m_data->m_plugins.getHandle(pluginUniqueId); + pluginHandle->m_pluginHandle = 0; + pluginHandle->m_ownsPluginHandle =false; + pluginHandle->m_pluginUniqueId = pluginUniqueId; + pluginHandle->m_executeCommandFunc = executeCommandFunc; + pluginHandle->m_exitFunc = exitFunc; + pluginHandle->m_initFunc = initFunc; + pluginHandle->m_preTickFunc = preTickFunc; + pluginHandle->m_postTickFunc = postTickFunc; + pluginHandle->m_pluginHandle = 0; + pluginHandle->m_pluginPath = pluginPath; + pluginHandle->m_userPointer = 0; + + m_data->m_pluginMap.insert(pluginPath, *pluginHandle); + + { + b3PluginContext context; + context.m_userPointer = 0; + context.m_physClient = (b3PhysicsClientHandle) m_data->m_physicsDirect; + int result = pluginHandle->m_initFunc(&context); + pluginHandle->m_userPointer = context.m_userPointer; + } + return pluginUniqueId; +} diff --git a/examples/SharedMemory/b3PluginManager.h b/examples/SharedMemory/b3PluginManager.h index 9a71b352a..dd02b9630 100644 --- a/examples/SharedMemory/b3PluginManager.h +++ b/examples/SharedMemory/b3PluginManager.h @@ -1,6 +1,8 @@ #ifndef B3_PLUGIN_MANAGER_H #define B3_PLUGIN_MANAGER_H +#include "plugins/b3PluginAPI.h" + class b3PluginManager { struct b3PluginManagerInternalData* m_data; @@ -12,8 +14,10 @@ class b3PluginManager int loadPlugin(const char* pluginPath); void unloadPlugin(int pluginUniqueId); - int executePluginCommand(int pluginUniqueId, const char* arguments); - + int executePluginCommand(int pluginUniqueId, const struct b3PluginArguments* arguments); + void tickPlugins(double timeStep, bool isPreTick); + int registerStaticLinkedPlugin(const char* pluginPath, PFN_INIT initFunc,PFN_EXIT exitFunc, PFN_EXECUTE m_executeCommandFunc, PFN_TICK preTickFunc, PFN_TICK postTickFunc); + }; #endif //B3_PLUGIN_MANAGER_H diff --git a/examples/SharedMemory/plugins/b3PluginAPI.h b/examples/SharedMemory/plugins/b3PluginAPI.h index de5da762d..54387668f 100644 --- a/examples/SharedMemory/plugins/b3PluginAPI.h +++ b/examples/SharedMemory/plugins/b3PluginAPI.h @@ -26,10 +26,10 @@ extern "C" { #endif /* Plugin API */ - typedef B3_API_ENTRY int (B3_API_CALL * PFN_INIT)(); - typedef B3_API_ENTRY void (B3_API_CALL * PFN_EXIT)(); - typedef B3_API_ENTRY int (B3_API_CALL * PFN_EXECUTE)(struct b3PluginContext* context); - + typedef B3_API_ENTRY int (B3_API_CALL * PFN_INIT)(struct b3PluginContext* context); + typedef B3_API_ENTRY void (B3_API_CALL * PFN_EXIT)(struct b3PluginContext* context); + typedef B3_API_ENTRY int (B3_API_CALL * PFN_EXECUTE)(struct b3PluginContext* context, const struct b3PluginArguments* arguments); + typedef B3_API_ENTRY int (B3_API_CALL * PFN_TICK)(struct b3PluginContext* context); #ifdef __cplusplus } #endif diff --git a/examples/SharedMemory/plugins/b3PluginContext.h b/examples/SharedMemory/plugins/b3PluginContext.h index 873269f39..cb8bd754d 100644 --- a/examples/SharedMemory/plugins/b3PluginContext.h +++ b/examples/SharedMemory/plugins/b3PluginContext.h @@ -5,9 +5,17 @@ struct b3PluginContext { - const char* m_arguments; b3PhysicsClientHandle m_physClient; + + //plugin can modify the m_userPointer to store persistent object pointer (class or struct instance etc) + void* m_userPointer; + }; + + + + + #endif //B3_PLUGIN_CONTEXT_H \ No newline at end of file diff --git a/examples/SharedMemory/plugins/testPlugin/testplugin.cpp b/examples/SharedMemory/plugins/testPlugin/testplugin.cpp index db3f32fdf..2ba2b6bf2 100644 --- a/examples/SharedMemory/plugins/testPlugin/testplugin.cpp +++ b/examples/SharedMemory/plugins/testPlugin/testplugin.cpp @@ -16,22 +16,119 @@ p.unloadPlugin(pluginUid) #include "../b3PluginContext.h" #include -B3_SHARED_API int initPlugin() +struct MyClass { + int m_testData; + + MyClass() + :m_testData(42) + { + } + virtual ~MyClass() + { + } +}; + +B3_SHARED_API int initPlugin(struct b3PluginContext* context) +{ + MyClass* obj = new MyClass(); + context->m_userPointer = obj; + printf("hi!\n"); return SHARED_MEMORY_MAGIC_NUMBER; } -B3_SHARED_API int executePluginCommand(struct b3PluginContext* context) -{ - printf("arguments:%s\n",context->m_arguments); +B3_SHARED_API int preTickPluginCallback(struct b3PluginContext* context) +{ + MyClass* obj = (MyClass* )context->m_userPointer; + + { + b3SharedMemoryCommandHandle commandHandle = b3RequestVREventsCommandInit(context->m_physClient); + int deviceTypeFilter = VR_DEVICE_CONTROLLER; + b3VREventsSetDeviceTypeFilter(commandHandle, deviceTypeFilter); + + b3SharedMemoryStatusHandle statusHandle = b3SubmitClientCommandAndWaitStatus(context->m_physClient, commandHandle); + int statusType = b3GetStatusType(statusHandle); + if (statusType == CMD_REQUEST_VR_EVENTS_DATA_COMPLETED) + { + struct b3VREventsData vrEvents; + + int i = 0; + b3GetVREventsData(context->m_physClient, &vrEvents); + if (vrEvents.m_numControllerEvents) + { + //this is only for a test, normally you wouldn't print to the console at each simulation substep! + printf("got %d VR controller events!\n", vrEvents.m_numControllerEvents); + } + } + } + { + b3KeyboardEventsData keyboardEventsData; + b3SharedMemoryCommandHandle commandHandle = b3RequestKeyboardEventsCommandInit(context->m_physClient); + b3SubmitClientCommandAndWaitStatus(context->m_physClient, commandHandle); + b3GetKeyboardEventsData(context->m_physClient, &keyboardEventsData); + if (keyboardEventsData.m_numKeyboardEvents) + { + //this is only for a test, normally you wouldn't print to the console at each simulation substep! + printf("got %d keyboard events\n", keyboardEventsData.m_numKeyboardEvents); + } + } + + { + b3MouseEventsData mouseEventsData; + b3SharedMemoryCommandHandle commandHandle = b3RequestMouseEventsCommandInit(context->m_physClient); + b3SubmitClientCommandAndWaitStatus(context->m_physClient, commandHandle); + b3GetMouseEventsData(context->m_physClient, &mouseEventsData); + if (mouseEventsData.m_numMouseEvents) + { + //this is only for a test, normally you wouldn't print to the console at each simulation substep! + printf("got %d mouse events\n", mouseEventsData.m_numMouseEvents); + } + } + + return 0; +} + + +B3_SHARED_API int postTickPluginCallback(struct b3PluginContext* context) +{ + MyClass* obj = (MyClass* )context->m_userPointer; + obj->m_testData++; + return 0; +} + +B3_SHARED_API int executePluginCommand(struct b3PluginContext* context, const struct b3PluginArguments* arguments) +{ + printf("text argument:%s\n",arguments->m_text); + printf("int args: ["); + for (int i=0;im_numInts;i++) + { + printf("%d", arguments->m_ints[i]); + if ((i+1)m_numInts) + { + printf(","); + } + } + printf("]\nfloat args: ["); + for (int i=0;im_numFloats;i++) + { + printf("%f", arguments->m_floats[i]); + if ((i+1)m_numFloats) + { + printf(","); + } + } + printf("]\n"); + + MyClass* obj = (MyClass*) context->m_userPointer; + b3SharedMemoryStatusHandle statusHandle; int statusType = -1; int bodyUniqueId = -1; b3SharedMemoryCommandHandle command = - b3LoadUrdfCommandInit(context->m_physClient, context->m_arguments); + b3LoadUrdfCommandInit(context->m_physClient, arguments->m_text); statusHandle = b3SubmitClientCommandAndWaitStatus(context->m_physClient, command); statusType = b3GetStatusType(statusHandle); @@ -43,7 +140,11 @@ B3_SHARED_API int executePluginCommand(struct b3PluginContext* context) } -B3_SHARED_API void exitPlugin() +B3_SHARED_API void exitPlugin(struct b3PluginContext* context) { + MyClass* obj = (MyClass*) context->m_userPointer; + delete obj; + context->m_userPointer = 0; + printf("bye!\n"); } diff --git a/examples/SharedMemory/plugins/testPlugin/testplugin.h b/examples/SharedMemory/plugins/testPlugin/testplugin.h index 53718693f..bb14345cc 100644 --- a/examples/SharedMemory/plugins/testPlugin/testplugin.h +++ b/examples/SharedMemory/plugins/testPlugin/testplugin.h @@ -8,9 +8,16 @@ extern "C" { #endif -B3_SHARED_API int initPlugin(); -B3_SHARED_API void exitPlugin(); -B3_SHARED_API int executePluginCommand(struct b3PluginContext* context); +//initPlugin, exitPlugin and executePluginCommand are required, otherwise plugin won't load +B3_SHARED_API int initPlugin(struct b3PluginContext* context); +B3_SHARED_API void exitPlugin(struct b3PluginContext* context); +B3_SHARED_API int executePluginCommand(struct b3PluginContext* context, const struct b3PluginArguments* arguments); + +//preTickPluginCallback and postTickPluginCallback are optional. +B3_SHARED_API int preTickPluginCallback(struct b3PluginContext* context); +B3_SHARED_API int postTickPluginCallback(struct b3PluginContext* context); + + #ifdef __cplusplus }; diff --git a/examples/pybullet/pybullet.c b/examples/pybullet/pybullet.c index ef1aad238..ed4fc453b 100644 --- a/examples/pybullet/pybullet.c +++ b/examples/pybullet/pybullet.c @@ -6658,15 +6658,15 @@ static PyObject* pybullet_loadPlugin(PyObject* self, PyObject* args, PyObject* keywds) { int physicsClientId = 0; - int option = 0; + char* pluginPath = 0; b3SharedMemoryCommandHandle command = 0; b3SharedMemoryStatusHandle statusHandle = 0; int statusType = -1; b3PhysicsClientHandle sm = 0; - static char* kwlist[] = { "pluginPath", "option", "physicsClientId", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|ii", kwlist, &pluginPath, &option, &physicsClientId)) + static char* kwlist[] = { "pluginPath", "physicsClientId", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s|i", kwlist, &pluginPath, &physicsClientId)) { return NULL; } @@ -6679,7 +6679,7 @@ static PyObject* pybullet_loadPlugin(PyObject* self, } command = b3CreateCustomCommand(sm); - b3CustomCommandLoadPlugin(command, pluginPath, option); + b3CustomCommandLoadPlugin(command, pluginPath); statusHandle = b3SubmitClientCommandAndWaitStatus(sm, command); statusType = b3GetStatusPluginUniqueId(statusHandle); return PyInt_FromLong(statusType); @@ -6724,15 +6724,16 @@ static PyObject* pybullet_executePluginCommand(PyObject* self, { int physicsClientId = 0; int pluginUniqueId = -1; - int commandUniqueId = -1; - char* arguments = 0; + char* textArgument = 0; b3SharedMemoryCommandHandle command=0; b3SharedMemoryStatusHandle statusHandle=0; int statusType = -1; + PyObject* intArgs=0; + PyObject* floatArgs=0; b3PhysicsClientHandle sm = 0; - static char* kwlist[] = { "pluginUniqueId", "commandUniqueId", "arguments", "physicsClientId", NULL }; - if (!PyArg_ParseTupleAndKeywords(args, keywds, "ii|si", kwlist, &pluginUniqueId, &commandUniqueId, &arguments, &physicsClientId)) + static char* kwlist[] = { "pluginUniqueId", "textArgument", "intArgs", "floatArgs", "physicsClientId", NULL }; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "i|sOOi", kwlist, &pluginUniqueId, &textArgument, &intArgs, &floatArgs, &physicsClientId)) { return NULL; } @@ -6746,7 +6747,29 @@ static PyObject* pybullet_executePluginCommand(PyObject* self, command = b3CreateCustomCommand(sm); - b3CustomCommandExecutePluginCommand(command, pluginUniqueId, commandUniqueId, arguments); + b3CustomCommandExecutePluginCommand(command, pluginUniqueId, textArgument); + + { + PyObject* seqIntArgs = intArgs?PySequence_Fast(intArgs, "expected a sequence"):0; + PyObject* seqFloatArgs = floatArgs?PySequence_Fast(floatArgs, "expected a sequence"):0; + int numIntArgs = seqIntArgs?PySequence_Size(intArgs):0; + int numFloatArgs = seqIntArgs?PySequence_Size(floatArgs):0; + int i; + for (i=0;i