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() ? &notifications[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