Iray Programmer's Manual

Extending the database with user-defined classes

This topic introduces:

  1. The important API interfaces and steps to extend the database for user-defined classes:
  2. The program example_user_defined_classes.cpp, which demonstrates the implementation and usage of user-defined classes to be used in conjunction with the Iray API. In this example, a new class is defined in and used by the main application.
    Note: In contrast, the example for plugins, described in Extending neuray with plugins demonstrates how to provide additional functionality with user-defined classes by using plugins.
    A simple class called My_class with a corresponding interface class IMy_class is used to demonstrate the required steps.

Defining the interface of a user-defined class

To define user-defined classes you need to provide an interface with the public methods of your class. The interface is an abstract base class which contains only pure virtual methods. The interface must be (directly or indirectly) derived from mi::neuraylib::IUser_class.

The easiest way to define such an interface is by deriving from the mixin class mi::base::Interface_declare. The first eleven template parameters are used to construct the mi::base::Uuid_t (which must be unique). The last template parameter denotes the actual interface to derive from (should be mi::neuraylib::IUser_class, or another interface (directly or indirectly) derived from mi::neuraylib::IUser_class).

This definition of the interface is required by the applications (or other plugins) in which the user-defined class is supposed to be used.

Implementing a user-defined class

You need to implement the interface defined in IMy_class.

Deriving your implementation from the mixin mi::neuraylib::User_class is required to ensure that your implementation class works together with the class framework, including features like creation, serialization and deserialization. Note that if you derive your implementation class directly from your interface or indirectly via mi::base::Interface_implement it will not correctly work together with the class framework.

To make serialization and deserialization work, you need to implement mi::neuraylib::ISerializable::serialize() and mi::neuraylib::ISerializable::deserialize(). In this example it is sufficient to write the single member m_foo to the serializer and to read it from the deserializer, respectively. Furthermore, you need to implement mi::neuraylib::IUser_class::copy() which has to create a copy of a given object.

Registering and using a user-defined class

Finally the example demonstrates how to use the user-defined class. Before using the new class it is necessary to register it with the Iray API. This can be accomplished by mi::neuraylib::IExtension_api::register_class(). Using the user-defined class works the same way as for all other classes. You can use mi::neuraylib::ITransaction::create() to create new instances; you can store them in the database and retrieve them from the database. Here, the example just does a simply test of the serialization and deserialization functionality.

imy_class.h

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 #ifndef IMY_CLASS_H
006 #define IMY_CLASS_H
007 
008 #include <mi/neuraylib.h>
009 
010 // The interface for the user-defined class.
011 //
012 // The class has getter and setter for an artificial property "foo" to demonstrate
013 // basic features like serialization and deserialization
014 class IMy_class : public
015     mi::base::Interface_declare<0x7274f2a1,0xb7e1,0x4fc7,0x8c,0xe4,0xef,0x2d,0xd0,0x9b,0x75,0x52,
016                                 mi::neuraylib::IUser_class>
017 {
018 public:
019     // Sets property foo
020     virtual void set_foo( mi::Sint32 foo) = 0;
021 
022     // Gets property foo
023     virtual mi::Sint32 get_foo() const = 0;
024 };
025 
026 #endif // IMY_CLASS_H

my_class.h

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 #ifndef MY_CLASS_H
006 #define MY_CLASS_H
007 
008 #include <mi/neuraylib.h>
009 #include "imy_class.h"
010 
011 // The implementation of the IMy_class interface
012 class My_class : public
013     mi::neuraylib::User_class<0x0650d689,0xef50,0x433f,0xb3,0xae,0xae,0x83,0xa9,0xf2,0xf2,0xa6,
014                               IMy_class>
015 {
016 public:
017     // Constructor
018     My_class() { m_foo = 0; }
019 
020     // Destructor
021     ~My_class() { }
022 
023     // Sets property foo
024     void set_foo( mi::Sint32 foo) { m_foo = foo; }
025 
026     // Gets property foo
027     mi::Sint32 get_foo() const { return m_foo; }
028 
029     // Serializes an instance of My_class
030     void serialize( mi::neuraylib::ISerializer* serializer) const
031     {
032         serializer->write( &m_foo);
033     }
034 
035     // Deserializes an instance of My_class
036     void deserialize( mi::neuraylib::IDeserializer* deserializer)
037     {
038         deserializer->read( &m_foo);
039     }
040 
041     // Creates a copy of the object
042     mi::neuraylib::IUser_class* copy () const
043     {
044         My_class* copy = new My_class( *this);
045         return copy;
046     }
047 
048     // Returns a human readable class name
049     const char* get_class_name() const
050     {
051         return "My_class";
052     }
053 
054     // Returns the list of elements referenced by this elements, none in this example.
055     mi::IArray* get_references( mi::neuraylib::ITransaction* /*transaction*/) const
056     {
057         return 0;
058     }
059 
060 private:
061     // Member to realize property foo
062     mi::Sint32 m_foo;
063 };
064 
065 #endif // MY_CLASS_H

example_user_defined_classes.cpp

001 /******************************************************************************
002  * © 1986, 2015 NVIDIA ARC GmbH. All rights reserved.
003  *****************************************************************************/
004 
005 // examples/example_user_defined_classes.cpp
006 //
007 // Demonstrates implementation and usage of user-defined classes
008 
009 #include <mi/neuraylib.h>
010 
011 // Include code shared by all examples.
012 #include "example_shared.h"
013 // Include header file for the interface of the user-defined class.
014 #include "imy_class.h"
015 // Include header file for the implementation of the user-defined class.
016 #include "my_class.h"
017 
018 void configuration( mi::base::Handle<mi::neuraylib::INeuray> neuray)
019 {
020     // Register the user-defined class.
021     mi::base::Handle<mi::neuraylib::IExtension_api> extension_api(
022         neuray->get_api_component<mi::neuraylib::IExtension_api>());
023     check_success( extension_api.is_valid_interface());
024     check_success( extension_api->register_class<My_class>( "My_class") == 0);
025 }
026 
027 void test_plugin( mi::base::Handle<mi::neuraylib::INeuray> neuray)
028 {
029     // Get the database, the global scope of the database, and create a transaction in the global
030     // scope.
031     mi::base::Handle<mi::neuraylib::IDatabase> database(
032         neuray->get_api_component<mi::neuraylib::IDatabase>());
033     check_success( database.is_valid_interface());
034     mi::base::Handle<mi::neuraylib::IScope> scope(
035         database->get_global_scope());
036     mi::base::Handle<mi::neuraylib::ITransaction> transaction(
037         scope->create_transaction());
038     check_success( transaction.is_valid_interface());
039 
040     // Create instance of My_class and call a method on it.
041     mi::base::Handle<IMy_class> my_class( transaction->create<IMy_class>( "My_class"));
042     check_success( my_class.is_valid_interface());
043     my_class->set_foo( 42);
044 
045     // Store instance of My_class in the database and release the handle
046     check_success( transaction->store( my_class.get(), "some_name") == 0);
047     my_class = 0;
048 
049     // Get the instance of My_class from the database again and change the property
050     my_class = transaction->edit<IMy_class>( "some_name");
051     check_success( my_class.is_valid_interface());
052     check_success( my_class->get_foo() == 42);
053     my_class->set_foo( 43);
054     my_class = 0;
055 
056     transaction->commit();
057 }
058 
059 int main( int /*argc*/, char* /*argv*/[])
060 {
061     // Access the neuray library
062     mi::base::Handle<mi::neuraylib::INeuray> neuray( load_and_get_ineuray());
063     check_success( neuray.is_valid_interface());
064 
065     // Configure the neuray library
066     configuration( neuray);
067 
068     // Start the neuray library
069     check_success( neuray->start() == 0);
070 
071     // Load and interact with the plugin
072     test_plugin( neuray);
073 
074     // Shut down the neuray library
075     check_success( neuray->shutdown() == 0);
076     neuray = 0;
077 
078     // Unload the neuray library
079     check_success( unload());
080 
081     keep_console_open();
082     return EXIT_SUCCESS;
083 }