Commit 926372ea by Mathias Goldau

[REMOVE] Module fiberStipples, does not need CPU generated geometry for each…

[REMOVE] Module fiberStipples, does not need CPU generated geometry for each slice. Instead it uses now one time generated geometry modified by a linearTranslation Callback, which is damn fast.
parent dcc93f1e
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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 <cmath>
// #include <string>
// #include <vector>
//
// #include <osg/ref_ptr>
//
// #include "core/common/exceptions/WTypeMismatch.h"
// #include "core/common/WLogger.h"
// #include "core/dataHandler/WDataSetScalar.h"
// #include "core/dataHandler/WGridRegular3D.h"
// #include "core/graphicsEngine/WGEGroupNode.h"
// #include "WSPSliceBuilder.h"
//
// WSPSliceBuilder::WSPSliceBuilder( ProbTractList probTracts, WPropGroup sliceGroup, std::vector< WPropGroup > colorMap )
// : m_slicePos( 3 ),
// m_probTracts( probTracts ),
// m_sliceBB( 3 ),
// m_colorMap( colorMap ) // yes this is a COPY of the vector but WPropGroup is a boost::shared_ptr so updates will propagate!
// {
// m_slicePos[2] = sliceGroup->findProperty( "Axial Position" )->toPropDouble();
// m_slicePos[1] = sliceGroup->findProperty( "Coronal Position" )->toPropDouble();
// m_slicePos[0] = sliceGroup->findProperty( "Sagittal Position" )->toPropDouble();
//
// checkAndExtractGrids();
// computeSliceBB(); // just to be sure those are initialized, since they may change due to m_slicePos[0], et al. anyway
// }
//
// WSPSliceBuilder::~WSPSliceBuilder()
// {
// // since we are having virtual member functions we also need a virtual destructor
// }
//
// // helper functions only to be DRY
// namespace
// {
// /**
// * Try a cast to WGridRegular3D, and return the cast result if it was successful, otherwise throw an exception of
// * WTypeMismatched.
// *
// * \param dataset The dataset of which the grid is taken from to check.
// *
// * \return The grid of the dataset casted to WGridRegular3D.
// */
// boost::shared_ptr< const WGridRegular3D > ensureWGridRegular3D( boost::shared_ptr< const WDataSetScalar > dataset )
// {
// boost::shared_ptr< const WGridRegular3D > result = boost::shared_dynamic_cast< WGridRegular3D >( dataset->getGrid() );
// if( !result )
// {
// wlog::error( "WSPSliceBuilder" ) << "Cast to WGridRegular3D failed.";
// throw WTypeMismatch( "WSPSliceBuilder::extractGrid(): WGridRegular3D expected, but cast failed." );
// }
// return result;
// }
// }
//
// void WSPSliceBuilder::checkAndExtractGrids()
// {
// if( m_probTracts.empty() )
// {
// m_grid.reset();
// }
// else
// {
// try
// {
// m_grid = ensureWGridRegular3D( m_probTracts.front() );
//
// for( ProbTractList::const_iterator cit = m_probTracts.begin(); cit != m_probTracts.end(); ++cit )
// {
// boost::shared_ptr< const WGridRegular3D > grid = ensureWGridRegular3D( *cit );
// // TODO(math): ensure that each WGridRegular3D is the same once the operator== is available for WGridRegular3D
// // grid == m_grid
// }
// }
// catch( const WTypeMismatch& e )
// {
// wlog::error( "WSPSliceBuilder" ) << "At least one probabilistic tractogram has a grid which is not castable to WGridRegluar3D";
// throw e;
// }
// }
// }
//
// WColor WSPSliceBuilder::colorMap( size_t probTractNum ) const
// {
// std::string dataSetFileName = m_probTracts[probTractNum]->getFilename();
//
// for( size_t i = 0; i < m_colorMap.size(); ++i )
// {
// std::string colorMapFileName = m_colorMap[i]->findProperty( "Filename" )->toPropString()->get();
// if( colorMapFileName == dataSetFileName )
// {
// return m_colorMap[i]->findProperty( "Color" )->toPropColor()->get();
// }
// }
//
// // keep old behaviour
// return m_colorMap.at( probTractNum )->findProperty( "Color" )->toPropColor()->get();
// }
//
// bool WSPSliceBuilder::alphaBelowThreshold( const WColor& c, const double threshold ) const
// {
// return c[3] < threshold;
// }
//
// WColor WSPSliceBuilder::lookUpColor( const WPosition& pos, size_t tractID ) const
// {
// WColor c = colorMap( tractID );
// bool success = false;
// double probability = m_probTracts.at( tractID )->interpolate( pos, &success );
// if( m_probTracts.at( tractID )->getMax() > 1 )
// {
// probability /= static_cast< double >( m_probTracts.at( tractID )->getMax() );
// }
// if( c[3] != 0.0 )
// {
// // linear mapping
// c[3] = ( success ? probability : -1.0 );
//
// // // sinusiodal mapping
// // double pi2 = 2*3.14159265358979323846;
// // c[3] = ( success ? ( pi2*probability - std::sin(pi2*probability) ) / ( pi2 ) : -1.0 );
//
// // // square root mapping
// // c[3] = ( success ? std::sqrt( probability ) : -1.0 );
// }
//
// return c;
// }
//
// osg::ref_ptr< osg::Vec4Array > WSPSliceBuilder::computeColorsFor( const osg::Vec3& pos ) const
// {
// osg::ref_ptr< osg::Vec4Array > result( new osg::Vec4Array );
// result->reserve( m_probTracts.size() );
//
// // for each probabilisitc tractogram look up if its probability at this vertex is below a certain threshold or not
// for( size_t tractID = 0; tractID < m_probTracts.size(); ++tractID )
// {
// WColor c = lookUpColor( WPosition( pos ), tractID );
// if( c[3] != -1.0 )
// {
// result->push_back( c );
// }
// }
//
// return result;
// }
//
// void WSPSliceBuilder::computeSliceBB()
// {
// if( !m_grid )
// {
// wlog::warn( "WSPSliceBuilder" ) << "Invalid grid while BB computation!";
// return;
// }
// m_sliceBB[0] = WBoundingBox( m_grid->getOrigin() + m_slicePos[0]->get() * m_grid->getDirectionX(),
// m_grid->getOrigin() + m_slicePos[0]->get() * m_grid->getDirectionX() + m_grid->getNbCoordsY() * m_grid->getDirectionY() +
// m_grid->getNbCoordsZ() * m_grid->getDirectionZ() );
// m_sliceBB[1] = WBoundingBox( m_grid->getOrigin() + m_slicePos[1]->get() * m_grid->getDirectionY(),
// m_grid->getOrigin() + m_slicePos[1]->get() * m_grid->getDirectionY() + m_grid->getNbCoordsX() * m_grid->getDirectionX() +
// m_grid->getNbCoordsZ() * m_grid->getDirectionZ() );
// m_sliceBB[2] = WBoundingBox( m_grid->getOrigin() + m_slicePos[2]->get() * m_grid->getDirectionZ(),
// m_grid->getOrigin() + m_slicePos[2]->get() * m_grid->getDirectionZ() + m_grid->getNbCoordsY() * m_grid->getDirectionY() +
// m_grid->getNbCoordsX() * m_grid->getDirectionX() );
// }
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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 WSPSLICEBUILDER_H
#define WSPSLICEBUILDER_H
// #include <vector>
//
// #include <boost/shared_ptr.hpp>
//
// #include <osg/ref_ptr>
//
// #include "core/common/WBoundingBox.h"
// #include "core/common/WProperties.h"
// #include "core/common/WPropertyTypes.h"
//
// // forward declarations
// class WDataSetScalar;
// class WGEGroupNode;
// template< typename T >
// class WGridRegular3DTemplate;
//
// /**
// * This Builder is used to generate views of probabilistic tractograms ala Schmahmann and Pandya.
// */
// class WSPSliceBuilder
// {
// public:
// /**
// * Vector of scalar datasets e.g. probabilistic tractograms.
// */
// typedef std::vector< boost::shared_ptr< const WDataSetScalar > > ProbTractList;
//
// /**
// * Creates a geode builder to build axial, coronal and sagittal slices ala Schahmann y Pandya.
// *
// * \param probTracts The vector of probabilistic tractograms which should be taken into account.
// * \param sliceGroup Slice positions
// * \param colorMap For each connected probabilistic trac its color
// */
// WSPSliceBuilder( ProbTractList probTracts, WPropGroup sliceGroup, std::vector< WPropGroup > colorMap );
//
// /**
// * Destructs this. We need a virtual desturctor as long as we have virtual member functions...
// */
// virtual ~WSPSliceBuilder();
//
// /**
// * Do some preprocessing which is needed for every slice redraw, e.g. when the slice has moved.
// */
// virtual void preprocess() = 0;
//
// /**
// * This generates for each axis a group node with some geodes.
// *
// * \param sliceNum 0 == xSlice, 1 ySlice, 2 zSlice.
// *
// * \return The group of nodes for the given slice.
// */
// virtual osg::ref_ptr< WGEGroupNode > generateSlice( const unsigned char sliceNum ) const = 0;
//
// protected:
// /**
// * Very simple color mapping which is used temporarily, later we want to substitute this with a color chooser as properties.
// *
// * \param probTractNum Index of the probabilisitc tractrogram to get the color for.
// *
// * \return The color for the given prob tract index.
// */
// WColor colorMap( size_t probTractNum ) const;
//
// /**
// * Compares the color's alpha value and the threshold.
// *
// * \param c The given color
// * \param threshold The given Threshold
// *
// * \return ture if the color has an alpha value below the given threshold.
// */
// bool alphaBelowThreshold( const WColor& c, const double threshold ) const;
//
// /**
// * For a certain tractogram the color is looked up in the color map and the alpha value is set to the interpolated
// * probability value.
// *
// * \param pos The position to look up the color and probability.
// * \param tractID For which tract the color should be looked up
// *
// * \return The color of the tract, where the alpha value is either the interpolated tract probability or -1.0 if interpolation has failed.
// */
// WColor lookUpColor( const WPosition& pos, size_t tractID ) const;
//
// /**
// * Compute for each probabilistic tractogram the color at the given pos and sets the alpha value to the interpolated probability.
// *
// * \param pos The position to look up colors and probabilities for.
// *
// * \return The vector of colors.
// */
// osg::ref_ptr< osg::Vec4Array > computeColorsFor( const osg::Vec3& pos ) const;
//
// /**
// * Computes the bouding boxes for the slices.
// *
// * \note Whenever the xPos, yPos or zPos of the slice change those have to be recomputed!
// */
// void computeSliceBB();
//
// /**
// * The grid of the first tractogram. It is assumed that all given probablilisitc tractograms operate on the same grid.
// */
// boost::shared_ptr< const WGridRegular3DTemplate< double > > m_grid;
//
// /**
// * Hold the current position of each slice given from the properties
// */
// std::vector< boost::shared_ptr< const WPVDouble > > m_slicePos;
//
// /**
// * List of probabilisitc tractograms.
// */
// ProbTractList m_probTracts;
//
// /**
// * Axis aligned bounding box for each slice.
// */
// std::vector< WBoundingBox > m_sliceBB;
//
// private:
// /**
// * Ensures that every grid of each probabilistic tractogram is of type WGridRegular3D and that they are all the same.
// *
// * \todo Check that each grid is the same as soon as operator== for WGridRegular3D is available
// * \throw WTypeMismatched when a grid was found which is not castable to WGridRegular3D
// */
// void checkAndExtractGrids();
//
// /**
// * Reference to the color properites.
// */
// std::vector< WPropGroup > m_colorMap;
// };
//
#endif // WSPSLICEBUILDER_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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 WSPSLICEBUILDERTRACTS_H
#define WSPSLICEBUILDERTRACTS_H
// #include <list>
// #include <utility>
// #include <vector>
//
// #include <boost/shared_ptr.hpp>
//
// #include <osg/Geode>
//
// #include "core/common/WBoundingBox.h"
// #include "core/common/WProperties.h"
// #include "core/common/WPropertyTypes.h"
// #include "WSPSliceBuilder.h"
//
// class WDataSetFibers;
//
// /**
// * This Builder is used to generate views of probabilistic tractograms ala Schmahmann and Pandya. After creating a builder instance
// * you must calculate the intersections (with preprocess) again and again whenever a slice has moved.
// */
// class WSPSliceBuilderTracts : public WSPSliceBuilder
// {
// public:
// /**
// * Creates a geode builder to build axial, coronal and sagittal slices ala Schahmann y Pandya. After this initialization,
// * the user needs still to call the \ref preprocess() member function in order to get right results.
// *
// * \param probTracts The list of probabilistic tractograms which should be taken into account.
// * \param sliceGroup Slice positions
// * \param colorMap For each connected probabilistic trac its color
// * \param detTracts The deterministic fibers which are used to show the probabilistic tracts.
// * \param tractGroup The properties for visualization for the deterministic tract method
// */
// WSPSliceBuilderTracts( ProbTractList probTracts, WPropGroup sliceGroup, std::vector< WPropGroup > colorMap,
// boost::shared_ptr< const WDataSetFibers > detTracts, WPropGroup tractGroup );
//
// /**
// * Implements the preprocessing interface \ref WSPSliceBuilder.
// * For each slice compute the deterministic trac indices which are intersecting with it.
// */
// void preprocess();
//
// /**
// * Implements the generateSlice interface \ref WSPSliceBuilder.
// * Creates some geodes for the given slice which depicts a limited envirnonment of its intersecting fibers and a geode
// * for those projected onto that slice.
// *
// * \param sliceNum 0 denotes xSlice, 1 ySlice and finally 2 means zSlice.
// *
// * \return A group node with the cutted intersecting fibers and projected onto the slice.
// */
// osg::ref_ptr< WGEGroupNode > generateSlice( const unsigned char sliceNum ) const;
//
// protected:
// private:
// /**
// * Projects a given line strip onto the given slice simply by setting its components to the slice position.
// *
// * \param sliceNum Which slice 0 == xSlice, 1 == ySlice and 2 == zSlice
// * \param vertices Verices of the tract which needs to be transformed/projected.
// * \param slicePos The position of the slice.
// *
// * \note After calling this funtion the given vertices are lost!
// */
// void projectTractOnSlice( const unsigned char sliceNum, osg::ref_ptr< osg::Vec3Array > vertices, const int slicePos ) const;
//
// /**
// * Color each vertex accordingly to all given probabilistic tractograms. For each vertex all probTracts are considered in the following manner:
// * - first check if the tract contribute, and if so, set alpha value to probability
// * - the resulting color is then computed by summing all contributing colors but divide them by the number of contributing colors, so each
// * prob tract contributes the same amount but with different alpha value.
// *
// * \param vertices The vertices to compute the colors for
// *
// * \return An array of colors for the given vertices.
// */
// osg::ref_ptr< osg::Vec4Array > colorVertices( osg::ref_ptr< const osg::Vec3Array > vertices ) const;
//
//
// /**
// * Reference to the deterministic tracts.
// */
// boost::shared_ptr< const WDataSetFibers > m_detTracts;
//
// /**
// * Lists of deterministic tract indices which are intersecting each slice.
// */
// std::vector< std::list< size_t > > m_intersectionList;
//
// /**
// * For each deterministic tract its precomputed axis aligned bounding box.
// */
// std::vector< WBoundingBox > m_tractBB;
//
// /**
// * The distance at which the lines are cut off, and only their parts inside the so defined environment are projected onto the slices.
// */
// boost::shared_ptr< const WPVDouble > m_maxDistance;
//
// /**
// * Up to this propbability the probabilities of the probabilisitic tractogram do NOT contribute.
// */
// boost::shared_ptr< const WPVDouble > m_probThreshold;
//
// /**
// * Forwarded flag which denotes if the node corresponding to the intersections stipples should be visible or not.
// */
// WPropBool m_showIntersections;
//
// /**
// * Forwarded flag which denotes if the node corresponding to the projections stipples should be visible or not.
// */
// WPropBool m_showProjections;
// };
//
#endif // WSPSLICEBUILDERTRACTS_H
//---------------------------------------------------------------------------
//
// Project: OpenWalnut ( http://www.openwalnut.org )
//
// Copyright 2009 OpenWalnut Community, BSV@Uni-Leipzig and CNCF@MPI-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 WSPSLICEBUILDERVECTORS_H
#define WSPSLICEBUILDERVECTORS_H
// #include <utility>
// #include <vector>
//
// #include <boost/filesystem/path.hpp>
// #include <boost/shared_ptr.hpp>
//
// #include <osg/Geode>
//
// #include "core/common/WProperties.h"
// #include "core/common/WPropertyTypes.h"
// #include "core/graphicsEngine/shaders/WGEShader.h"
// #include "WSPSliceBuilder.h"
//
// // forward declarations
// class WDataSetVector;
//
// /**
// * This Builder is used to generate views of probabilistic tractograms ala Schmahmann and Pandya.
// */
// class WSPSliceBuilderVectors : public WSPSliceBuilder
// {
// public:
// /**
// * Creates a geode builder to build axial, coronal and sagittal slices ala Schahmann y Pandya.
// *
// * \param probTracts The list of probabilistic tractograms which should be taken into account.
// * \param sliceGroup Slice positions
// * \param colorMap For each connected probabilistic trac its color
// * \param vector Vector dataset with the largest eigen vectors.
// * \param vectorGroup Properties for some parameters of this drawing method
// * \param shaderPath The filesystem path where the shader file is located.
// */
// WSPSliceBuilderVectors( ProbTractList probTracts, WPropGroup sliceGroup, std::vector< WPropGroup > colorMap,
// boost::shared_ptr< const WDataSetVector > vector, WPropGroup vectorGroup, boost::filesystem::path shaderPath );
//
// /**
// * Implements the preprocessing interface \ref WSPSliceBuilder.
// */
// void preprocess();
//
// /**
// * Implements the generateSlice interface \ref WSPSliceBuilder.
// * This generates for each axis a group node with some geodes.
// *
// * \param sliceNum 0 == xSlice, 1 ySlice, 2 zSlice.
// *
// * \return The group of nodes for the given slice.
// */
// osg::ref_ptr< WGEGroupNode > generateSlice( const unsigned char sliceNum ) const;
//
// private:
// // osg::ref_ptr< osg::Vec3Array > generateQuadStubs( const WPosition& pos ) const;
//
// /**
// * Computes four vertices so each describe the translation of the middle point to one of the four quad corners.
// *
// * \param activeDims This are the opposite indices of the current slice.
// *
// * \return All four coordinate transformations, for each vertex in a slice.
// */
// osg::ref_ptr< osg::Vec3Array > generateQuadSpanning( std::pair< unsigned char, unsigned char > activeDims ) const;
//
// /**
// * Generates directions clockwise around a center where the other quads will be placed later on.
// *
// * \param activeDims This are the opposite indices of the current slice.
// * \param distance How far the other quads are placed around the center point
// *
// * \return A array of direction to add to the center point to get the new centerpoints around in clockwise manner.
// */
// boost::shared_ptr< std::vector< WVector3d > > generateClockwiseDir( std::pair< unsigned char, unsigned char > activeDims, double distance ) const;
//
// /**
// * Compute the origin and the base vectors of each slice, and returns the other opposite indices.
// *
// * \param sliceNum The current slice index: 0 sagittal (xSlice), 1 coronal (ySlice), 2 axial (zSlice)
// * \param origin There will be put the origin of the given slice
// * \param a The first base vector of the given slice
// * \param b The second base vector of the given slice
// *
// * \return If \c sliceNum=0 the oppsite indices are \c 1 and \c 2. For \c sliceNum=1, they are \c 0,2, and for \c sliceNum=2 they are \c 1,2.
// */
// std::pair< unsigned char, unsigned char > computeSliceBase( const unsigned char sliceNum, boost::shared_ptr< WVector3d > origin,
// boost::shared_ptr< WVector3d > a, boost::shared_ptr< WVector3d > b ) const;
//
// /**
// * Compute the focal points for ellipsoid generation within the fragment shader. Basically this are just the start and end points of
// * the principal diffusion direction, e.g. the interpolated vector at that given point projected onto the current slice.
// *
// * \param pos Where the interpolation should start
// * \param sliceNum Which slice to project on
// *
// * \return The foci describing the ellipsoid.
// */
// std::pair< WPosition, WPosition > computeFocalPoints( const WPosition& pos, size_t sliceNum ) const;
//
// /**
// * The eigenvectors.
// */
// boost::shared_ptr< const WDataSetVector > m_vectors;
//
// /**
// * A reference to the property which denotes the space between the primary quads (aka subdivision) as well as the size of the cell borders.
// */
// WPropDouble m_spacing; // we cannot make const here since we need the WPropType for the WGEPropertyUniform creation
//
// /**
// * Upto which threshold the quads should be discarded.
// */
// boost::shared_ptr< const WPVDouble > m_probThreshold;
//
// /**
// * Spacing between the glyphs around the grid points.
// */
// boost::shared_ptr< const WPVDouble > m_glyphSpacing;
//
// /**
// * Thickness of the line used to draw the glyph.
// */
// WPropDouble m_glyphThickness;
//
// /**
// * Flag to show or hide the slice grid of current resolution.
// */
// WPropBool m_showGrid;
//
// /**
// * Shading the quads and transform them to the glyphs (line stipples).
// */
// osg::ref_ptr< WGEShader > m_shader;
// };
#endif // WSPSLICEBUILDERVECTORS_H
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