Commit c970c1a4 authored by Alexander Wiebel's avatar Alexander Wiebel
Browse files

[MERGE]

parents 56e4fa53 648a548c
......@@ -35,6 +35,7 @@ ADD_MODULE( schmahmannPandyaSlices )
ADD_MODULE( splineSurface )
ADD_MODULE( surfaceParameterAnimator )
ADD_MODULE( webglSupport )
ADD_MODULE( surfaceIllustrator )
IF( Teem_FOUND )
ADD_MODULE( teemGlyphs ${Teem_LIBRARIES} )
......
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#include <algorithm>
#include <list>
#include <limits>
#include <map>
#include <string>
#include <vector>
#include <osg/Geode>
#include <osg/LightModel>
#include "core/common/math/WMath.h"
#include "core/common/WLimits.h"
#include "core/graphicsEngine/shaders/WGEPropertyUniform.h"
#include "core/graphicsEngine/shaders/WGEShader.h"
#include "core/graphicsEngine/shaders/WGEShaderPropertyDefineOptions.h"
#include "core/graphicsEngine/WGEColormapping.h"
#include "core/graphicsEngine/WGEGeodeUtils.h"
#include "core/graphicsEngine/WGEManagedGroupNode.h"
#include "core/graphicsEngine/WGEUtils.h"
#include "core/graphicsEngine/WTriangleMesh.h"
#include "core/kernel/WKernel.h"
#include "WMSurfaceIllustrator.h"
#include "WMSurfaceIllustrator.xpm"
// This line is needed by the module loader to actually find your module.
W_LOADABLE_MODULE( WMSurfaceIllustrator )
WMSurfaceIllustrator::WMSurfaceIllustrator():
WModule()
{
}
WMSurfaceIllustrator::~WMSurfaceIllustrator()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMSurfaceIllustrator::factory() const
{
// See "src/modules/template/" for an extensively documented example.
return boost::shared_ptr< WModule >( new WMSurfaceIllustrator() );
}
const char** WMSurfaceIllustrator::getXPMIcon() const
{
return WMSurfaceIllustrator_xpm;
}
const std::string WMSurfaceIllustrator::getName() const
{
return "Surface Illustrator";
}
const std::string WMSurfaceIllustrator::getDescription() const
{
return "Takes a (parameterized) triangle mesh as input and renders it as a shaded surface with serverall illustration options.";
}
void WMSurfaceIllustrator::updateMinMax( double& minX, double& maxX, // NOLINT
double& minY, double& maxY, // NOLINT
double& minZ, double& maxZ, const osg::Vec3d& vector ) const // NOLINT
{
minX = std::min( minX, vector.x() );
minY = std::min( minY, vector.y() );
minZ = std::min( minZ, vector.z() );
maxX = std::max( maxX, vector.x() );
maxY = std::max( maxY, vector.y() );
maxZ = std::max( maxZ, vector.z() );
}
double WMSurfaceIllustrator::getMedian( double x, double y, double z ) const
{
if( ( y < x && z > x ) || ( z < x && y > x) )
{
return x;
}
if( ( x < y && z > y ) || ( x < y && z > y) )
{
return y;
}
if( ( y < z && x > z ) || ( x < z && y > z) )
{
return z;
}
if( x == y )
{
return x;
}
if( x == z )
{
return x;
}
if( y == z )
{
return z;
}
if( x == y && y == z && x == z)
{
return x;
}
return 0;
}
void WMSurfaceIllustrator::connectors()
{
// this input contains the triangle data
m_meshInput = WModuleInputData< WTriangleMesh >::createAndAdd( shared_from_this(), "mesh", "The mesh to display" );
// this input provides an additional map from vertex ID to color. This is especially useful for using the trimesh renderer in conjunction
// with clustering mechanisms and so on
m_colorMapInput = WModuleInputData< WColoredVertices >::createAndAdd( shared_from_this(), "colorMap", "The special colors" );
// call WModule's initialization
WModule::connectors();
}
void WMSurfaceIllustrator::properties()
{
m_nbTriangles = m_infoProperties->addProperty( "Triangles", "The number of triangles in the mesh.", 0 );
m_nbTriangles->setMax( std::numeric_limits< int >::max() );
m_nbVertices = m_infoProperties->addProperty( "Vertices", "The number of vertices in the mesh.", 0 );
m_nbVertices->setMax( std::numeric_limits< int >::max() );
// some properties need to trigger an update
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
// setup all the properties. See header file for their meaning and purpose.
m_showOutline = m_properties->addProperty( "Outline", "Show all edges of the trinagulation as lines.", false, m_propCondition );
m_coloringGroup = m_properties->addPropertyGroup( "Coloring", "Coloring options and colormap options." );
m_opacity = m_coloringGroup->addProperty( "Opacity %", "Opaqueness of surface.", 100.0 );
m_opacity->setMin( 0.0 );
m_opacity->setMax( 100.0 );
// Allow the user to select different colormodes
boost::shared_ptr< WItemSelection > colorModes( boost::shared_ptr< WItemSelection >( new WItemSelection() ) );
colorModes->addItem( "Single Color", "The whole surface is colored using the default color." );
colorModes->addItem( "From Mesh", "The surface is colored according to the mesh." );
colorModes->addItem( "From colormap connector", "The surface is colored using the colormap on colorMap connector." );
m_colorMode = m_coloringGroup->addProperty( "Color mode", "Choose one of the available colorings.", colorModes->getSelectorFirst(),
m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_colorMode );
// this is the color used if single color is selected
m_color = m_coloringGroup->addProperty( "Default color", "The color of of the surface.",
WColor( .9f, .9f, 0.9f, 1.0f ), m_propCondition );
m_colormap = m_coloringGroup->addProperty( "Enable colormapping", "Turn colormapping on", false );
m_parameterCenter = m_coloringGroup->addProperty( "Parameter center", "Parameter center selection", 0.5 );
m_parameterCenter->setMin( -1.0 );
m_parameterCenter->setMax( 1.0 );
m_parameterWidth = m_coloringGroup->addProperty( "Parameter width", "Parameter width selection", 0.1 );
m_parameterWidth->setMin( 0.0 );
m_parameterWidth->setMax( 2.0 );
// call WModule's initialization
WModule::properties();
}
void WMSurfaceIllustrator::moduleMain()
{
// let the main loop awake if the data changes.
m_moduleState.setResetable( true, true );
m_moduleState.add( m_meshInput->getDataChangedCondition() );
m_moduleState.add( m_colorMapInput->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
// signal ready state. The module is now ready to be used.
ready();
////////////////////////////////////////////////////////////////////////////////////////////////////
// setup the main graphics-node:
////////////////////////////////////////////////////////////////////////////////////////////////////
// create a OSG node, which will contain the triangle data and allows easy transformations:
m_moduleNode = new WGEManagedGroupNode( m_active );
osg::ref_ptr<osg::LightModel> lightModel( new osg::LightModel() );
osg::ref_ptr<osg::StateSet> moduleNodeState = m_moduleNode->getOrCreateStateSet();
lightModel->setTwoSided( true );
moduleNodeState->setAttributeAndModes( lightModel.get(), osg::StateAttribute::ON );
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->insert( m_moduleNode );
// load the GLSL shader:
m_shader = new WGEShader( "WMSurfaceIllustrator", m_localPath );
m_colorMapTransformation = new osg::Uniform( "u_colorMapTransformation", osg::Matrixd::identity() );
m_shader->addPreprocessor( WGEShaderPreprocessor::SPtr(
new WGEShaderPropertyDefineOptions< WPropBool >( m_colormap, "COLORMAPPING_DISABLED", "COLORMAPPING_ENABLED" ) )
);
// set the opacity and material color property as GLSL uniforms:
moduleNodeState->addUniform( new WGEPropertyUniform< WPropDouble >( "u_opacity", m_opacity ) );
// loop until the module container requests the module to quit
while( !m_shutdownFlag() )
{
// Now, the moduleState variable comes into play. The module can wait for the condition, which gets fired whenever the input receives data
// or an property changes. The main loop now waits until something happens.
debugLog() << "Waiting ...";
m_moduleState.wait();
// woke up since the module is requested to finish
if( m_shutdownFlag() )
{
break;
}
// Get data and check for invalid data.
boost::shared_ptr< WTriangleMesh > mesh = m_meshInput->getData();
if( !mesh )
{
debugLog() << "Invalid Data. Disabling.";
continue;
}
renderMesh( mesh );
}
// it is important to always remove the modules again
WKernel::getRunningKernel()->getGraphicsEngine()->getScene()->remove( m_moduleNode );
}
void WMSurfaceIllustrator::renderMesh( boost::shared_ptr< WTriangleMesh > mesh )
{
boost::shared_ptr< WColoredVertices > colorMap = m_colorMapInput->getData();
m_nbTriangles->set( mesh->triangleSize() );
m_nbVertices->set( mesh->vertSize() );
// prepare the geometry node
debugLog() << "Start rendering Mesh";
osg::ref_ptr< osg::Geometry > geometry;
osg::ref_ptr< osg::Geode > geode( new osg::Geode );
geode->getOrCreateStateSet()->addUniform( m_colorMapTransformation );
geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_parameterCenter", m_parameterCenter ) );
geode->getOrCreateStateSet()->addUniform( new WGEPropertyUniform< WPropDouble >( "u_parameterWidth", m_parameterWidth ) );
// apply shader only to mesh
m_shader->apply( geode );
// get the middle point of the mesh
std::vector< size_t >triangles = mesh->getTriangles();
std::vector< size_t >::const_iterator trianglesIterator;
double minX = wlimits::MAX_DOUBLE;
double minY = wlimits::MAX_DOUBLE;
double minZ = wlimits::MAX_DOUBLE;
double maxX = wlimits::MIN_DOUBLE;
double maxY = wlimits::MIN_DOUBLE;
double maxZ = wlimits::MIN_DOUBLE;
for( trianglesIterator = triangles.begin();
trianglesIterator != triangles.end();
trianglesIterator++ )
{
osg::Vec3d vectorX = mesh->getVertex( *trianglesIterator );
updateMinMax( minX, maxX, minY, maxY, minZ, maxZ, vectorX );
}
// start rendering
boost::shared_ptr< WProgress > progress = boost::shared_ptr< WProgress >( new WProgress( "Rendering", 3 ) );
m_progress->addSubProgress( progress );
++*progress;
// now create the mesh but handle the color mode properly
if( m_showOutline->get( true ) )
{
geometry = wge::convertToOsgGeometryLines( mesh, m_color->get(), false );
}
else
{
WItemSelector colorModeSelector = m_colorMode->get( true );
if( colorModeSelector.getItemIndexOfSelected( 0 ) == 0 )
{
// use single color
geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, false );
}
else if( colorModeSelector.getItemIndexOfSelected( 0 ) == 1 )
{
// take color from mesh
geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, true );
}
else
{
// take color from map
if( colorMap )
{
geometry = wge::convertToOsgGeometry( mesh, *colorMap, m_color->get(), true, true );
}
else
{
warnLog() << "External colormap not connected. Using default color.";
geometry = wge::convertToOsgGeometry( mesh, m_color->get(), true, true, false );
}
}
}
WGEColormapping::apply( geode, m_shader );
// done. Set the new drawable
geode->addDrawable( geometry );
m_moduleNode->clear();
m_moduleNode->insert( geode );
debugLog() << "Rendering Mesh done";
progress->finish();
}
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV-Leipzig and CNCF-CBS
// For more information see http://www.openwalnut.org/copying
//
// This file is part of OpenWalnut.
//
// OpenWalnut is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// OpenWalnut is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with OpenWalnut. If not, see <http://www.gnu.org/licenses/>.
//
//---------------------------------------------------------------------------
#ifndef WMSURFACEILLUSTRATOR_H
#define WMSURFACEILLUSTRATOR_H
#include <string>
#include <osg/Uniform>
#include "core/common/datastructures/WColoredVertices.h"
#include "core/common/math/linearAlgebra/WVectorFixed.h"
#include "core/kernel/WModule.h"
#include "core/kernel/WModuleInputData.h"
#include "core/kernel/WModuleOutputData.h"
class WTriangleMesh;
class WGEShader;
class WGEManagedGroupNode;
/**
* This module renders the triangle mesh given at its input connector
* as a surface.
*
* \ingroup modules
*/
class WMSurfaceIllustrator: public WModule
{
public:
/**
* Constructor. Creates the module skeleton.
*/
WMSurfaceIllustrator();
/**
* Destructor.
*/
virtual ~WMSurfaceIllustrator();
/**
* Gives back the name of this module.
* \return the module's name.
*/
virtual const std::string getName() const;
/**
* Gives back a description of this module.
* \return description to module.
*/
virtual const std::string getDescription() const;
/**
* Due to the prototype design pattern used to build modules, this method returns a new instance of this method. NOTE: it
* should never be initialized or modified in some other way. A simple new instance is required.
*
* \return the prototype used to create every module in OpenWalnut.
*/
virtual boost::shared_ptr< WModule > factory() const;
/**
* Get the icon for this module in XPM format.
* \return The icon.
*/
virtual const char** getXPMIcon() const;
protected:
/**
* Entry point after loading the module. Runs in separate thread.
*/
virtual void moduleMain();
/**
* Initialize the connectors this module is using.
*/
virtual void connectors();
/**
* Initialize the properties for this module.
*/
virtual void properties();
private:
/**
* Calculates the bounding box of a vector and increases the specified one if needed.
*
* \param minX old maximum X and gets overwritten by new one
* \param maxX old maximum Y and gets overwritten by new one
* \param minY old minimum Z and gets overwritten by new one
* \param maxY old maximum X and gets overwritten by new one
* \param minZ old maximum Y and gets overwritten by new one
* \param maxZ old maximum Z and gets overwritten by new one
* \param vector the new vector to include in bbox calculation.
*/
void updateMinMax( double& minX, double& maxX, double& minY, double& maxY, double& minZ, double& maxZ, const osg::Vec3d& vector ) const;
/**
* Gets the median of three values.
*
* \param x first value
* \param y second value
* \param z third value
*
* \return the median of x,y,z
*/
double getMedian( double x, double y, double z ) const;
/**
* Center of the mesh. Needed for applying transformation with the mesh in (0,0,0).
*/
WVector3d m_meshCenter;
/**
* Group for all color and colormapping options.
*/
WPropGroup m_coloringGroup;
/**
* Turn Colormapping on/off
*/
WPropBool m_colormap;
/**
* Set center of selected surface parameter
*/
WPropDouble m_parameterCenter;
/**
* Set width of selected surface parameter interval
*/
WPropDouble m_parameterWidth;
/**
* A condition used to notify about changes in several properties.
*/
boost::shared_ptr< WCondition > m_propCondition;
/**
* An input connector used to get meshes from other modules. The connection management between connectors must not be handled by the module.
*/
boost::shared_ptr< WModuleInputData< WTriangleMesh > > m_meshInput;
/**
* A map for mapping each vertex to a color.
*/
boost::shared_ptr< WModuleInputData< WColoredVertices > > m_colorMapInput;
/**
* A group wich contains all transformation tools.
*/
WPropGroup m_groupTransformation;
/**
* Set the transformation tool to default
*/
WPropTrigger m_setDefault;
/**
* Render the mesh
*
* \param mesh The mesh to be rendered.
*/
void renderMesh( boost::shared_ptr< WTriangleMesh > mesh );
/**
* OSG Uniform for the transformation matrix which transforms the mesh. Needed for the colormapper
*/
osg::ref_ptr< osg::Uniform > m_colorMapTransformation;
/**
* The mesh's opacity value.
*/
WPropDouble m_opacity;
/**
* Toggle showing outline instead fo surface.
*/
WPropBool m_showOutline;
/**
* The color of the mesh to be rendered.
*/
WPropColor m_color;
/**
* Which colormode should be used?
*/
WPropSelection m_colorMode;
WPropInt m_nbTriangles; //!< Info-property showing the number of triangles in the mesh.
WPropInt m_nbVertices; //!< Info-property showing the number of vertices in the mesh.
/**
* The node containing all geometry nodes.
*/
WGEManagedGroupNode::SPtr m_moduleNode;
/**
* The shader for the mesh
*/
osg::ref_ptr< WGEShader > m_shader;
};
#endif // WMSURFACEILLUSTRATOR_H
/* XPM */
static const char * WMSurfaceIllustrator_xpm[] = {
"32 32 3 1",
" c None",
". c #000000",
"+ c #FFFF00",
" ",
" .. ",
" ...... ..... ",
" .......... ......+.. ",
" .....+++.............++++.. ",
" ..+...++++++.....++++++++.. ",
" .+++..+++++++...++++++++.. ",
" .++++..++++++....+++++++.. ",
" ..++++...++++..+...+++++.. ",
" ..+++++...+++..++...++++.. ",
" ..+++++++..++..+++...+++.. ",
" .++++++++..++.+++++..++.. ",
" .+++++++++....++++++..+.. ",
" ..+++++++++...+++++++.... ",
" ......................... ",
" ........+++...++++....... ",
" ..+++++++++...+++++++.... ",
" ..++++++++....++++++..+.. ",
" .+++++++...++.+++++..++.. ",