Extending the database with user-defined classes
This topic introduces:
- The important API interfaces and steps to extend the database for user-defined classes:
- 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::ISerializable::serialize() and mi::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, 2014 NVIDIA Corporation. 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, 2014 NVIDIA Corporation. 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::ISerializer* serializer) const 031 { 032 serializer->write( &m_foo); 033 } 034 035 // Deserializes an instance of My_class 036 void deserialize( mi::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, 2014 NVIDIA Corporation. 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, which is the root for all transactions, 030 // and create a transaction. 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 }