Example #1
0
IECore::CompoundDataPtr GXEvaluator::evaluate( const IECore::FloatVectorData *s, const IECore::FloatVectorData *t, const std::vector<std::string> &primVarNames ) const
{
	size_t numPoints = s->readable().size();
	if( t->readable().size() != numPoints )
	{
		throw InvalidArgumentException( "s and t must have the same length" );
	}
		
	buildSTEvaluator();
	
	MeshPrimitiveEvaluator::ResultPtr evaluatorResult = staticPointerCast<MeshPrimitiveEvaluator::Result>( m_stEvaluator->createResult() );
	IntVectorDataPtr fData = new IntVectorData;
	FloatVectorDataPtr uData = new FloatVectorData;
	FloatVectorDataPtr vData = new FloatVectorData;
	BoolVectorDataPtr statusData = new BoolVectorData;
	std::vector<int> &fWritable = fData->writable(); fWritable.resize( numPoints );
	std::vector<float> &uWritable = uData->writable(); uWritable.resize( numPoints );
	std::vector<float> &vWritable = vData->writable(); vWritable.resize( numPoints );
	std::vector<bool> &statusWritable = statusData->writable(); statusWritable.resize( numPoints );
	
	const std::vector<float> &sReadable = s->readable();
	const std::vector<float> &tReadable = t->readable();
	
	const PrimitiveVariable &uPrimVar = m_stEvaluator->primitive()->variables.find( "u" )->second;
	const PrimitiveVariable &vPrimVar = m_stEvaluator->primitive()->variables.find( "v" )->second;
	for( size_t i=0; i<numPoints; i++ )
	{
		bool success = m_stEvaluator->pointAtUV( Imath::V2f( sReadable[i], tReadable[i] ), evaluatorResult );
		// dividing by 2 maps from the triangle index to the original face index of the mesh before it
		// was triangulated - we can guarantee this because the original mesh was all quads.
		fWritable[i] = success ? evaluatorResult->triangleIndex() / 2 : 0;
		uWritable[i] = success ? evaluatorResult->floatPrimVar( uPrimVar ) : 0;
		vWritable[i] = success ? evaluatorResult->floatPrimVar( vPrimVar ) : 0;
		statusWritable[i] = success;
	}

	CompoundDataPtr result = evaluate( fData, uData, vData, primVarNames );
	result->writable()["gxStatus"] = statusData;
	
	return result;
}
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() );
}