Commit 039a6b75 authored by schurade's avatar schurade

[ADD] module that paints directly in the 3D scene

parent 1512f5e4
......@@ -10,6 +10,7 @@ ADD_SUBDIRECTORY( hud )
ADD_SUBDIRECTORY( isosurfaceRaytracer )
ADD_SUBDIRECTORY( lic )
ADD_SUBDIRECTORY( marchingCubes )
ADD_SUBDIRECTORY( paintTexture )
ADD_SUBDIRECTORY( superquadricGlyphs )
ADD_SUBDIRECTORY( template )
ADD_SUBDIRECTORY( triangleMeshRenderer )
......
FILE( GLOB_RECURSE MODULES_SRC "*.cpp" "*.h" )
# Grab module name and setup target directories
GET_FILENAME_COMPONENT( MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME )
SET( MODULE_TARGET_DIR ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/modules/${MODULE_NAME} )
SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${MODULE_TARGET_DIR} )
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MODULE_TARGET_DIR} )
SET( MODULE_DIRNAME ${MODULE_NAME} )
SET( MODULE_NAME "OWmodule_${MODULE_NAME}" ) # prefix all module names with "OWmodule_" to separate them from other libs
# Build module lib
ADD_LIBRARY( ${MODULE_NAME} SHARED ${MODULES_SRC} )
TARGET_LINK_LIBRARIES( ${MODULE_NAME} OWkernel )
# Copy local shaders to module target directory
IF( OW_COPY_SHADERS AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/shaders ) # copy shaders only if the user wants it
ADD_CUSTOM_TARGET( ${MODULE_NAME}_CopyShaders
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/shaders ${MODULE_TARGET_DIR}/shaders/
COMMENT "Copy shaders of ${MODULE_NAME}"
)
ADD_DEPENDENCIES( ${MODULE_NAME} ${MODULE_NAME}_CopyShaders )
ENDIF()
# Build unit tests
IF( OW_COMPILE_TESTS )
# This ensures that the test is copied to the module directory
SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${MODULE_TARGET_DIR} )
CXXTEST_ADD_TESTS_FROM_LIST( "${MODULES_SRC}"
"OWkernel;${MODULE_NAME}"
)
# Copy fixtures if they exist
IF( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/fixtures )
ADD_CUSTOM_TARGET( ${MODULE_NAME}_CopyFixtures
# as the "test" target runs in CMakes temporary build dir, the fixtures need to be placed there too.
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/test/fixtures ${CMAKE_BINARY_DIR}/modules/${MODULE_DIRNAME}/fixtures/
COMMENT "Copy fixtures of ${MODULE_NAME}"
)
ADD_DEPENDENCIES( ${MODULE_NAME} ${MODULE_NAME}_CopyFixtures )
ENDIF( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/test/fixtures )
ENDIF( OW_COMPILE_TESTS )
//---------------------------------------------------------------------------
//
// 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 <string>
#include <sstream>
#include <vector>
#include "../../kernel/WKernel.h"
#include "../../dataHandler/WDataHandler.h"
#include "../../dataHandler/WDataTexture3D.h"
#include "../../common/WPropertyHelper.h"
#include "paintTexture.xpm" // Please put a real icon here.
#include "WMPaintTexture.h"
// This line is needed by the module loader to actually find your module. Do not remove. Do NOT add a ";" here.
W_LOADABLE_MODULE( WMPaintTexture )
WMPaintTexture::WMPaintTexture():
WModule()
{
}
WMPaintTexture::~WMPaintTexture()
{
// Cleanup!
}
boost::shared_ptr< WModule > WMPaintTexture::factory() const
{
return boost::shared_ptr< WModule >( new WMPaintTexture() );
}
const char** WMPaintTexture::getXPMIcon() const
{
return paintTexture_xpm; // Please put a real icon here.
}
const std::string WMPaintTexture::getName() const
{
return "PaintTexture";
}
const std::string WMPaintTexture::getDescription() const
{
return "This module allows painting areas in a 3D texture";
}
void WMPaintTexture::connectors()
{
// the input dataset is just used as source for resolurtion and transformation matrix
m_input = boost::shared_ptr< WModuleInputData < WDataSetSingle > >(
new WModuleInputData< WDataSetSingle >( shared_from_this(), "in", "The input dataset." ) );
addConnector( m_input );
m_output = boost::shared_ptr< WModuleOutputData < WDataSetScalar > >(
new WModuleOutputData< WDataSetScalar >( shared_from_this(), "out", "The extracted image." ) );
addConnector( m_output );
WModule::connectors();
}
void WMPaintTexture::properties()
{
m_propCondition = boost::shared_ptr< WCondition >( new WCondition() );
m_painting = m_properties->addProperty( "Paint", "If active, left click in the scene with pressed ctrl key"
" will paint something.", false, m_propCondition );
m_pencilSelectionsList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_pencilSelectionsList->addItem( "1x1", "" );
m_pencilSelectionsList->addItem( "3x3", "" );
m_pencilSelectionsList->addItem( "5x5", "" );
m_pencilSelection = m_properties->addProperty( "Pencil", "Pencil type.", m_pencilSelectionsList->getSelectorFirst() );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_pencilSelection );
m_paintIndex = m_properties->addProperty( "Paint index", "Index we paint into the output texture", 1 );
m_paintIndex->setMin( 0 );
m_paintIndex->setMax( 255 );
// these are taken from WMData
m_interpolation = m_properties->addProperty( "Interpolation",
"If active, the boundaries of single voxels"
" will not be visible in colormaps. The transition between"
" them will be smooth by using interpolation then.",
false,
m_propCondition );
m_opacity = m_properties->addProperty( "Opacity %", "The opacity of this data in colormaps combining"
" values from several data sets.", 100, m_propCondition );
m_opacity->setMax( 100 );
m_opacity->setMin( 0 );
m_colorMapSelectionsList = boost::shared_ptr< WItemSelection >( new WItemSelection() );
m_colorMapSelectionsList->addItem( "Grayscale", "" );
m_colorMapSelectionsList->addItem( "Rainbow", "" );
m_colorMapSelectionsList->addItem( "Hot iron", "" );
m_colorMapSelectionsList->addItem( "Red-Yellow", "" );
m_colorMapSelectionsList->addItem( "Atlas", "" );
m_colorMapSelectionsList->addItem( "Blue-Green-Purple", "" );
m_colorMapSelection = m_properties->addProperty( "Colormap", "Colormap type.", m_colorMapSelectionsList->getSelector( 4 ), m_propCondition );
WPropertyHelper::PC_SELECTONLYONE::addTo( m_colorMapSelection );
m_queueAdded = m_properties->addProperty( "Something paint", "", false, m_propCondition );
m_queueAdded->setHidden();
}
void WMPaintTexture::moduleMain()
{
WKernel::getRunningKernel()->getGraphicsEngine()->getViewer()->getPickHandler()->getPickSignal()->connect(
boost::bind( &WMPaintTexture::queuePaint, this, _1 ) );
m_moduleState.setResetable( true, true );
m_moduleState.add( m_input->getDataChangedCondition() );
m_moduleState.add( m_propCondition );
ready();
while( !m_shutdownFlag() )
{
m_moduleState.wait();
if( m_shutdownFlag() )
{
break;
}
boost::shared_ptr< WDataSetSingle > newDataSet = m_input->getData();
bool dataChanged = ( m_dataSet != newDataSet );
bool dataValid = ( newDataSet );
if( dataValid )
{
if( dataChanged )
{
m_dataSet = newDataSet;
WAssert( m_dataSet, "" );
WAssert( m_dataSet->getValueSet(), "" );
if( m_outData )
{
WDataHandler::deregisterDataSet( m_outData );
}
m_outData = createNewOutTexture();
if( m_outData )
{
setOutputProps();
m_outData->setFileName( std::string( "painted" ) );
WDataHandler::registerDataSet( m_outData );
}
m_output->updateData( m_outData );
}
else
{
if( m_outData )
{
setOutputProps();
}
}
if ( m_painting->changed() )
{
if ( m_painting->get( true ) )
{
WKernel::getRunningKernel()->getSelectionManager()->setPaintMode( PAINTMODE_PAINT );
}
else
{
WKernel::getRunningKernel()->getSelectionManager()->setPaintMode( PAINTMODE_NONE );
}
}
}
else // case !dataValid
{
if( m_outData )
{
WDataHandler::deregisterDataSet( m_outData );
}
m_outData = boost::shared_ptr< WDataSetScalar >();
m_output->updateData( m_outData );
}
if ( m_queueAdded->changed() && m_queueAdded->get( true ) )
{
boost::shared_ptr< WDataSetScalar > old;
if( m_outData )
{
old = m_outData;
}
m_outData = doPaint();
WDataHandler::registerDataSet( m_outData );
WDataHandler::deregisterDataSet( old );
m_output->updateData( m_outData );
}
}
debugLog() << "Shutting down...";
if( m_outData )
{
WDataHandler::deregisterDataSet( m_outData );
}
debugLog() << "Finished! Good Bye!";
}
void WMPaintTexture::activate()
{
if( m_outData )
{
m_outData->getTexture()->setGloballyActive( m_active->get() );
}
WModule::activate();
}
void WMPaintTexture::setOutputProps()
{
if( m_outData )
{
m_outData->getTexture()->setThreshold( 0 );
m_outData->getTexture()->setOpacity( m_opacity->get() );
m_outData->getTexture()->setInterpolation( m_interpolation->get() );
m_outData->getTexture()->setSelectedColormap( m_colorMapSelection->get( true ).getItemIndexOfSelected( 0 ) );
}
}
boost::shared_ptr< WDataSetScalar > WMPaintTexture::createNewOutTexture()
{
WAssert( m_dataSet, "" );
WAssert( m_dataSet->getValueSet(), "" );
WAssert( m_dataSet->getGrid(), "" );
boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_dataSet->getGrid() );
WAssert( grid, "" );
m_values.resize( m_dataSet->getGrid()->size(), 0 );
m_values[0] = 255;
boost::shared_ptr< WValueSet< unsigned char > > vs =
boost::shared_ptr< WValueSet< unsigned char > >( new WValueSet< unsigned char >( 0, 1, m_values, W_DT_UINT8 ) );
return boost::shared_ptr< WDataSetScalar >( new WDataSetScalar( vs, grid ) );
}
boost::shared_ptr< WDataSetScalar > WMPaintTexture::doPaint()
{
boost::shared_ptr< WGridRegular3D > grid = boost::shared_dynamic_cast< WGridRegular3D >( m_outData->getGrid() );
while ( !m_paintQueue.empty() )
{
wmath::WPosition paintPosition = m_paintQueue.front();
m_paintQueue.pop();
int voxelNum = grid->getVoxelNum( paintPosition );
if ( voxelNum != -1 )
{
switch ( m_pencilSelection->get( true ).getItemIndexOfSelected( 0 ) )
{
case 0:
m_values[ voxelNum ] = m_paintIndex->get();
break;
case 1:
{
m_values[ voxelNum ] = m_paintIndex->get();
std::vector< size_t > ids = grid->getNeighbours( voxelNum );
for ( size_t i = 0; i < ids.size(); ++i )
{
m_values[ ids[i] ] = m_paintIndex->get();
}
break;
}
default:
break;
}
}
}
m_queueAdded->set( false );
boost::shared_ptr< WValueSet< unsigned char > > vs =
boost::shared_ptr< WValueSet< unsigned char > >( new WValueSet< unsigned char >( 0, 1, m_values, W_DT_UINT8 ) );
return boost::shared_ptr< WDataSetScalar >( new WDataSetScalar( vs, grid ) );
}
void WMPaintTexture::queuePaint( WPickInfo pickInfo )
{
if ( !m_painting->get() || ( pickInfo.getMouseButton() != WPickInfo::MOUSE_LEFT ) )
{
return;
}
m_paintQueue.push( pickInfo.getPickPosition() );
m_queueAdded->set( true );
}
//---------------------------------------------------------------------------
//
// 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 WMPAINTTEXTURE_H
#define WMPAINTTEXTURE_H
#include <queue>
#include <string>
#include <vector>
#include <osg/Geode>
#include "../../kernel/WModule.h"
#include "../../kernel/WModuleInputData.h"
#include "../../kernel/WModuleOutputData.h"
#include "../../dataHandler/WDataSetScalar.h"
#include "../../dataHandler/WValueSet.h"
/**
* Someone should add some documentation here.
* Probably the best person would be the module's
* creator, i.e. "schurade".
*
* This is only an empty template for a new module. For
* an example module containing many interesting concepts
* and extensive documentation have a look at "src/modules/template"
*
* \ingroup modules
*/
class WMPaintTexture: public WModule
{
public:
/**
*
*/
WMPaintTexture();
/**
*
*/
virtual ~WMPaintTexture();
/**
* 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.
*/
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();
/**
* Callback for m_active.
*/
virtual void activate();
private:
/**
* Write property values to output dataset.
*/
void setOutputProps();
/**
* this function listens to the pick handler, if the paint flag is true it will write into the out texture
*/
boost::shared_ptr< WDataSetScalar > doPaint();
/**
* this function listens to the pick handler, if the paint flag is true it will add the paint position to the
* paint queue
*
* \param pickInfo the pickInfo object fromt he current pick
*/
void queuePaint( WPickInfo pickInfo );
/**
* creates a new dataset scalar from the output field
* TODO (schurade): this is too slow and needs to be replaced by a direct texture generation from the field
*
* \return the new dataset
*/
boost::shared_ptr< WDataSetScalar > createNewOutTexture();
/**
* Interpolation?
*/
WPropBool m_painting;
/**
* A list of pencil sizes and shapes
*/
boost::shared_ptr< WItemSelection > m_pencilSelectionsList;
/**
* Selection property for pencil size and shape
*/
WPropSelection m_pencilSelection;
/**
* specifies the value we paint into the output texture
*/
WPropInt m_paintIndex;
// the following 5 members are taken from WMData
/**
* Interpolation?
*/
WPropBool m_interpolation;
/**
* A list of color map selection types
*/
boost::shared_ptr< WItemSelection > m_colorMapSelectionsList;
/**
* Selection property for color map
*/
WPropSelection m_colorMapSelection;
/**
* Opacity value for this data.
*/
WPropInt m_opacity;
/**
* true when a new paint coordinate is added to the queue
*/
WPropBool m_queueAdded;
/**
* field that stores the new values
*/
std::vector< unsigned char > m_values;
/**
* new paint coordinates get added here
*/
std::queue< wmath::WPosition >m_paintQueue;
/**
* An input connector that accepts order 1 datasets.
*/
boost::shared_ptr< WModuleInputData< WDataSetSingle > > m_input;
/**
* An output connector for the output scalar dsataset.
*/
boost::shared_ptr< WModuleOutputData< WDataSetScalar > > m_output;
/**
* This is a pointer to the dataset the module is currently working on.
*/
boost::shared_ptr< WDataSetSingle > m_dataSet;
/**
* Point to the out dataset once it is invalid. Used to deregister from the datahandler
*/
boost::shared_ptr< WDataSetScalar > m_outDataOld;
/**
* This is a pointer to the current output.
*/
boost::shared_ptr< WDataSetScalar > m_outData;
/**
* A condition used to notify about changes in several properties.
*/
boost::shared_ptr< WCondition > m_propCondition;
};
#endif // WMPAINTTEXTURE_H
/* XPM */
static const char * paintTexture_xpm[] = {
"32 32 248 2",
" c None",
". c #683908",
"+ c #673907",
"@ c #8C5214",
"# c #6E3E08",
"$ c #673A06",
"% c #9F580C",
"& c #6E3D07",