1
2 #include "b3PluginManager.h"
3 #include "Bullet3Common/b3HashMap.h"
4 #include "Bullet3Common/b3ResizablePool.h"
5 #include "PhysicsClientC_API.h"
6 #include "PhysicsDirect.h"
7 #include "plugins/b3PluginContext.h"
8 #include "../Utils/b3BulletDefaultFileIO.h"
9 #include <string.h>
10 #ifdef _WIN32
11 #define WIN32_LEAN_AND_MEAN
12 #define VC_EXTRALEAN
13 #include <windows.h>
14
15 typedef HMODULE B3_DYNLIB_HANDLE;
16
17 #define B3_DYNLIB_OPEN LoadLibraryA
18 #define B3_DYNLIB_CLOSE FreeLibrary
19 #define B3_DYNLIB_IMPORT GetProcAddress
20 #else
21 #include <dlfcn.h>
22
23 typedef void* B3_DYNLIB_HANDLE;
24
25 #ifdef B3_USE_DLMOPEN
26 #define B3_DYNLIB_OPEN(path) dlmopen(LM_ID_NEWLM, path, RTLD_LAZY)
27 #else
28 #define B3_DYNLIB_OPEN(path) dlopen(path, RTLD_NOW | RTLD_GLOBAL)
29 #endif
30 #define B3_DYNLIB_CLOSE dlclose
31 #define B3_DYNLIB_IMPORT dlsym
32 #endif
33
34 struct b3Plugin
35 {
36 B3_DYNLIB_HANDLE m_pluginHandle;
37 bool m_ownsPluginHandle;
38 bool m_isInitialized;
39 std::string m_pluginPath;
40 std::string m_pluginPostFix;
41 int m_pluginUniqueId;
42 PFN_INIT m_initFunc;
43 PFN_EXIT m_exitFunc;
44 PFN_EXECUTE m_executeCommandFunc;
45
46 PFN_TICK m_preTickFunc;
47 PFN_TICK m_postTickFunc;
48 PFN_TICK m_processNotificationsFunc;
49 PFN_TICK m_processClientCommandsFunc;
50
51 PFN_GET_RENDER_INTERFACE m_getRendererFunc;
52 PFN_GET_COLLISION_INTERFACE m_getCollisionFunc;
53 PFN_GET_FILEIO_INTERFACE m_getFileIOFunc;
54
55 void* m_userPointer;
56 b3UserDataValue* m_returnData;
57
b3Pluginb3Plugin58 b3Plugin()
59 : m_pluginHandle(0),
60 m_ownsPluginHandle(false),
61 m_isInitialized(false),
62 m_pluginUniqueId(-1),
63 m_initFunc(0),
64 m_exitFunc(0),
65 m_executeCommandFunc(0),
66 m_preTickFunc(0),
67 m_postTickFunc(0),
68 m_processNotificationsFunc(0),
69 m_processClientCommandsFunc(0),
70 m_getRendererFunc(0),
71 m_getCollisionFunc(0),
72 m_getFileIOFunc(0),
73 m_userPointer(0),
74 m_returnData(0)
75 {
76 }
clearb3Plugin77 void clear()
78 {
79 if (m_ownsPluginHandle)
80 {
81 B3_DYNLIB_CLOSE(m_pluginHandle);
82 }
83 m_pluginHandle = 0;
84 m_initFunc = 0;
85 m_exitFunc = 0;
86 m_executeCommandFunc = 0;
87 m_preTickFunc = 0;
88 m_postTickFunc = 0;
89 m_processNotificationsFunc = 0;
90 m_processClientCommandsFunc = 0;
91 m_getRendererFunc = 0;
92 m_getCollisionFunc = 0;
93 m_getFileIOFunc = 0;
94 m_userPointer = 0;
95 m_returnData = 0;
96 m_isInitialized = false;
97 }
98
GetMapKeyb3Plugin99 const char* GetMapKey() const
100 {
101 return GetMapKey(m_pluginPath.c_str(), m_pluginPostFix.c_str());
102 }
103
GetMapKeyb3Plugin104 static const char* GetMapKey(const char* path, const char* postFix)
105 {
106 if (path != 0 && strlen(path) > 0)
107 {
108 return path;
109 }
110 else if (postFix != 0 && strlen(postFix) > 0)
111 {
112 return postFix;
113 }
114 return "";
115 }
116 };
117
118 typedef b3PoolBodyHandle<b3Plugin> b3PluginHandle;
119
120 struct b3PluginManagerInternalData
121 {
122 b3ResizablePool<b3PluginHandle> m_plugins;
123 b3HashMap<b3HashString, int> m_pluginMap;
124 PhysicsDirect* m_physicsDirect;
125 PhysicsCommandProcessorInterface* m_rpcCommandProcessorInterface;
126 b3AlignedObjectArray<b3KeyboardEvent> m_keyEvents;
127 b3AlignedObjectArray<b3VRControllerEvent> m_vrEvents;
128 b3AlignedObjectArray<b3MouseEvent> m_mouseEvents;
129 b3AlignedObjectArray<b3Notification> m_notifications[2];
130 int m_activeNotificationsBufferIndex;
131 int m_activeRendererPluginUid;
132 int m_activeCollisionPluginUid;
133 int m_numNotificationPlugins;
134 int m_activeFileIOPluginUid;
135 b3BulletDefaultFileIO m_defaultFileIO;
136
b3PluginManagerInternalDatab3PluginManagerInternalData137 b3PluginManagerInternalData()
138 : m_physicsDirect(0), m_rpcCommandProcessorInterface(0), m_activeNotificationsBufferIndex(0), m_activeRendererPluginUid(-1), m_activeCollisionPluginUid(-1), m_numNotificationPlugins(0), m_activeFileIOPluginUid(-1)
139 {
140 }
141 };
142
b3PluginManager(class PhysicsCommandProcessorInterface * physSdk)143 b3PluginManager::b3PluginManager(class PhysicsCommandProcessorInterface* physSdk)
144 {
145 m_data = new b3PluginManagerInternalData;
146 m_data->m_rpcCommandProcessorInterface = physSdk;
147 m_data->m_physicsDirect = new PhysicsDirect(physSdk, false);
148 }
149
~b3PluginManager()150 b3PluginManager::~b3PluginManager()
151 {
152 while (m_data->m_pluginMap.size())
153 {
154 int* pluginUidPtr = m_data->m_pluginMap.getAtIndex(0);
155 if (pluginUidPtr)
156 {
157 int pluginUid = *pluginUidPtr;
158 unloadPlugin(*pluginUidPtr);
159 }
160 }
161 delete m_data->m_physicsDirect;
162 m_data->m_pluginMap.clear();
163 m_data->m_plugins.exitHandles();
164 delete m_data;
165 }
166
addEvents(const struct b3VRControllerEvent * vrControllerEvents,int numVRControllerEvents,const struct b3KeyboardEvent * keyEvents,int numKeyEvents,const struct b3MouseEvent * mouseEvents,int numMouseEvents)167 void b3PluginManager::addEvents(const struct b3VRControllerEvent* vrControllerEvents, int numVRControllerEvents, const struct b3KeyboardEvent* keyEvents, int numKeyEvents, const struct b3MouseEvent* mouseEvents, int numMouseEvents)
168 {
169 for (int i = 0; i < numKeyEvents; i++)
170 {
171 m_data->m_keyEvents.push_back(keyEvents[i]);
172 }
173
174 for (int i = 0; i < numVRControllerEvents; i++)
175 {
176 m_data->m_vrEvents.push_back(vrControllerEvents[i]);
177 }
178 for (int i = 0; i < numMouseEvents; i++)
179 {
180 m_data->m_mouseEvents.push_back(mouseEvents[i]);
181 }
182 }
183
clearEvents()184 void b3PluginManager::clearEvents()
185 {
186 m_data->m_keyEvents.resize(0);
187 m_data->m_vrEvents.resize(0);
188 m_data->m_mouseEvents.resize(0);
189 }
190
addNotification(const struct b3Notification & notification)191 void b3PluginManager::addNotification(const struct b3Notification& notification)
192 {
193 if (m_data->m_numNotificationPlugins > 0)
194 {
195 m_data->m_notifications[m_data->m_activeNotificationsBufferIndex].push_back(notification);
196 }
197 }
198
loadPlugin(const char * pluginPath,const char * postFixStr)199 int b3PluginManager::loadPlugin(const char* pluginPath, const char* postFixStr)
200 {
201 int pluginUniqueId = -1;
202
203 int* pluginUidPtr = m_data->m_pluginMap.find(b3Plugin::GetMapKey(pluginPath, postFixStr));
204 if (pluginUidPtr)
205 {
206 //already loaded
207 pluginUniqueId = *pluginUidPtr;
208 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
209 if (!plugin->m_isInitialized)
210 {
211 b3PluginContext context = {0};
212 context.m_userPointer = 0;
213 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
214 context.m_rpcCommandProcessorInterface = m_data->m_rpcCommandProcessorInterface;
215 int result = plugin->m_initFunc(&context);
216 plugin->m_isInitialized = true;
217 plugin->m_userPointer = context.m_userPointer;
218 }
219 }
220 else
221 {
222 pluginUniqueId = m_data->m_plugins.allocHandle();
223 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
224 plugin->m_pluginUniqueId = pluginUniqueId;
225 B3_DYNLIB_HANDLE pluginHandle = B3_DYNLIB_OPEN(pluginPath);
226 bool ok = false;
227 if (pluginHandle)
228 {
229 std::string postFix = postFixStr;
230 std::string initStr = std::string("initPlugin") + postFix;
231 std::string exitStr = std::string("exitPlugin") + postFix;
232 std::string executePluginCommandStr = std::string("executePluginCommand") + postFix;
233 std::string preTickPluginCallbackStr = std::string("preTickPluginCallback") + postFix;
234 std::string postTickPluginCallback = std::string("postTickPluginCallback") + postFix;
235 std::string processNotificationsStr = std::string("processNotifications") + postFix;
236 std::string processClientCommandsStr = std::string("processClientCommands") + postFix;
237 std::string getRendererStr = std::string("getRenderInterface") + postFix;
238 std::string getCollisionStr = std::string("getCollisionInterface") + postFix;
239 std::string getFileIOStr = std::string("getFileIOInterface") + postFix;
240
241 plugin->m_initFunc = (PFN_INIT)B3_DYNLIB_IMPORT(pluginHandle, initStr.c_str());
242 plugin->m_exitFunc = (PFN_EXIT)B3_DYNLIB_IMPORT(pluginHandle, exitStr.c_str());
243 plugin->m_executeCommandFunc = (PFN_EXECUTE)B3_DYNLIB_IMPORT(pluginHandle, executePluginCommandStr.c_str());
244 plugin->m_preTickFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, preTickPluginCallbackStr.c_str());
245 plugin->m_postTickFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, postTickPluginCallback.c_str());
246 plugin->m_processNotificationsFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, processNotificationsStr.c_str());
247
248 if (plugin->m_processNotificationsFunc)
249 {
250 m_data->m_numNotificationPlugins++;
251 }
252 plugin->m_processClientCommandsFunc = (PFN_TICK)B3_DYNLIB_IMPORT(pluginHandle, processClientCommandsStr.c_str());
253
254 plugin->m_getRendererFunc = (PFN_GET_RENDER_INTERFACE)B3_DYNLIB_IMPORT(pluginHandle, getRendererStr.c_str());
255 plugin->m_getCollisionFunc = (PFN_GET_COLLISION_INTERFACE)B3_DYNLIB_IMPORT(pluginHandle, getCollisionStr.c_str());
256 plugin->m_getFileIOFunc = (PFN_GET_FILEIO_INTERFACE)B3_DYNLIB_IMPORT(pluginHandle, getFileIOStr.c_str());
257
258
259 if (plugin->m_initFunc && plugin->m_exitFunc && plugin->m_executeCommandFunc)
260 {
261 b3PluginContext context;
262 context.m_userPointer = plugin->m_userPointer;
263 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
264 context.m_rpcCommandProcessorInterface = m_data->m_rpcCommandProcessorInterface;
265 int version = plugin->m_initFunc(&context);
266 plugin->m_isInitialized = true;
267 //keep the user pointer persistent
268 plugin->m_userPointer = context.m_userPointer;
269 if (version == SHARED_MEMORY_MAGIC_NUMBER)
270 {
271 ok = true;
272 plugin->m_ownsPluginHandle = true;
273 plugin->m_pluginHandle = pluginHandle;
274 plugin->m_pluginPath = pluginPath;
275 plugin->m_pluginPostFix = postFixStr;
276 m_data->m_pluginMap.insert(plugin->GetMapKey(), pluginUniqueId);
277 }
278 else
279 {
280 int expect = SHARED_MEMORY_MAGIC_NUMBER;
281 b3Warning("Warning: plugin is wrong version: expected %d, got %d\n", expect, version);
282 }
283 }
284 else
285 {
286 b3Warning("Loaded plugin but couldn't bind functions");
287 }
288
289 if (!ok)
290 {
291 B3_DYNLIB_CLOSE(pluginHandle);
292 }
293 }
294 else
295 {
296 b3Warning("Warning: couldn't load plugin %s\n", pluginPath);
297 #ifdef _WIN32
298 #else
299 b3Warning("Error: %s\n", dlerror());
300 #endif
301 }
302 if (!ok)
303 {
304 m_data->m_plugins.freeHandle(pluginUniqueId);
305 pluginUniqueId = -1;
306 }
307 }
308
309 //for now, automatically select the loaded plugin as active renderer.
310 if (pluginUniqueId >= 0)
311 {
312 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
313 if (plugin && plugin->m_getRendererFunc)
314 {
315 selectPluginRenderer(pluginUniqueId);
316 }
317 }
318
319 //for now, automatically select the loaded plugin as active collision plugin.
320 if (pluginUniqueId >= 0)
321 {
322 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
323 if (plugin && plugin->m_getCollisionFunc)
324 {
325 selectCollisionPlugin(pluginUniqueId);
326 }
327 }
328 //for now, automatically select the loaded plugin as active fileIO plugin.
329 if (pluginUniqueId >= 0)
330 {
331 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
332 if (plugin && plugin->m_getFileIOFunc)
333 {
334 selectFileIOPlugin(pluginUniqueId);
335 }
336 }
337
338 return pluginUniqueId;
339 }
340
unloadPlugin(int pluginUniqueId)341 void b3PluginManager::unloadPlugin(int pluginUniqueId)
342 {
343 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
344 if (plugin)
345 {
346 if (plugin->m_processNotificationsFunc)
347 {
348 m_data->m_numNotificationPlugins--;
349 }
350 b3PluginContext context = {0};
351 context.m_userPointer = plugin->m_userPointer;
352 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
353
354 if (plugin->m_isInitialized)
355 {
356 plugin->m_exitFunc(&context);
357 plugin->m_userPointer = 0;
358 plugin->m_returnData = 0;
359 plugin->m_isInitialized = false;
360 }
361 m_data->m_pluginMap.remove(plugin->GetMapKey());
362 m_data->m_plugins.freeHandle(pluginUniqueId);
363 }
364 }
365
tickPlugins(double timeStep,b3PluginManagerTickMode tickMode)366 void b3PluginManager::tickPlugins(double timeStep, b3PluginManagerTickMode tickMode)
367 {
368 for (int i = 0; i < m_data->m_pluginMap.size(); i++)
369 {
370 int* pluginUidPtr = m_data->m_pluginMap.getAtIndex(i);
371 b3PluginHandle* plugin = 0;
372
373 if (pluginUidPtr)
374 {
375 int pluginUid = *pluginUidPtr;
376 plugin = m_data->m_plugins.getHandle(pluginUid);
377 }
378 else
379 {
380 continue;
381 }
382
383 PFN_TICK tick = 0;
384 switch (tickMode)
385 {
386 case B3_PRE_TICK_MODE:
387 {
388 tick = plugin->m_preTickFunc;
389 break;
390 }
391 case B3_POST_TICK_MODE:
392 {
393 tick = plugin->m_postTickFunc;
394 break;
395 }
396 case B3_PROCESS_CLIENT_COMMANDS_TICK:
397 {
398 tick = plugin->m_processClientCommandsFunc;
399 break;
400 }
401 default:
402 {
403 }
404 }
405
406 if (tick)
407 {
408 b3PluginContext context = {0};
409 context.m_userPointer = plugin->m_userPointer;
410 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
411 context.m_numMouseEvents = m_data->m_mouseEvents.size();
412 context.m_mouseEvents = m_data->m_mouseEvents.size() ? &m_data->m_mouseEvents[0] : 0;
413 context.m_numKeyEvents = m_data->m_keyEvents.size();
414 context.m_keyEvents = m_data->m_keyEvents.size() ? &m_data->m_keyEvents[0] : 0;
415 context.m_numVRControllerEvents = m_data->m_vrEvents.size();
416 context.m_vrControllerEvents = m_data->m_vrEvents.size() ? &m_data->m_vrEvents[0] : 0;
417 if (tickMode == B3_PROCESS_CLIENT_COMMANDS_TICK)
418 {
419 context.m_rpcCommandProcessorInterface = m_data->m_rpcCommandProcessorInterface;
420 }
421 int result = tick(&context);
422 plugin->m_userPointer = context.m_userPointer;
423 }
424 }
425 }
426
reportNotifications()427 void b3PluginManager::reportNotifications()
428 {
429 b3AlignedObjectArray<b3Notification>& notifications = m_data->m_notifications[m_data->m_activeNotificationsBufferIndex];
430 if (notifications.size() == 0)
431 {
432 return;
433 }
434
435 // Swap notification buffers.
436 m_data->m_activeNotificationsBufferIndex = 1 - m_data->m_activeNotificationsBufferIndex;
437
438 for (int i = 0; i < m_data->m_pluginMap.size(); i++)
439 {
440 int* pluginUidPtr = m_data->m_pluginMap.getAtIndex(i);
441 b3PluginHandle* plugin = 0;
442
443 if (pluginUidPtr)
444 {
445 int pluginUid = *pluginUidPtr;
446 plugin = m_data->m_plugins.getHandle(pluginUid);
447 }
448 else
449 {
450 continue;
451 }
452
453 if (plugin->m_processNotificationsFunc)
454 {
455 b3PluginContext context = {0};
456 context.m_userPointer = plugin->m_userPointer;
457 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
458 context.m_numNotifications = notifications.size();
459 context.m_notifications = notifications.size() ? ¬ifications[0] : 0;
460 plugin->m_processNotificationsFunc(&context);
461 }
462 }
463 notifications.resize(0);
464 }
465
executePluginCommand(int pluginUniqueId,const b3PluginArguments * arguments)466 int b3PluginManager::executePluginCommand(int pluginUniqueId, const b3PluginArguments* arguments)
467 {
468 int result = -1;
469
470 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
471 if (plugin)
472 {
473 b3PluginContext context = {0};
474 context.m_userPointer = plugin->m_userPointer;
475 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
476 context.m_rpcCommandProcessorInterface = m_data->m_rpcCommandProcessorInterface;
477 result = plugin->m_executeCommandFunc(&context, arguments);
478 plugin->m_userPointer = context.m_userPointer;
479 plugin->m_returnData = context.m_returnData;
480 }
481 return result;
482 }
483
484
485
registerStaticLinkedPlugin(const char * pluginPath,b3PluginFunctions & functions,bool initPlugin)486 int b3PluginManager::registerStaticLinkedPlugin(const char* pluginPath, b3PluginFunctions& functions, bool initPlugin)
487 {
488 b3Plugin orgPlugin;
489
490 int pluginUniqueId = m_data->m_plugins.allocHandle();
491 b3PluginHandle* pluginHandle = m_data->m_plugins.getHandle(pluginUniqueId);
492 pluginHandle->m_pluginHandle = 0;
493 pluginHandle->m_ownsPluginHandle = false;
494 pluginHandle->m_pluginUniqueId = pluginUniqueId;
495 pluginHandle->m_executeCommandFunc = functions.m_executeCommandFunc;
496 pluginHandle->m_exitFunc = functions.m_exitFunc;
497 pluginHandle->m_initFunc = functions.m_initFunc;
498 pluginHandle->m_preTickFunc = functions.m_preTickFunc;
499 pluginHandle->m_postTickFunc = functions.m_postTickFunc;
500 pluginHandle->m_getRendererFunc = functions.m_getRendererFunc;
501 pluginHandle->m_getCollisionFunc = functions.m_getCollisionFunc;
502 pluginHandle->m_processClientCommandsFunc = functions.m_processClientCommandsFunc;
503 pluginHandle->m_getFileIOFunc = functions.m_fileIoFunc;
504 pluginHandle->m_pluginHandle = 0;
505 pluginHandle->m_pluginPath = pluginPath;
506 pluginHandle->m_pluginPostFix = "";
507 pluginHandle->m_userPointer = 0;
508 pluginHandle->m_returnData = 0;
509
510 if (pluginHandle->m_processNotificationsFunc)
511 {
512 m_data->m_numNotificationPlugins++;
513 }
514
515 m_data->m_pluginMap.insert(pluginHandle->GetMapKey(), pluginUniqueId);
516
517 if (initPlugin)
518 {
519 b3PluginContext context = {0};
520 context.m_userPointer = 0;
521 context.m_returnData = 0;
522 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
523 context.m_rpcCommandProcessorInterface = m_data->m_rpcCommandProcessorInterface;
524 int result = pluginHandle->m_initFunc(&context);
525 pluginHandle->m_isInitialized = true;
526 pluginHandle->m_userPointer = context.m_userPointer;
527 pluginHandle->m_returnData = 0;
528 }
529 return pluginUniqueId;
530 }
531
selectPluginRenderer(int pluginUniqueId)532 void b3PluginManager::selectPluginRenderer(int pluginUniqueId)
533 {
534 m_data->m_activeRendererPluginUid = pluginUniqueId;
535 }
536
getRenderInterface()537 UrdfRenderingInterface* b3PluginManager::getRenderInterface()
538 {
539 UrdfRenderingInterface* renderer = 0;
540
541 if (m_data->m_activeRendererPluginUid >= 0)
542 {
543 b3PluginHandle* plugin = m_data->m_plugins.getHandle(m_data->m_activeRendererPluginUid);
544 if (plugin && plugin->m_getRendererFunc)
545 {
546 b3PluginContext context = {0};
547 context.m_userPointer = plugin->m_userPointer;
548 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
549 renderer = plugin->m_getRendererFunc(&context);
550 }
551 }
552 return renderer;
553 }
554
selectFileIOPlugin(int pluginUniqueId)555 void b3PluginManager::selectFileIOPlugin(int pluginUniqueId)
556 {
557 m_data->m_activeFileIOPluginUid = pluginUniqueId;
558 }
559
getFileIOInterface()560 struct CommonFileIOInterface* b3PluginManager::getFileIOInterface()
561 {
562 CommonFileIOInterface* fileIOInterface = 0;
563 if (m_data->m_activeFileIOPluginUid >= 0)
564 {
565 b3PluginHandle* plugin = m_data->m_plugins.getHandle(m_data->m_activeFileIOPluginUid);
566 if (plugin && plugin->m_getFileIOFunc)
567 {
568 b3PluginContext context = {0};
569 context.m_userPointer = plugin->m_userPointer;
570 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
571 fileIOInterface = plugin->m_getFileIOFunc(&context);
572 }
573 }
574 if (fileIOInterface==0)
575 {
576 return &m_data->m_defaultFileIO;
577 }
578 return fileIOInterface;
579 }
580
selectCollisionPlugin(int pluginUniqueId)581 void b3PluginManager::selectCollisionPlugin(int pluginUniqueId)
582 {
583 m_data->m_activeCollisionPluginUid = pluginUniqueId;
584 }
585
getCollisionInterface()586 struct b3PluginCollisionInterface* b3PluginManager::getCollisionInterface()
587 {
588 b3PluginCollisionInterface* collisionInterface = 0;
589 if (m_data->m_activeCollisionPluginUid >= 0)
590 {
591 b3PluginHandle* plugin = m_data->m_plugins.getHandle(m_data->m_activeCollisionPluginUid);
592 if (plugin && plugin->m_getCollisionFunc)
593 {
594 b3PluginContext context = {0};
595 context.m_userPointer = plugin->m_userPointer;
596 context.m_physClient = (b3PhysicsClientHandle)m_data->m_physicsDirect;
597 collisionInterface = plugin->m_getCollisionFunc(&context);
598 }
599 }
600 return collisionInterface;
601 }
602
getReturnData(int pluginUniqueId)603 const struct b3UserDataValue* b3PluginManager::getReturnData(int pluginUniqueId)
604 {
605 b3PluginHandle* plugin = m_data->m_plugins.getHandle(pluginUniqueId);
606 if (plugin)
607 {
608 return plugin->m_returnData;
609 }
610 return 0;
611 }
612