Extending neuray with plugins
This topic introduces:
- Important interfaces and the required steps to add functionality and package it as a plugin:
- The programs plugin.cpp and example_plugins.cpp, which demonstrate how to provide additional functionality as plugins. This example extends the user-defined classes described in Extending the database with user-defined classes. The functionality of the IMy_class interface is provided to the main application by using a plugin. Therefore, the main application only needs the definition of the interface IMy_class and the compiled plugin, but not the source code of the implementation.
Implementing a plugin
To implement a plugin you need to provide an implementation of the mi::neuraylib::IPlugin interface. An example implementation of such a class is shown in the code below. The most important part is the implementation of the mi::neuraylib::IPlugin::init() method which has to register all user-defined classes.
Finally you need to provide a factory function called mi_plugin_factory() that creates an instance of your implementation of mi::neuraylib::IPlugin. Again, using the example implementation as shown in the code below is fine.
You need to compile the implementation of your interfaces, your implementation of mi::neuraylib::IPlugin, and the factory function, and to create a DSO from the object code. Using g++ you can use commands similar to the following:
g++ -I$NEURAY_ROOT/include -fPIC -c plugin.cpp -o plugin.o g++ -shared -export-dynamic --whole-archive plugin.o -o libplugin.so
Loading a plugin
You can load plugins by passing the filename to the method mi::neuraylib::IPlugin_configuration::load_plugin_library(). After the plugin has been loaded (in a way similar to the loading of the DSO for the Iray API itself), the method mi::neuraylib::IPlugin::init() is called. In this method you need to register all user-defined classes.
Using the user-defined class works the same way as for all other classes. In particular there is no difference to user-defined classes defined in the main application as described in Extending the database with user-defined classes.
plugin.cpp
001 /****************************************************************************** 002 * © 1986, 2016 NVIDIA Corporation. All rights reserved. 003 *****************************************************************************/ 004 005 #include <mi/neuraylib.h> 006 #include "my_class.h" 007 008 // Implementation of the IPlugin interface 009 class Plugin_impl : public mi::neuraylib::IPlugin 010 { 011 public: 012 // Virtual destructor 013 virtual ~Plugin_impl() { } 014 015 // Returns the name of the plugin 016 const char* get_name() const { return "example plugin"; } 017 018 // Returns the type of the plugin 019 const char* get_type() const { return MI_NEURAYLIB_PLUGIN_TYPE; } 020 021 // Returns the version of the plugin 022 mi::Sint32 get_version() const { return 1; } 023 024 // Returns the compiler used to compile the plugin 025 const char* get_compiler() const { return "unknown"; } 026 027 // Releases the plugin giving back all allocated resources 028 void release() { delete this; } 029 030 // Initializes the plugin 031 bool init( mi::neuraylib::IPlugin_api* plugin_api) 032 { 033 mi::base::Handle<mi::neuraylib::ILogging_configuration> logging_configuration( 034 plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>()); 035 mi::base::Handle<mi::base::ILogger> logger( 036 logging_configuration->get_forwarding_logger()); 037 logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN", 038 "Plugin_impl::init() called"); 039 mi::base::Handle<mi::neuraylib::IExtension_api> extension_api( 040 plugin_api->get_api_component<mi::neuraylib::IExtension_api>()); 041 if( ! extension_api.is_valid_interface()) 042 return false; 043 return extension_api->register_class<My_class>( "My_class") == 0; 044 } 045 046 // Exits the plugin 047 bool exit( mi::neuraylib::IPlugin_api* plugin_api) 048 { 049 mi::base::Handle<mi::neuraylib::ILogging_configuration> logging_configuration( 050 plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>()); 051 mi::base::Handle<mi::base::ILogger> logger( 052 logging_configuration->get_forwarding_logger()); 053 logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN", 054 "Plugin_impl::exit() called"); 055 return true; 056 } 057 }; 058 059 // Factory to create an instance of Plugin_impl 060 extern "C" 061 MI_DLL_EXPORT 062 mi::base::Plugin* mi_plugin_factory( 063 mi::Sint32 index, // index of the plugin 064 void* context) // context given to the library, ignore 065 { 066 if( index != 0) 067 return 0; 068 return new Plugin_impl; 069 }
example_plugins.cpp
001 /****************************************************************************** 002 * © 1986, 2016 NVIDIA Corporation. All rights reserved. 003 *****************************************************************************/ 004 005 // examples/example_plugins.cpp 006 // 007 // Demonstrates providing additional functionality via plugins 008 009 #include <mi/neuraylib.h> 010 011 // Include code shared by all examples. 012 #include "example_shared.h" 013 014 // Include header file for the interface of the user-defined class. 015 #include "imy_class.h" 016 017 void test_plugin( mi::base::Handle<mi::neuraylib::INeuray> neuray) 018 { 019 020 // Get the database, the global scope of the database, and create a transaction in the global 021 // scope. 022 mi::base::Handle<mi::neuraylib::IDatabase> database( 023 neuray->get_api_component<mi::neuraylib::IDatabase>()); 024 check_success( database.is_valid_interface()); 025 mi::base::Handle<mi::neuraylib::IScope> scope( 026 database->get_global_scope()); 027 mi::base::Handle<mi::neuraylib::ITransaction> transaction( 028 scope->create_transaction()); 029 check_success( transaction.is_valid_interface()); 030 031 // Create instance of My_class and call a method on it. 032 mi::base::Handle<IMy_class> my_class( transaction->create<IMy_class>( "My_class")); 033 check_success( my_class.is_valid_interface()); 034 my_class->set_foo( 42); 035 036 // Store instance of My_class in the database and release the handle 037 transaction->store( my_class.get(), "some_name"); 038 my_class = 0; 039 040 // Get the instance of My_class from the database again 041 my_class = transaction->edit<IMy_class>( "some_name"); 042 check_success( my_class.is_valid_interface()); 043 check_success( my_class->get_foo() == 42); 044 my_class = 0; 045 046 transaction->commit(); 047 } 048 049 int main( int /*argc*/, char* /*argv*/[]) 050 { 051 // Access the neuray library 052 mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray()); 053 check_success( neuray.is_valid_interface()); 054 055 // Load the plugin 056 mi::base::Handle<mi::neuraylib::IPlugin_configuration> plugin_configuration( 057 neuray->get_api_component<mi::neuraylib::IPlugin_configuration>()); 058 check_success( plugin_configuration.is_valid_interface()); 059 #ifndef MI_PLATFORM_WINDOWS 060 check_success( plugin_configuration->load_plugin_library( "./libplugin.so") == 0); 061 #else 062 check_success( plugin_configuration->load_plugin_library( "./plugin.dll") == 0); 063 #endif 064 plugin_configuration = 0; 065 066 // Start the neuray library 067 mi::Sint32 result = neuray->start(); 068 check_start_success( result); 069 070 // Interact with the loaded plugin 071 test_plugin( neuray); 072 073 // Shut down the neuray library 074 check_success( neuray->shutdown() == 0); 075 neuray = 0; 076 077 // Unload the neuray library 078 check_success( unload()); 079 080 keep_console_open(); 081 return EXIT_SUCCESS; 082 }