Clarisse 5.0 SP8 SDK  5.0.5.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
Declaring new modules in Clarisse

Table of Contents

This topic covers how to use the Clarisse module system and how to declare new modules.

What is a module?

Modules are dynamic libraries written in C++ that are loaded by Clarisse during starup in order to extend Clarisse's core features. A module in Clarisse defines both OfClass and its implementation. It can virtually define anything, from new type of geometries, to custom materials and textures or custom renderering engines. Before writing your first module you should familiarize yourself with the CID syntax as well as cmagen.

Module declaration

Your module will have to link on several Clarisse libraries depending on your needs, but there are few that are required:

ix_module, ix_of, ix_dso, ix_core, ix_gui

Module entry point is a C function called on_register_module within the main file, which will declare and register callbacks depending on the module needs. Lets say you module main file is called main.cpp, here is a minimal example:

#include <dso_export.h>
#include <of_app.h>
// Always include the cma generated by your cid file on pre-build step
#include <my_new_module.cma>
/* This is the callback declaration part. You declare which callbacks are going to be used in this module.
Specify here which callback class you inherit from, depending on your module class inheritance. (if you create a ModuleWidget, inherit from ModuleWidgetCallbacks)
All callback classes inherit from OfClassCallbacks */
static ModuleObject *declare_module(OfObject& object, OfObjectFactory& objects);
static bool destroy_module(OfObject& object, OfObjectFactory& objects, ModuleObject *impl);
/* This is the callback registration part. You register the callback in the proper function pointers so they can be called. Callbacks you can implement depend on the module you are deriving from.
See modules class documentation for a list and description of available callbacks. */
IX_BEGIN_EXTERN_C
DSO_EXPORT void
on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes)
{
OfClass *new_class = IX_DECLARE_MODULE_CLASS(MyNewModule);
new_classes.add(new_class);
// Assign the callbacks you implemented here
IX_MODULE_CLBK *module_callbacks;
module_callbacks->cb_create_module = IX_MODULE_CLBK::declare_module;
module_callbacks->cb_destroy_module = IX_MODULE_CLBK::destroy_module;
}
IX_END_EXTERN_C
// Callbacks implementation
IX_MODULE_CLBK::declare_module(OfObject& object, OfObjectFactory& objects)
{
MyNewModule *module = new MyNewModule(object);
return module;
}
bool
IX_MODULE_CLBK::destroy_module(OfObject& object, OfObjectFactory& objects, ModuleObject *impl)
{
delete impl;
return true;
}

IX_MODULE_CLBK is a typedef to an internal class declared by the macro IX_BEGIN_DECLARE_MODULE_CALLBACKS. Its the name of the class containing the callbacks for this module.

Which callbacks to implement ?

Depending on the module you are creating, you may want to implement various callbacks. Please refer to the documentation of OfClassCallbacks and its subclasses to see which callbacks are available for your module to be implemented. The callbacks available depend on what you inherited from in IX_BEGIN_DECLARE_MODULE_CALLBACKS macro.

Example for a module widget

If you want to implement a new module widget (to have a new window within clarisse for specific purposes), here is a simple example:

// Called just after module creation to do some initialization
static void module_constructor(OfObject& object, ModuleObject *module);
// Called to create the module
static GuiWidget *create_widget(OfObject& object, GuiWidget& parent);
// Called when application selection change, to be able to react within the module
static void on_selection_change(OfObject& object, const CoreString& selection_group, const CoreVector<OfItem *>& selection);
// Called when application loads the settings, to allow the widget to load its serialized settings
static void load_settings(OfObject& object, const ParserGroup& settings);
// Called when application saves the settings, to allow the widget to serialize its settings
static void save_settings(OfObject& object, ParserGroup& settings);
IX_BEGIN_EXTERN_C
DSO_EXPORT void
on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes)
{
OfClass *new_class = IX_DECLARE_MODULE_CLASS(MyNewWidget);
new_classes.add(new_class);
IX_MODULE_CLBK *module_callbacks;
module_callbacks->cb_module_constructor = IX_MODULE_CLBK::module_constructor;
module_callbacks->cb_create_widget = IX_MODULE_CLBK::create_widget;
module_callbacks->cb_on_selection_change = IX_MODULE_CLBK::on_selection_change;
module_callbacks->cb_load_settings = IX_MODULE_CLBK::load_settings;
module_callbacks->cb_save_settings = IX_MODULE_CLBK::save_settings;
}
IX_END_EXTERN_C
void
IX_MODULE_CLBK::module_constructor(OfObject& object, ModuleObject *module)
{
// This is the way to specify that you are interested in listening to the GLOBAL_SELECTION modifications
((ModuleWidget *)module)->add_selection_group(GLOBAL_SELECTION);
}
IX_MODULE_CLBK::create_widget(OfObject& object, GuiWidget& parent)
{
// Instantiate and create your module
return new MyNewWidget(parent, parent.get_x(), parent.get_y(), parent.get_width(), parent.get_height());
}
// React to selection changes
void
IX_MODULE_CLBK::on_selection_change(OfObject& object, const CoreString& selection_group, const CoreVector<OfItem *>& selection)
{
ModuleWidget *module = (ModuleWidget *) object.get_module();
MyNewWidget *editor = (MyNewWidget*) module->get_widget();
editor->set_selection(selection);
}
void
IX_MODULE_CLBK::load_settings(OfObject& object, const ParserGroup& settings)
{
ModuleWidget *module = (ModuleWidget *) object.get_module();
MyNewWidget *editor = (MyNewWidget *) module->get_widget();
editor->load_settings(settings);
}
void
IX_MODULE_CLBK::save_settings(OfObject& object, ParserGroup& settings)
{
ModuleWidget *module = (ModuleWidget *) object.get_module();
MyNewWidget *editor = (MyNewWidget *) module->get_widget();
editor->save_settings(settings);
}

Declaring multiple modules in the same module Library

It is possible to declare multiple modules in the same library. It means having a cid file and a cpp file with callbacks registration for each module, compiled in the same library. The module library entry point remains the same, the C function on_register_module.

There is currently only one restriction, abstract module classes (which are inherited by other classes like module.texture or module.geometry) must be stored in a module library that matches their name, for resolution purpose. By convention, these classes are stored alone in a module that has the same name. This is the case for module.texture, module.geometry, module.layer...

Structure Example of a module library "custom_modules" containing 3 classes:

main.cpp, custom_modules.h, custom_module1.cpp, custom_module2.cpp, custom_module3.cpp, custom_module1.cid, custom_module2.cid, custom_module3.cid

main.cpp

IX_BEGIN_EXTERN_C
DSO_EXPORT void
on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes)
{
CustomModule1::on_register_module(app, new_classes);
CustomModule2::on_register_module(app, new_classes);
CustomModule2::on_register_module(app, new_classes);
}
IX_END_EXTERN_C

custom_modules.h

#define __custom_modules_h__
class OfApp;
class OfClass;
struct CustomModule1 {
static void on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes);
};
struct CustomModule2 {
static void on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes);
};
struct CustomModule3 {
static void on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes);
};

the other files are:

custom_module1.cpp, custom_module1.cid, custom_module2.cpp, custom_module2.cid, custom_module3.cpp, custom_module3.cid

Their content is exactly the same that they would be for a single class module library. See above example. The only difference remains in the declaration of "on_register_module" function which is now a function as declared in custom_modules.h and not a C callback.

Example with custom_module1.cpp:

static ModuleObject *declare_module(OfObject& object, OfObjectFactory& objects);
static bool destroy_module(OfObject& object, OfObjectFactory& objects, ModuleObject *impl);
void
CustomModule1::on_register_module(OfApp& app, CoreVector<OfClass *>& new_classes)
{
OfClass *new_class = IX_DECLARE_MODULE_CLASS(CustomModule1);
new_classes.add(new_class);
IX_MODULE_CLBK *module_callbacks;
module_callbacks->cb_create_module = IX_MODULE_CLBK::declare_module;
module_callbacks->cb_destroy_module = IX_MODULE_CLBK::destroy_module;
...
}
// Callbacks implementation
IX_MODULE_CLBK::declare_module(OfObject& object, OfObjectFactory& objects)
{
CustomModule1 *module = new CustomModule1(object);
return module;
}
...

The cid files are unchanged whether the module is alone in its library or not.