void MeshFaceFilterOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands )
{
	ObjectPtr object = m_filterParameter->getValue();
	if( !object )
	{
		throw InvalidArgumentException( "MeshFaceFilterOp : Invalid filter input object." );
	}
	
	BoolVectorDataPtr filterData = runTimeCast<BoolVectorData>( object );
	if( !filterData )
	{
		throw InvalidArgumentException( "MeshFaceFilterOp : The filter input is not a BoolVectorData object." );
	}
	
	const std::vector<bool>& filter = filterData->readable();
	
	if( filter.size() != mesh->numFaces() )
	{
		throw InvalidArgumentException( "MeshFaceFilterOp : The filter must have one entry per mesh face." );
	}
	
	// find all verts/face verts touched by an active face:
	const std::vector<int>& verticesPerFace = mesh->verticesPerFace()->readable();
	const std::vector<int>& vertexIds = mesh->vertexIds()->readable();
	
	size_t numVerts = mesh->variableSize( PrimitiveVariable::Vertex );
	
	BoolVectorDataPtr activeVertsData = new BoolVectorData();
	BoolVectorDataPtr activeFaceVertsData = new BoolVectorData();
	
	std::vector<bool>& activeVerts = activeVertsData->writable();
	std::vector<bool>& activeFaceVerts = activeFaceVertsData->writable();
	
	activeVerts.resize( numVerts, false );
	activeFaceVerts.resize( vertexIds.size(), false );
	
	// why don't we work out the new topology while we're at it?
	IntVectorDataPtr newVerticesPerFaceData = new IntVectorData();
	IntVectorDataPtr newVertexIdsData = new IntVectorData();
	
	std::vector<int>& newVerticesPerFace = newVerticesPerFaceData->writable();
	std::vector<int>& newVertexIds = newVertexIdsData->writable();
	
	size_t vertNum( 0 );
	for( size_t face=0; face < mesh->numFaces(); ++face )
	{
		size_t polyNumVerts = verticesPerFace[face];
		if( filter[ face ] )
		{
			newVerticesPerFace.push_back( polyNumVerts );
			for( size_t j=0; j < polyNumVerts; ++j )
			{
				int vertId = vertexIds[ vertNum + j ];
				activeVerts[vertId] = true;
				activeFaceVerts[ vertNum + j ] = true;
				
				newVertexIds.push_back( vertId );
			}
		}
		vertNum += polyNumVerts;
	}
	
	// Right. So we've gotta chuck away the vertices that aren't touched any more which means resizing arrays and
	// randomly removing their elements. Lets find a mapping between the old arrays and the new ones:
	std::vector<int> vertMapping( activeVerts.size() );
	int idx = 0;
	for( size_t i=0; i < activeVerts.size(); ++i )
	{
		vertMapping[i] = idx;
		idx += int( activeVerts[i] );
	}
	
	// use this to remap the new vertex ids:
	for( size_t i=0; i < newVertexIds.size(); ++i )
	{
		newVertexIds[i] = vertMapping[ newVertexIds[i] ];
	}
	
	// decimate primvars:
	VectorDataFilterOpPtr filterOp = new VectorDataFilterOp();
	filterOp->copyParameter()->setTypedValue( false );
	
	// we keep track of all the primitive variables we've filtered so far, in case some of the
	// actual data buffers are duplicated:
	std::set< IECore::DataPtr > primvarsDone;
	
	for( IECore::PrimitiveVariableMap::iterator it = mesh->variables.begin(); it != mesh->variables.end(); ++it )
	{
		if( primvarsDone.find( it->second.data ) != primvarsDone.end() )
		{
			continue;
		}
		
		switch( it->second.interpolation )
		{
			case PrimitiveVariable::Constant :
				break; // nothing to do

			case PrimitiveVariable::Uniform :
				filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( filterData );
				filterOp->inputParameter()->setValue( it->second.data );
				filterOp->operate();
				break;

			case PrimitiveVariable::Vertex :
			case PrimitiveVariable::Varying:
				filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( activeVertsData );
				filterOp->inputParameter()->setValue( it->second.data );
				filterOp->operate();
				break;

			case PrimitiveVariable::FaceVarying:
				filterOp->parameters()->parameter<Parameter>( "filter" )->setValue( activeFaceVertsData );
				filterOp->inputParameter()->setValue( it->second.data );
				filterOp->operate();
				break;

			default :
				break;

		}
		
		primvarsDone.insert( it->second.data );
		
	}
	
	// set new topology:
	mesh->setTopology( newVerticesPerFaceData, newVertexIdsData, mesh->interpolation() );
}