neuray API Programmer's Manual

Example for Plugins

[Previous] [Next] [Up]

This example demonstrates how to provide additional functionality in form of plugins. It extends the previous example about user-defined classes.

In contrast to the previous application, the functionality of the IMy_class interface will be provided to the main application via 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.

New Topics

  • Implementation of a plugin

  • Loading a plugin

Detailed Description

Implementation of 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
‎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 neuray 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 in the previous example.

Source Code Location: example/plugin.cpp

‎/******************************************************************************
 * Copyright 1986, 2011 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/

#include <mi/neuraylib.h>
#include "my_class.h"

// Implementation of the IPlugin interface
class Plugin_impl : public mi::neuraylib::IPlugin
{
public:
    // Gets the name of the plugin
    const char* get_name() const { return "example plugin"; }

    // Gets the type of the plugin
    const char* get_type() const { return MI_NEURAYLIB_PLUGIN_TYPE; }

    // Gets the version of the plugin
    mi::Sint32 get_version() const { return 1; }

    // Gets the compiler used to compile the plugin
    const char* get_compiler() const { return "unknown"; }

    // Releases the plugin giving back all allocated resources
    void release() { delete this; }

    // Initializes the plugin
    bool init( mi::neuraylib::IPlugin_api* plugin_api)
    {
        mi::base::Handle< mi::neuraylib::ILogging_configuration> logging_configuration(
            plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>());
        mi::base::Handle< mi::base::ILogger> logger(
            logging_configuration->get_forwarding_logger());
        logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN",
            "Plugin_impl::init() called");
        mi::base::Handle< mi::neuraylib::IExtension_api> extension_api(
            plugin_api->get_api_component<mi::neuraylib::IExtension_api>());
        if( ! extension_api.is_valid_interface())
            return false;
        return extension_api->register_class<My_class>( "My_class") == 0;
    }

    // Exits the plugin
    bool exit( mi::neuraylib::IPlugin_api* plugin_api)
    {
        mi::base::Handle< mi::neuraylib::ILogging_configuration> logging_configuration(
            plugin_api->get_api_component<mi::neuraylib::ILogging_configuration>());
        mi::base::Handle< mi::base::ILogger> logger(
            logging_configuration->get_forwarding_logger());
        logger->message( mi::base::MESSAGE_SEVERITY_INFO, "PLUGIN",
            "Plugin_impl::exit() called");
        return true;
    }
};

// Factory to create an instance of Plugin_impl
extern "C"
MI_DLL_EXPORT
mi::base::Plugin* mi_plugin_factory(
    mi::Sint32 index,         // index of the plugin
    void* context)            // context given to the library, ignore
{
    if( index != 0)
        return 0;
    return new Plugin_impl;
}

Source Code Location: examples/example_plugins.cpp

‎/******************************************************************************
 * Copyright 1986, 2011 NVIDIA Corporation. All rights reserved.
 *****************************************************************************/

// examples/example_plugins.cpp
//
// Demonstrates providing additional functionality via plugins

#include <mi/neuraylib.h>

// Include code shared by all examples.
#include "example_shared.h"

// Include header file for the interface of the user-defined class.
#include "imy_class.h"

void test_plugin( mi::base::Handle< mi::neuraylib::INeuray> neuray)
{

    // Get the database, the global scope, which is the root for all transactions,
    // and create a transaction.
    mi::base::Handle< mi::neuraylib::IDatabase> database(
        neuray->get_api_component<mi::neuraylib::IDatabase>());
    check_success( database.is_valid_interface());
    mi::base::Handle< mi::neuraylib::IScope> scope(
        database->get_global_scope());
    mi::base::Handle< mi::neuraylib::ITransaction> transaction(
        scope->create_transaction());
    check_success( transaction.is_valid_interface());

    // Create instance of My_class and call a method on it.
    mi::base::Handle< IMy_class> my_class( transaction->create<IMy_class>( "My_class"));
    check_success( my_class.is_valid_interface());
    my_class->set_foo( 42);

    // Store instance of My_class in the database and release the handle
    transaction->store( my_class.get(), "some_name");
    my_class = 0;

    // Get the instance of My_class from the database again
    my_class = transaction->edit<IMy_class>( "some_name");
    check_success( my_class.is_valid_interface());
    check_success( my_class->get_foo() == 42);
    my_class = 0;

    // All transactions need to get committed or aborted, not really important in this example.
    transaction->commit();
}

int main( int argc, char* argv[])
{
    // Access the neuray library
    mi::base::Handle< mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
    check_success( neuray.is_valid_interface());

    // Load the plugin
    mi::base::Handle< mi::neuraylib::IPlugin_configuration> plugin_configuration(
        neuray->get_api_component<mi::neuraylib::IPlugin_configuration>());
    check_success( plugin_configuration.is_valid_interface());
#ifndef MI_PLATFORM_WINDOWS
    check_success( plugin_configuration->load_plugin_library( "./libplugin.so") == 0);
#else
    check_success( plugin_configuration->load_plugin_library( "./plugin.dll") == 0);
#endif
    plugin_configuration = 0;

    // Start the neuray library
    check_success( neuray->start( true) == 0);

    // Interact with the loaded plugin
    test_plugin( neuray);

    // Shut down the neuray library
    check_success( neuray->shutdown() == 0);
    neuray = 0;

    // Unload the neuray library
    check_success( unload());

    return EXIT_SUCCESS;
}

[Previous] [Next] [Up]