void MixSmoothSkinningWeightsOp::modify( Object * object, const CompoundObject * operands )
{
	SmoothSkinningData *skinningData = static_cast<SmoothSkinningData *>( object );
	assert( skinningData );
	
	SmoothSkinningData *origMixingData = runTimeCast<SmoothSkinningData>( m_skinningDataParameter->getValidatedValue() );
	if ( !origMixingData )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix is not valid" );
	}
	
	assert( origMixingData );
	
	// make sure the number of influences matches
	if ( origMixingData->influenceNames()->readable().size() != skinningData->influenceNames()->readable().size() )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix and input have different numbers of influences" );
	}
	
	std::vector<float> &mixingWeights = m_mixingWeightsParameter->getTypedValue();
	
	// make sure there is one mixing weight per influence
	if ( mixingWeights.size() != skinningData->influenceNames()->readable().size() )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: There must be exactly one mixing weight per influence" );
	}
	
	// decompress both sets of skinning data
	DecompressSmoothSkinningDataOp decompressionOp;
	decompressionOp.inputParameter()->setValidatedValue( skinningData );
	decompressionOp.copyParameter()->setTypedValue( false );
	decompressionOp.operate();
	decompressionOp.inputParameter()->setValidatedValue( origMixingData );
	decompressionOp.copyParameter()->setTypedValue( true );
	decompressionOp.operate();
	const SmoothSkinningData *mixingData = runTimeCast<const SmoothSkinningData>( decompressionOp.resultParameter()->getValidatedValue() );
	if ( !mixingData )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix did not decompress correctly" );
	}
	
	// make sure everything matches except the weights
	if ( *(mixingData->pointIndexOffsets()) != *(skinningData->pointIndexOffsets()) )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix and input have different pointIndexOffsets when decompressed" );
	}
	if ( *(mixingData->pointInfluenceCounts()) != *(skinningData->pointInfluenceCounts()) )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix and input have different pointInfluenceCounts when decompressed" );
	}
	if ( *(mixingData->pointInfluenceIndices()) != *(skinningData->pointInfluenceIndices()) )
	{
		throw IECore::Exception( "MixSmoothSkinningWeightsOp: skinningDataToMix and input have different pointInfluenceIndices when decompressed" );
	}
	
	const std::vector<int> &inputIndexOffsets = skinningData->pointIndexOffsets()->readable();
	const std::vector<int> &inputInfluenceCounts = skinningData->pointInfluenceCounts()->readable();
	const std::vector<int> &inputInfluenceIndices = skinningData->pointInfluenceIndices()->readable();
	
	std::vector<float> &inputInfluenceWeights = skinningData->pointInfluenceWeights()->writable();
	const std::vector<float> &mixingInfluenceWeights = mixingData->pointInfluenceWeights()->readable();
	
	LinearInterpolator<float> lerp;
	
	// mix the weights
	for ( unsigned i=0; i < inputIndexOffsets.size(); i++ )
	{
		for ( int j=0; j < inputInfluenceCounts[i]; j++ )
		{
			int current = inputIndexOffsets[i] + j;
			
			lerp( mixingInfluenceWeights[current], inputInfluenceWeights[current], mixingWeights[ inputInfluenceIndices[current] ], inputInfluenceWeights[current] );
		}
	}
	
	// re-compress the input data
	CompressSmoothSkinningDataOp compressionOp;
	compressionOp.inputParameter()->setValidatedValue( skinningData );
	compressionOp.copyParameter()->setTypedValue( false );
	compressionOp.operate();
}