OpenCOVER Plugin Programming

The virtual reality Renderer module OpenCOVER is a COVISE module with support for virtual reality (VR) input devices such as Polhemus FASTRAK, Ascension Motionstar or A.R.T. tracking devices and backprojection displays with stereo projection like CAVE or workbench. OpenCOVER can also be started independently of COVISE and be used as a virtual reality viewer for 3D geometry.

The functionality of OpenCOVER can be extended through plugins. A plugin is a dynamic library with a certain interface. During execution, OpenCOVER executes the functions provided by each such library.

Plugins can either be used to implement interaction with other COVISE modules (also called "feedback"), for example for steering a simulation module, or for extending the functionality of OpenCOVER as a VR viewer.

The plugin programmer needs to derive from the class coVRPlugin and reimplement some of its virtual methods as well as its constructor and destructor. These virtual methods are called at the appropriate times while OpenCOVER is running. This class has to be advertised to OpenCOVER with the macro COVERPLUGIN.

A simple skeleton for an OpenCOVER plugin is available in covise/src/template/plugin.

Background on Dynamic Libraries

In UNIX systems dlopen makes a dynamic library available to a running process. dlsym returns the address of a symbol in the dynamic library (returns a pointer to a function in the dynamic library), dlerror returns diagnostic information and dlclose closes the dynamic library. The class coVRDynLib encapsulates this in a platform independent way.

If OpenCOVER notices that it has to open a plugin it creates an instance of the class coVRPlugin. The class coVRPlugin handles a plugin in OpenCOVER. It has virtual methods which correspond to the functions in a plugin, e. g. preFrame, postFrame, addObject, addInteractor, removeObject, ... Then OpenCOVER opens the dynamic library with

      handle=dlopen(name, mode)

and extracts the function with the name coVRPluginInit with

      dlsym(handle, "coVRPluginInit")

which creates a new instance of coVRPlugin. All this is handled by the COVERPLUGIN macro.

During execution of OpenCOVER for each loaded plugin the methods are called at the appropriate time, e. g. coVRPlugin::preFrame is executed before OpenCOVER calls osgViewer::Viewer::frame and for each plugin coVRPlugin::postFrame is executed after.

OpenSceneGraph

OpenCOVER uses the scene graph library OpenSceneGraph. The plugin programmer should be familiar with the basic concepts of OpenSceneGraph such as the scene graph with its different types of nodes, the rendering loop and its main concepts. You can consult the OpenSceneGraph Quickstart Guide by Paul Martz (available as hardcopya or a free download from http://www.lulu.com/content/767629) and the OpenSceneGraph Doxygen documentation (available online at http://www.openscenegraph.org/projects/osg/wiki/Support/ReferenceGuides) for more information.

OpenCOVER can be configured to use multiple threads for rendering.

The scene graph of OpenCOVER which is relevant to the plugin programmer looks like this:

Figure: OpenCOVER scene graph
Scene_Graph.png
Figure: OpenCOVER scene graph


The matrix of handTransform comes from the 3D input device of the hand e. g. the Polhemus Stylus or the Ascension 6DOF Mouse. Under handTransform the interactor geometry for the hand is located. This is for e. g. laser sword or the magnifying glass. For the action "xform" the matrix of the handTransform is applied also to the objectXformTransform, for the action "scale" only the x component of the position is used to compute a scale matrix and is applied to the objectScaleTransform. COVISE geometry and other 3D geometry (in IV, OBJ etc. format) is appended under the group node cover->getObjectsRoot().

OpenCOVER as a COVISE module

As a COVISE module, OpenCOVER loads the COVISE plugin and uses the library coAppl for interfacing to COVISE. This library is similar to the newer coApi (which is used by non-renderer modules) and provides functions to open a socket connection to the controller and data manager and to create COVISE data objects. OpenCOVER can also be used stand-alone. Depending on the number of command line parameters the program decides if a connection to COVISE is needed.

As OpenSceneGraph has its own main loop, OpenCOVER checks for COVISE "ADD OBJECT" or "REMOVE OBJECT" messages from COVISE every frame. If it receives an object, OpenCOVER creates the appropriate OpenSceneGraph objects and appends them to the scene graph under the node cover->getObjectsRoot(). If feedback information was appended to the object (see [*]), OpenCOVER loads the appropriate plugin automatically.

Section [*] describes the methods your plugin can implement for interfacing with COVISE.

OpenCOVER as a VR viewer for 3D geometry

If OpenCOVER is started outside of COVISE, it interprets the argument as a file which should be loaded. If you want to load a plugin, this has to be specified in your COVISE configuration in the section COVER.Plugin. A minimal configuration file to enable OpenCOVER's Vrml97 plugin would look like this:

<?xml version="1.0"?>

<COCONFIG version="1" >
  <GLOBAL>
    <COVER>
      <Plugin>
        <Vrml97 value="on" />
      </Plugin>
    </COVER>
  </GLOBAL>
</COCONFIG>

The Plugin Interface

During execution OpenCOVER calls the functions provided by the plugin at certain points in the rendering loop. The functions are declared in cover/coVRPlugin.h.

None of these methods have to implemented, all are optional. However, you should make sure that all resources acquired by your plugin are released in its desctructor.

Plugin Life Cycle

The following methods are called during the different phases of the plugin life time.

coVRPlugin()
Description: The plugin is constructed when it is loaded. There are four methods to load a plugin:
  1. The plugin is specified in the configuration file. Then it is initialized in OpenCOVER before the main loop starts. In this case, the OpenCOVER scene graph is not yet fully initialized.
  2. OpenCOVER gets a COVISE object with had a coFeedback object applied.
  3. The user requests that a plugin be loaded from Tablet User Interface.
  4. A plugin starts another plugin.
The plugin constructor should be used to do early plugin initialization that does not depend on OpenCOVER data structures.

bool init()
Description: This method is called when the plugin is loaded and when OpenCOVER has completed start-up, all its data structures are established. This is the place where you can insert objects into the scene graph, add new menu entries, ...

bool destroy()
Description: This method is called to announce that OpenCOVER wants to remove your plugin. Reimplement it in order to do early clean-up work. Return false to prevent your module from being removed.

~coVRPlugin()
Description: This function is called before the plugin is removed from OpenCOVER.
It is important that you remove all your menu entries, remove your objects from the scene graph and release all resources acquired by your plugin.


COVISE Interface

The following functions deal with COVISE data objects. A plugin can be informed if OpenCOVER gets ADD_OBJECT or DELETE_OBJECT messages:

Within OpenCOVER all COVISE data objects, i. e. objects derived from coDistributedObject, are represented as RenderObjects. These are replicated between all nodes if OpenCOVER runs on a render cluster for e. g. a CAVE. All data and attributes are copied to the corresponding fields of the RenderObject.

void addObject(RenderObject *baseObj, RenderObject *geomObj,
RenderObject *normObj, RenderObject *colorObj, RenderObject *texObj,
const char *parentName,
int numCol, int colorBinding, int colorPacking, float *r, float *g, float *b, int *packedCol,
int numNormals, int normalBinding, float *xn, float *yn, float *zn, float transparency)
Description: If implemented, this function is called whenever OpenCOVER receives a COVISE object.
IN: baseObj The container object, i. e. the representation of the coDoSet object the newly added object is part of.
IN: geomObj The geometry container object consisting of a geometry object, a color object, a normal object and a texture object.
geomContainer is NULL if there is no container object but only a geometry object (e. g. polygons without colors)
IN: normObj The representation of the associated normals data.
IN: colorObj The representation of the associated colors data.
IN: texObj The representation of the associated texture data.
IN: parentName Name of the parent COVISE object, it is only set for set elements, for other data objects it is NULL.
IN: numCol Number of colors
IN: colorBinding Color binding type:
PER_PRIMITIVE, PER_FACE, PER_VERTEX, NONE
IN: colorPacking Non-zero if colors are packed colors instead of RGB values.
IN: r Red color values.
IN: g Green color values.
IN: b Blue color values.
IN: packedCol: Packed RGBA colors.
IN: numNormals Number of normals.
IN: normalBinding Normal binding type:
PER_PRIMITIVE, PER_FACE, PER_VERTEX, NONE
IN: xn List of normals x values.
IN: yn List of normal y values.
IN: zn List of normal z values.
IN: transparency Transparency value.

void removeObject(const char *objName, bool replace)
Description: If implemented, this function is called whenever OpenCOVER receives a DELETE_OBJECT message.
IN: objName The name of the COVISE object to delete.
IN: replace true, if the COVISE object is replaced (this happens if the user a module executes again), false if it really has to be deleted (this happens, if the user removes a module or the connection between the module and OpenCOVER).

void newInteractor(RenderObject *container, coInteractor *feedback)
Description: If implemented, this function is called whenever OpenCOVER receives a COVISE object with feedback information appended.
IN: container The geometry container object consisting of a geometry object, a color object, a normal object and a texture object.
container is NULL if there is no container object but only a geometry object (e. g. polygons without colors).
IN: feedback The class coInteractor handles feedback in OpenCOVER.

void coviseError(const char *errorMsg)
Description: If implemented, this function is called whenever OpenCOVER receives an error message. Error messages are created by modules with sendError. They are displayed in the Map Editor message window.
IN: errorMsg The COVISE error message.

Scene Graph Management

These functions are called when OpenCOVER appends or removes a node in the scene graph:

void addNode(osg::Node *node, RenderObject *obj)
Description: If implemented, this function is called when OpenCOVER adds a new COVISE object to the scenegraph or if other plugins insert a node into the scene graph.
IN: node A pointer to the scene graph node.
IN: obj A pointer to the RenderObject generated from the COVISE object,
NULL if not corresponding to a COVISE object

void removeNode(osg::Node *node)
Description: If implemented, this function is called if a node is removed from the scene graph.
IN: node A pointer to the scene graph node.

Render Loop

These functions are called at certain points during the execution of OpenCOVER.

void preFrame()
Description: If implemented, this function is called from the main thread immediately before osgViewer::Viewer::frame() is called.

void postFrame()
Description: If implemented, this function is called from the main thread immediately after osgViewer::Viewer::frame() was called.

void preSwapBuffers()
Description: This method is called by the draw thread immediately before GL swap buffers.

Other Events

All animations in OpenCOVER are synchronised. If a plugin needs to synchronise its interaction to the global animation, it should implement setTimestep to become informed whenever OpenCOVER displays another timestep.

void setTimestep(int timestep)
Description: If implemented, this function is called when OpenCOVER switches to a new timestep.
IN: timestep The number of the current timestep.

Plugins can be notified when the user presses keys on its keyboard.

void key(int type, int keySym, int modifiers)
Description: If implemented, this function is called when a key is pressed or released.
IN: type Type of event: osgGA::GUIEventAdapter::KEYDOWN or KEYUP.
IN: keySym The key symbol, see osgGA/GUIEventAdapter.
IN: modifiers The state of the Shift and other modifier keys, also see osgGA/GUIEventAdapter.

Plugins can send messages to each other, see [*].

void message(int type, int len, const void *buf)
Description: If implemented, this function is called when messages from other plugins arrive.
IN: type Integer representing the message type.
IN: len Message length.
IN: buf A pointer to the message.

Accessing OpenCOVER from a plugin

The class coVRPluginSupport gives the plugin programmer access to the OpenCOVER scene graph if he wants to add own geometry, or needs access to the menu to add new menu items, ... This class is a singleton, the static instance of coVRPluginSupport named cover is declared in cover/coVRPluginSupport.h.

Example:

   osg::Group *s = cover.getScene();


Access to the scene graph and its transformations

With the following methods you can access parts of the OpenCOVER scene graph (see Figure 12: OpenCOVER Scene Graph) or get/set transformations in the osg::MatrixTransform nodes.

osg::Group* getScene();
Description: Returns a pointer to the scene node
Return value: pointer to the scene node

osg::ClipNode* getObjectsRoot();
Description: Returns a pointer to the group node objectsRoot
Return value: pointer to the group node

osg::MatrixTransform * getPointer();
Description: Returns a pointer to the transform node for the hand which contains the transformation matrix of the 3D input device.
Return value: pointer to the transform node for the hand/pointer device

osg::MatrixTransform * getObjectsXform();
Description: Returns a pointer to the objectsXform node.
Return value: pointer to the transform node objectsXform

osg::MatrixTransform * getObjectsScale();
Description: Returns a pointer to the objectsXform node.
Return value: pointer to the transform node objectsXform

osg::Matrix &getBaseMat();
Description: transformation matrix from object coordinates to world coordinates
(objectScaleMat*objectsXformMat)
Return value: transformation matrix

osg::Matrix &getInvBaseMat();
Description: transformation from world coordinates to object coordinates
1 / (objectScaleMat*objectsXformMat)
use this cached value instead of computing it on your own
Return value: transformation matrix

osg::Matrix &getPointerMat();
Description: get matrix of handTransform
(same as getPointer()->getMatrix())
Return value: transformation matrix

osg::Matrix &getXformMat();
Description: get the matrix of objectsXform
(same as getObjectXforms()->getMatrix())
Return value: transformation matrix

void setXformMat(osg::Matrix &transformMatrix);
Description: set the matrix of objectsXform
(same as getObjectXform()->setMatrix())
IN: transformMatrix transformation matrix

float getScale();
Description: get the scale factor of the scale node, scale factor is the same for all directions
Return value: scale factor

void setScale(float s);
Description: set the scale factor of the matrix of the scale node
IN: s scale factor

float getSceneSize();
Description: get the scene size defined in covise.config
Return value: the scene size in [mm]


Access to the camera

You get the viewing matrix with:

osg::Matrix &getViewerMat();
Description: get the transformation matrix of the viewer. The matrix contains the position and orientation of the users head. If headtracking is on, the viewer matrix changes every frame.
Return value: transformation matrix


Loading 3D Geometry

The following methods simplify the loading of files into the plugin:

const char *getname(const char *file);
Description: get the full name for the file (with absolute path)
IN: file short file name
Return value: full name

osg::Node *loadFile(const char *file);
Description: load a file in any format supported by OpenSceneGraph or a VRML97 file
IN: file file name
Return value: the root node of the scene graph created for this file

void loadVRML(const char *url);
Description: Load the specified VRML file into the OpenSceneGraph scene graph and appends it under objectsRoot
IN: url url containing a vrml97 file

void reloadVRML();
Description: reload the previously loaded VRML file. If your VRML file is on a remote machine and you changed the model there you can update it in OpenCOVER by using this method

void removeVRML();
Description: removes the current VRML file from the scene

osg::Node *loadIcon(const char *filename);
Description: Load an icon file, similar to loadFile, but this method looks first in covise/icons/$LookAndFeel, then covise/icons
Return value: the root node of the scene graph created for this file , or NULL, if the file was not found


Access to the Buttons of the Input Device

coPointerButton *getButton();
Description: returns a pointer to a pointerButton object
Return value: class coPointerButton handles the button state


Interactions

A plugin needs to know if the input device is already used for another interaction or if it is free for own interaction. If a plugin uses the input device it has to announce this to other plugins and to OpenCOVER.


Load and Unload Other Plugins and Communicate with them

coVRPlugin *addPlugin(const char *name);
Description: Load a plugin
IN: name The name of the plugin. If the name of the shared object is libXxxPlugin.so, then the name is XxxPlugin
Return value: Object of type coVRPlugin. Class coVRPlugin represents a plugin.

int removePlugin(const char *name);
Description: Unload a plugin
IN: name The name of the plugin to be unloaded.
Return value: true, if successfully unloaded

void unload(coVRPlugin *plugin);
Description: Unload a plugin
IN: plugin The plugin object

void sendMessage(coVRPlugin *sender, int toWhom, int type, int len, const void *buf);
Description: send a message to other plugins
IN: sender the name of the plugin which sends the message
IN: toWhom destination types are:
TO_ALL,
TO_ALL_OTHERS,
TO_SAME,
TO_SAME_OTHERS,
NUM_TYPES
IN: type a user defined number. The sender can identify the message by means of that number. For messages sent to all plugins this should be unique.
IN: len length of the message
IN: buf the message

void sendMessage(coVRPlugin *sender, const char *destination, int type, int len, const void *buf);
Description: send a message to a plugin
IN: sender the name of the plugin which sends the message
IN: destination The name of the destination plugin
IN: type a user defined number. The sender can identify the message by means of that number. For messages sent to all plugins this should be unique.
IN: len length of the message
IN: buf the message

void addedNode(osg::Node *node, coVRPlugin *myPlugin);
Description: informs other plugins that this plugin extended the scene graph
IN: node pointer to the OpenSceneGraph node which was added
IN: myPlugin the plugin which added the node


Append Buttons to the Pinboard

The plugin programmer has full access to the Virtual Reality User Interface library (OpenVRUI), which is used by OpenCOVER to generate the pinboard and its submenus. With this library simple user interface elements like labels and icons and more complex elements like menu items can be created. The OpenVRUI header files are located in covise/src/OpenCOVER/OpenVRUI. A small example how to use the library is available in the Cube plugin source code under covise/src/OpenCOVER/plugins/examples/Cube.

Sometimes a plugin needs to create own menu items or submenus and needs to add them to the main pinboard. The method getMenu returns a pointer to the pinboard menu. The plugin Cube is a small example which create an own submenu and add it to the pinboard.

coMenu *getMenu();
Description: Get a pointer to the Pinboard.
Return Value: pointer to the pinboard menu



For compatibility with older COVISE Versions (< 5.0) the following functions for menu item generation are available:

void addToggleButton(const char *buttonName, const char *parentMenuName, int state, void *callback, void *classPtr, void *userData);
Description: append a switch button to a menu
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, codeNULL menas to append it to the main Pinboard
IN: state The state of the switch button, false=off, true=on
IN: callback function which is called on press/release
IN: classPtr ptr to the class which calls the callback
IN: userData ptr to data which are handed over to the callback

void addGroupButton(const char *buttonName, const char *parentMenuName, int state, void *callback, int groupId, void *classPtr, void *userData);
Description: append a switch button to a menu
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, NULL means to append it to the main Pinboard
IN: state The state of the switch button, false=off, true=on
IN: callback function which is called on press/release
IN: groupId if a button is in the same group with others it is automatically switched off if another button is pressed. The group id of the navigation functions in the main Pinboard is zero. To create a new group id, use the method uniqueButtonGroup
IN: classPtr ptr to the class which calls the callback
IN: userData ptr to data which are handed over to the callback

void addSubmenuButton(const char *buttonName, const char *parentMenuName, const char *subMenuName, int state, void *callback, int groupId, void *classPtr);
Description: append a switch button to a menu
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, NULL means to append it to the main Pinboard
IN: subMenuName name of the submenu which is also the header text of the submenu. Name has to be unique?
IN: state The state of the switch button, false=off, true=on
IN: callback function which is called on press/release
IN: groupId if a button is in the same group with others it is automatically switched off if another button is pressed. The group id of the navigation functions in the main Pinboard is zero. To create a new group id, use the method uniqueButtonGroup
IN: classPtr ptr to the class which calls the callback

void setButtonState(const char *buttonName, int state);
Description: set the state of a switch or submenu button
IN: buttonName the name of the button
IN: state The state of the button
switch button:
false=off, true=on
submenu:
false=closed, true=open

addFunctionButton(const char *buttonName, const char *parentMenuName, *callback, void *classPtr);
Description: add a function button, a function button just calls the callback when pressed
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, NULL means to append it to the main Pinboard
IN: callback function which is called on press/release
IN: classPtr ptr to the class which calls the callback

void addSliderButton(const char *buttonName, const char *parentMenuName,float min, float max, float value, void *callback, void *classPtr);
Description: add a slider to a menu
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, NULL means to append it to the main Pinboard
IN: min minimum slider value
IN: max maximum slider value
IN: value current slider value
IN: callback function which is if slider value changes
IN: classPtr ptr to the class which calls the callback

void setSliderValue(const char *buttonName, float value);
Description: set slider value
IN: buttonName the name of the button
IN: value current slider value

void removeButton(const char *buttonName, const char *parentMenuName);
Description: remove a button
parentMenuName=NULL: remove it from main menu
IN: buttonName the name of the button which is also the text on the button. Button names have to be unique.
IN: parentMenuName the name of the menu to which this button will be appended, NULL = append it to the main Pinboard

Use OpenCOVER built-in interaction without the Pinboard

A plugin programmer may want to user OpenCOVER interaction although the pinboard is not visible, for example if the plugin implements a custom menu, but wants to use the navigation functions like XFORM, or the plugin wants to set the state of a button without using the menu.In this case the corresponding function needs to be configured in the section COVERPinboard. The Pinboard can be visible or invisible.

OpenCOVER supports the following functionality (see the usersguide for details):

Navigation:

Part Manipulation:

View Options:

Collaborative Working:

Scene Graph:

COVISE:

Animation:

int isFunction(const char *functionName);
Description: Test if a function is configured and therefore in the pinboard
IN: functionName The name of the function, for example "XFORM"
Return value: true, if function is in pinboard

void setFunctionState(const char *functionName, int state);
Description: Set the state of a toggle, group, or submenu button and call the callback
IN: functionName The name of the function, for example "FREEZE"
IN: state true/false

void setFunctionValue(const char *functionName, float val);
Description: Set the value of a slider button and call the callback
IN: functionName The name of the function, for example "DRIVE_SPEED"
IN: value value between min and max

void doFunctionState(const char *functionName);
Description: Call the callback of a function button
IN: functionName The name of the function, for example "XFORM"

int getFunctionState(const char *functionName, int *state);
Description: Get the state of a toggle, group or submenu button
IN: functionName The name of the function, for example "FREEZE"
IN: state provide a pointer for getting the current state
Return value: true, if the function is in pinboard, false if not configured

int getFunctionValue(const char *functionName, float *value);
Description: Get the state of slider button
IN: functionName The name of the function, for example "DRIVE_SPEED"
IN: state provide a pointer for getting the current value
Return value: true, if the function is in pinboard, false if not configured


Controlling a COVISE module from within OpenCOVER

Module parameters are usually adjusted through the COVISE Map Editor or its Control Panel. If parameters should also be controllable from within OpenCOVER,

  1. the module has to append the parameter information to the data objects and
  2. OpenCOVER has to be extended by a plugin.

Class coFeedback

Feedback information is appended to data objects as attributes with a certain keyword. The class coFeedback handles the creation of such feedback-attributes:

In the constructor of coFeedback the name of the plugin has to be provided. When OpenCOVER receives this feedback information, it loads the appropriate plugin, if not already loaded (note that plugins can be loaded at starting time through the keyword MODULE in the section CoverConfig in the file covise.config).

coFeedback::coFeedback(const char *pluginName)
Description: Create a feedback object
IN: PluginName The name of the plugin which should be loaded by OpenCOVER

Parameters can now be added to such a feedback object with:

void coFeedback::addPara(coUifPara *parameter);
Description: add a parameter
IN: Parameter The parameter which should be steerable from within the plugin

In case that the module programmer needs to provide other information than parameters to the plugin he can use:

void coFeedback::addString(const char *userString);
Description: add a string
IN: UserString Any string which is needed by the plugin

The feedback object has to be applied to a COVISE data object. This data object can be one which is created by the module anyway or you can create a dummy output object, for example a single point and append it to this object.

void coFeedback:: apply(coDistributedObject *obj
Description: apply feedback object
IN: Obj The COVISE data object to which the feedback is appended

The feedback object can be deleted after it is appended:

coFeedback:: coFeedback(const char *pluginName)
Description: Delete a feedback object

Other functions

If an OpenCOVER plugin has the functions addObject and removeObject implemented, it is informed if OpenCOVER receives "ADD OBJECT" or "REMOVE OBJECT". If it has the function newInteractor implemented it is also informed, when the COVISE object has feedback attributes attached.

With the coFeedback::getXXX methods, the plugin can access the values of the module parameters, here one example for retreiving the values of a slider parameter:

void coInteractor::getFloatSliderParam(int paraNo, float - min, float - max, float - val);
Description: Get the values of a slider parameter
IN: paraNo The index of the parameter. The parameters are attached to the covise object with coFeedback::addPara(). paraNo is the index of the parameter in the list of the parameters which are added as feedback. it is not the parameter index in the module info window or the control panel.
IN: min The minimum value of the slider parameter
IN: max The maximum value of the slider parameter
IN: min The current value of the slider parameter

The plugin can set module parameters with the coInteractor::setXXX methods:

void coInteractor::setSliderParam(const char *name,float min,float max, float value);
Description: Set the values of a slider parameter
IN: name The parameter name. It needs to be exactly the name of the parameter of the module
IN: min The minimum value of the slider parameter
IN: max The maximum value of the slider parameter
IN: min The current value of the slider parameter

Please look at covise/src/OpenCOVER/cover/coInteractor.h for the methods to receive and set also boolean, scalar, vector, string and choice parameters.

With newInteractor, addObject and removeObject a plugin is informed about any object which is added to OpenCOVER or removed from OpenCOVER. There are a few functions which can be used to find out from which module the coInteractor comes from or for which plugin it is intended:

const char *coInteractor::getPluginName();
Description: Get the name of the plugin for which this coInteractor is intended
Return value: The name of the plugin.

const char *coInteractor::getModuleName();
Description: Get the name of the module from which this coInteractor is generated
Return value: The name of the module.

int coInteractor::getModuleInstance();
Description: Get the instance of the module from which this coInteractor is generated
Return value: The instance of the module.

A Plugin Programming Example

Have a look at the programming example in the directory covise/src/OpenCOVER/plugins/examples/Cube.

The plugin Cube implements interaction with the COVISE example module Cube. The Cube module generates a solid cube. The size and center of the cube can be manipulated through the module parameters.

The Cube plugin main class CubePlugin implements constructor and destructor and the virtual methods init, newInteractor, removeObject and preFrame. In init, OpenSceneGraph nodes are prepared to be added to the scene graph later. Through newInteractor the plugin can access the current value of the module parameters and the current cube COVISE object. In removeObject the plugin is informed, when an object is deleted. In preFrame direct manipulation of a wireframe cube is implemented. We need this additional representation of the cube for direct manipulation because we cannot manipulate the parameters of the Cube module in realtime (the communication between OpenCOVER and the module is not fast enough). As soon as the manipulation is finished, the current size and center of this wireframe cube is sent back to the module.

Module Example

(from covise/src/application/examples/Cube)

#include "coFeedback.h"

// the ports and parameters of the module
coOutputPort *p_polyOut;
coFloatVectorParam *p_center;
coFloatParam *p_cusize;
 
// in the compute callback we create an output object
polygonObj = new DO_Polygons(polygonObjName, 8, xCoords, yCoords, zCoords, 24, 
vertexList, 6, polygonList);
 
// interaction info for OpenCOVER
coFeedback feedback("CubePlugin");
feedback.addPara(p_center);
feedback.addPara(p_cusize);
feedback.addString("Test the user string as well");
feedback.apply(polygonObj);
 
// apply the object to the port
p_polyOut->setObj(polygonObj);

Utility Classes

The classes coIntersection and coAction

The classes coIntersection and coAction provide intersection testing of a node in your scene graph with the pointer ray.

virtual int coAction::hit(osg::Vec3 &hitPoint, osgUtil::Hit *hit)
Description: hit is called whenever the node or any node with this action is intersected
IN: hitPoint intersection point in world coordinates
IN: hit see man osgUtil::Hit
Return value: return ACTION_CALL_ON_MISS if you want miss to be called, otherwise return ACTION_DONE

virtual void coAction::miss()
Description: miss is called once after a hit if the node is not intersected any more
Return value: return ACTION_CALL_ON_MISS if you want miss to be called, otherwise return ACTION_DONE

Append the node which you want to have tested for intersection to the global intersection list:

void coIntersection::add(osg::Node *node, coAction *action)
Description: you can add a node to the global intersection list intersector
IN: node the node you want to have tested for intersection
IN: action your class which is derived from coAction and which contains the functions hit and miss

void coIntersection::remove(osg::Node *node)
Description: remove a node from the global intersection list intersector
IN: node the node you want to have tested for intersection




Example:

#include <coInteraction.h>
 
class myClass: public coAction
{
private:
   osg::MatrixTransform *transform;
 
public:
   myClass()
{
       //...
       intersector.add(transform, this);
       //...
};
   ~myClass()
{
       //...
       interscetor.remove(transform);
       //...
};
   virtual int hit(osg::Vec3 &hitPoint, osgUtil::Hit *hit)
{
       //...
       fprintf(stderr, "my transform was hit\n");
       return ACTION_CALL_ON_MISS;
};
 
   virtual void miss()
{
       //...
       fprintf(stderr, "my transform was missed\n");
};
}

OpenCOVER in a clustered environment



Martin Aumueller 2016-03-23