Commit c01477a9 authored by Sebastian Eichelbaum's avatar Sebastian Eichelbaum

[ADD] - added some small WPropPosition example code

parent ea7852c1
......@@ -61,6 +61,7 @@
#include "../../kernel/WKernel.h"
#include "../../common/WColor.h"
#include "../../common/WPropertyHelper.h"
#include "../../graphicsEngine/WGEUtils.h"
#include "template.xpm"
#include "WMTemplate.h"
......@@ -191,6 +192,7 @@ void WMTemplate::properties()
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
m_aTrigger = m_properties->addProperty( "Do It Now!", "Trigger Button Text.", WPVBaseTypes::PV_TRIGGER_READY,
m_propCondition );
m_enableFeature = m_properties->addProperty( "Enable Feature", "Description.", true );
m_anInteger = m_properties->addProperty( "Number of Shape Rows", "Number of shape rows.", 10, m_propCondition );
m_anIntegerClone = m_properties->addProperty( "CLONE!Number of Shape Rows",
......@@ -199,6 +201,7 @@ void WMTemplate::properties()
m_aString = m_properties->addProperty( "A String", "Something.", std::string( "hello" ), m_propCondition );
m_aFile = m_properties->addProperty( "A Filenname", "Description.", WKernel::getAppPathObject(), m_propCondition );
m_aColor = m_properties->addProperty( "A Color", "Description.", WColor( 1.0, 0.0, 0.0, 1.0 ) );
m_aPosition = m_properties->addProperty( "Somewhere", "Description.", wmath::WPosition( 0.0, 0.0, 0.0 ) );
// These lines create some new properties and add them to the property list of this module. The specific type to create is determined by the
// initial value specified in the third argument. The first argument is the name of the property, which needs to be unique among all
......@@ -348,6 +351,20 @@ void WMTemplate::moduleMain()
ready();
debugLog() << "Module is now ready.";
// Most probably, your module will be a module providing some kind of visual output. In this case, the WGEManagedGroupNode is very handy.
// It allows you to insert several nodes and transform them as the WGEGroupNode (from which WGEManagedGroupNode is derived from) is also
// an osg::MatrixTransform. The transformation feature comes in handy if you want to transform your whole geometry according to a dataset
// coordinate system for example.
// But first, create the node and add it to the main scene. If you insert something into the scene, you HAVE TO remove it after your module
// has finished!
m_rootNode = new WGEGroupNode();
// Set a new callback for this node which basically transforms the geometry according to m_aPosition. Update callbacks are the thread safe
// way to manipulate an OSG node while it is inside the scene. This module contains several of these callbacks as an example. The one used
// here is to translate the root node coordinate system in space according to m_aPosition:
m_rootNode->addUpdateCallback( new TranslateCallback( this ) );
// Insert to the scene:
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
// Normally, you will have a loop which runs as long as the module should not shutdown. In this loop you can react on changing data on input
// connectors or on changed in your properties.
debugLog() << "Entering main loop";
......@@ -457,39 +474,37 @@ void WMTemplate::moduleMain()
// This block will be executed whenever we have a new dataset or the m_anInteger property has changed. This example codes produces
// some shapes and replaces the existing root node by a new (updated) one. Therefore, a new root node is needed:
osg::ref_ptr< osg::Geode > newRootNode = new osg::Geode();
osg::ref_ptr< osg::Geode > newGeode = new osg::Geode();
// When working with the OpenSceneGraph, always use ref_ptr to store pointers to OSG objects. This allows OpenSceneGraph to manage
// its resources automatically.
for ( int32_t i = 0; i < rows; ++i )
{
newRootNode->addDrawable(
newGeode->addDrawable(
new osg::ShapeDrawable( new osg::Box( osg::Vec3( 25, 128, i * 15 ), radii ) ) );
newRootNode->addDrawable(
newGeode->addDrawable(
new osg::ShapeDrawable( new osg::Sphere( osg::Vec3( 75, 128, i * 15 ), radii ) ) );
newRootNode->addDrawable(
newGeode->addDrawable(
new osg::ShapeDrawable( new osg::Cone( osg::Vec3( 125, 128, i * 15 ), radii, radii ) ) );
newRootNode->addDrawable(
newGeode->addDrawable(
new osg::ShapeDrawable( new osg::Cylinder( osg::Vec3( 175, 128, i * 15 ), radii, radii ) ) );
newRootNode->addDrawable(
newGeode->addDrawable(
new osg::ShapeDrawable( new osg::Capsule( osg::Vec3( 225, 128, i * 15 ), radii, radii ) ) );
}
// The old root node needs to be removed safely. The OpenSceneGraph traverses the graph at every frame. This traversion is done in a
// separate thread. Therefore, adding a Node directly may cause the OpenSceneGraph to crash. Thats why the Group node provided by
// getScene offers safe remove and insert methods. Use them to manipulate the scene node.
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
m_rootNode = newRootNode;
// please also ensure that, according to m_active, the node is active or not. Setting it here allows the user to deactivate modules
// in project files for example.
m_rootNode->setNodeMask( m_active->get() ? 0xFFFFFFFF : 0x0 );
// separate thread. Therefore, adding a node directly may cause the OpenSceneGraph to crash. Thats why the Group node (WGEGroupNode)
// offers safe remove and insert methods. Use them to manipulate the scene node.
// First remove the old node:
m_rootNode->remove( m_geode );
m_geode = newGeode;
// OSG allows you to add custom callbacks. These callbacks get executed on each update traversal. They can be used to modify several
// attributes and modes of existing nodes. You do not want to remove the node and recreate another one to simply change some color,
// right? Setting the color can be done in such an update callback. See in the header file, how this class is defined.
m_rootNode->addUpdateCallback( new SafeUpdateCallback( this ) );
m_geode->addUpdateCallback( new SafeUpdateCallback( this ) );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_rootNode );
// And insert the new node
m_rootNode->insert( m_geode );
}
// Now we updated the visualization after the dataset has changed. Your module might also calculate some other datasets basing on the
......@@ -581,8 +596,12 @@ void WMTemplate::moduleMain()
}
}
// At this point, the container managing this module signalled to shutdown. The main loop has ended and you should clean up. Always remove
// allocated memory and remove all OSG nodes.
// At this point, the container managing this module signalled to shutdown. The main loop has ended and you should clean up:
//
// * remove allocated memory
// * remove all OSG nodes
// * stop any pending threads you may have started earlier
// * ...
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_rootNode );
}
......@@ -604,6 +623,26 @@ void WMTemplate::SafeUpdateCallback::operator()( osg::Node* node, osg::NodeVisit
traverse( node, nv );
}
void WMTemplate::TranslateCallback::operator()( osg::Node* node, osg::NodeVisitor* nv )
{
// Update the transformation matrix according to m_aPosition if it has changed.
if ( m_module->m_aPosition->changed() || m_initialUpdate )
{
// The node to which this callback has been attached needs to be an osg::MatrixTransform:
osg::ref_ptr< osg::MatrixTransform > transform = static_cast< osg::MatrixTransform* >( node );
// Build a translation matrix (to comfortably convert between WPosition and osg::Vec3 use the convenience methods in "wge::" namespace)
osg::Matrixd translate = osg::Matrixd::translate( wge::osgVec3( m_module->m_aPosition->get( true ) ) );
// and set the translation matrix
transform->setMatrix( translate );
// First update done
m_initialUpdate = false;
}
traverse( node, nv );
}
bool WMTemplate::StringLength::accept( boost::shared_ptr< WPropertyVariable< WPVBaseTypes::PV_STRING > > /* property */,
WPVBaseTypes::PV_STRING value )
{
......
......@@ -32,6 +32,8 @@
#include "../../common/WItemSelection.h"
#include "../../common/WItemSelector.h"
#include "../../graphicsEngine/WGEGroupNode.h"
#include "../../kernel/WModule.h"
#include "../../kernel/WModuleInputData.h"
#include "../../kernel/WModuleOutputData.h"
......@@ -101,7 +103,12 @@ protected:
/**
* The root node used for this modules graphics. For OSG nodes, always use osg::ref_ptr to ensure proper resource management.
*/
osg::ref_ptr<osg::Geode> m_rootNode;
osg::ref_ptr< WGEGroupNode > m_rootNode;
/**
* The geometry rendered by this module.
*/
osg::ref_ptr< osg::Geode > m_geode;
/**
* Callback for m_active. Overwrite this in your modules to handle m_active changes separately.
......@@ -210,7 +217,7 @@ private:
/**
* A property simply providing a double value to the outside world.
*/
WPropDouble m_aDoubleOutput;
WPropDouble m_aDoubleOutput;
/**
* A property simply providing some text to the outside world.
......@@ -222,6 +229,11 @@ private:
*/
WPropColor m_aColorOutput;
/**
* A Property used to store some position.
*/
WPropPosition m_aPosition;
/**
* A Property used to show some filename to the user.
*/
......@@ -269,11 +281,54 @@ private:
/**
* Pointer used to access members of the module to modify the node.
* Please do not use shared_ptr here as this would prevent deletion of the module as the callback contains
* a reference to it. It is safe to use a simple pointer here as callback get deleted before the module.
*/
WMTemplate* m_module;
/**
* Denotes whether the update callback is called the first time. It is especially useful
* to set some initial value even if the property has not yet changed.
*/
bool m_initialUpdate;
};
/**
* Node callback to change the position of the shapes in the coordinate system of the scene.
* For more details on this class, refer to the documentation in moduleMain().
*/
class TranslateCallback : public osg::NodeCallback
{
public: // NOLINT
/**
* Constructor.
*
* \param module just set the creating module as pointer for later reference.
*/
explicit TranslateCallback( WMTemplate* module ): m_module( module ), m_initialUpdate( true )
{
};
/**
* operator () - called during the update traversal.
*
* \param node the osg node
* \param nv the node visitor
*/
virtual void operator()( osg::Node* node, osg::NodeVisitor* nv );
/**
* Pointer used to access members of the module to modify the node.
* Please do not use shared_ptr here as this would prevent deletion of the module as the callback contains
* a reference to it. It is safe to use a simple pointer here as callback get deleted before the module.
*/
WMTemplate* m_module;
/**
* Denotes whether the update callback is called the first time.
* Denotes whether the update callback is called the first time. It is especially useful
* to set some initial value even if the property has not yet changed.
*/
bool m_initialUpdate;
};
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment