PluginCreation old
From SOFAWiki
Contents |
What is a Plug-in?
In Sofa, a plugin is a list of components that can be integrated in the scene graph via the factory. A plugin contains a set of classes derivated from sofa components. You can also put external classes used by your components. The purpose is to add your own components into sofa without have to integrate them into the heart of Sofa directories. Optionnally you can also provide custom widgets to represent your component datas in the GUI. A plugin is actually a shared library, loaded at runtime by Sofa. They are available by default in the sofa/lib/sofa-plugins/ directory.
Creation of your plug-in project
Create your project in Sofa/applications/plugins/ . The project is a directory containing your source files; let's call it "MyPlugin". In addition to your source code files, you have to create 2 files : initMyPlugin.cpp, and MyPlugin.pro. You can also create a text file containing additionnal information like the authors or the license of your plugin, that will be copy and provide with the binary of the plugin. Finally, you have to add into Sofa/applications/plugins/plugins.pro the line :
SUBDIRS += MyPlugin
You should look at pluginExample to see what it looks like.
The MyPlugin.pro file
This file is used by QMake to configure compilation. It is composed by 2 parts : the first one general to all plugin, and you shouldn't have to modify it :
SOFA_DIR=../../.. include($${SOFA_DIR}/sofa.cfg) TEMPLATE = lib DESTDIR = $$SOFA_DIR/lib/sofa-plugins #set configuration to dynamic library CONFIG += $$CONFIGLIBRARIES CONFIG -= staticlib CONFIG += dll
The second part is specific to your plugin. You have to fill the name, put the list of your source files, and set the lib dependencies :
TARGET = MyPlugin$$LIBSUFFIX DEFINES += SOFA_BUILD_MYPLUGIN #specific macro only used in Windows for import/export of dll symbols LIBS += $$SOFA_LIBS LIBS += $$SOFA_EXT_LIBS INCLUDEPATH += $$SOFA_DIR/extlibs SOURCES = MyComponent.cpp \ OtherComponent.cpp \ initMyPlugin.cpp HEADERS = MyComponent.h \ OtherComponent.h README_FILE = PluginExample.txt #here is the optionnal text file containg other information you want to provide unix : QMAKE_POST_LINK = cp $$README_FILE $$DESTDIR win32 : QMAKE_POST_LINK = copy \"$$README_FILE\" \"$$SOFA_DIR/lib/sofa-plugins\"
The initMyPlugin.cpp file
This file is for the configuration of the plugin, and to set it loadable by the Sofa plugin manager. I advice you to take it from the initPluginExample.cpp file.
First part is macro definition for import/export symbol on windows :
#include <sofa/helper/system/config.h> #ifndef WIN32 #define SOFA_EXPORT_DYNAMIC_LIBRARY #define SOFA_IMPORT_DYNAMIC_LIBRARY #define SOFA_MYPLUGIN_API #else #ifdef SOFA_BUILD_MYPLUGIN // YOU just have to put here the name of the macro you set in the .pro file #define SOFA_EXPORT_DYNAMIC_LIBRARY __declspec( dllexport ) #define SOFA_MYPLUGIN_API SOFA_EXPORT_DYNAMIC_LIBRARY #else #define SOFA_IMPORT_DYNAMIC_LIBRARY __declspec( dllimport ) #define SOFA_MYPLUGIN_API SOFA_IMPORT_DYNAMIC_LIBRARY #endif #endif
It contains several short convenient functions, to make the plugin readable by the Plugin Manager :
SOFA_MYPLUGIN_API void initExternalModule(); //you don't have to chage this function SOFA_MYPLUGIN_API const char* getModuleName(); //give the module name SOFA_MYPLUGIN_API const char* getModuleVersion(); //give a version number of the plugin, update it if you want know easily which version is currently loaded in Sofa SOFA_MYPLUGIN_API const char* getModuleDescription(); //help the user to know what is supposed to do your plugin SOFA_MYPLUGIN_API const char* getModuleComponentList(); //help the user to know what are the components contained in the plugin
The last part are the macro that link your components to the Sofa factory :
SOFA_LINK_CLASS(MyComponent) SOFA_LINK_CLASS(OtherComponent)
Writing custom widgets for your component
By default Sofa will generate an edition dialog box when you double click in your component in the scene or visual graph to modify its data fields. However you can also register your own widget to do that data edition operation. In MyFakeComponentDataWidgets.h and .cpp files you have an example of a custom widget used to represent a data declared in MyFakeComponent. Basically you need to write a class which derives from TDataWidget and implement methods describing what widgets you want to create, how they can read from a Data, and how they can write into it.
Writing a custom widget for a Data<unsigned>
/** *\brief Customization of the representation of Data<unsigned> types * in the gui. In the .cpp file this widget is registered to represent * myData from MyFakeComponent in the gui. **/ class CustomDataUnsignedWidget : public TDataWidget<unsigned> { Q_OBJECT public : ///The class constructor takes a TData<unsigned> since it creates ///a widget for a that particular data type. CustomDataUnsignedWidget(QWidget* parent, const char* name, core::objectmodel::TData<unsigned>* data): TDataWidget<unsigned>(parent,name,data){}; ///In this method we create the widgets and perform the signal / slots ///connections. virtual bool createWidgets(); protected slots: void change(); protected: ///Implements how update the widgets knowing the data value. virtual void readFromData(); ///Implements how to update the data, knowing the widget value. virtual void writeToData(); QSlider* qslider; QLabel* label1; QLabel* label2; }; }
Registration in the factory.
/* register this new class in the DataWidgetFactory. The factory key is the Data widget property (see MyFakeComponent constructor) */ helper::Creator<DataWidgetFactory,CustomDataUnsignedWidget> DW_myData("widget_myData",false);
Make use of this widget to represent a data containing an unsigned by using the setWidget method of a Data object.
MyFakeComponent::MyFakeComponent() : customUnsignedData( initData(&customUnsignedData,(unsigned)1,"Custom Unsigned Data","Example of unsigned data with custom widget") ), regularUnsignedData( initData(®ularUnsignedData,(unsigned)1,"Unsigned Data","Example of unsigned data with standard widget") ) { customUnsignedData.setWidget("widget_myData"); }
Build and load the plugin
To build :
1. For windows users, you have to run projectVC8.bat or projectVC9.bat depending on your version of Microsoft Visual Studio C++.
For the others, simply run qmake at the Sofa main directory
2. Then launch the compilation.
To load :
When using GUI
1. Launch the excutable runSofa (or the modeler)
2. Go to the menu Edit > Plugin Manager...
3. Add you plugin by selecting it In the browser. Plugins should be in Sofa/lib/sofa-plugins directory. Extension is .dll on Windows, .so on linux, and .dylib on MacOs![]()
On batch mode
Use the -l option, specifying the path to your plugin library, for example :
./bin/runSofa -g batch -l lib/sofa-plugins/libPluginExample.so examples/Demos/liver.scn
Quick GUI run
It is possible to avoid to manually load the plugin, using the batch command, by customizing the run command in your favorite IDE.
For example, the following image shows a project customization for QtCreator on Linux. The run command and the LD_LIBRARY_PATH are customized.
Using this, simply run your project in the IDE. The following image shows the result of running the application scene graph




