Beispiel #1
0
void Grade::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const
{
	// Calculate the valid data window that we are to merge.
	const int dataWidth = ImagePlug::tileSize()*ImagePlug::tileSize();

	// Do some pre-processing.
	float A, B, gamma;
	bool whiteClamp, blackClamp;
	{
		GradeParametersScope s( context );	
		parameters( std::max( 0, ImageAlgo::colorIndex( channel ) ), A, B, gamma );
		whiteClamp = whiteClampPlug()->getValue();
		blackClamp = blackClampPlug()->getValue();
	}
	const float invGamma = 1. / gamma;

	// Get some useful pointers.
	float *outPtr = &(outData->writable()[0]);
	const float *END = outPtr + dataWidth;

	while (outPtr != END)
	{
		// Calculate the colour of the graded pixel.
		float colour = *outPtr;	// As the input has been copied to outData, grab the input colour from there.
		const float c = A * colour + B;
		colour = ( c >= 0.f && invGamma != 1.f ? (float)pow( c, invGamma ) : c );

		// Clamp the white and blacks if necessary.
		if ( blackClamp && colour < 0.f ) colour = 0.f;
		if ( whiteClamp && colour > 1.f ) colour = 1.f;

		// Write back the result.
		*outPtr++ = colour;
	}
}
Beispiel #2
0
IECore::ImagePrimitivePtr ImagePlug::image() const
{
	Format format = formatPlug()->getValue();
	Box2i dataWindow = dataWindowPlug()->getValue();
	Box2i newDataWindow( Imath::V2i(0) );

	if( dataWindow.isEmpty() )
	{
		dataWindow = Box2i( Imath::V2i(0) );
	}
	else
	{
		newDataWindow = format.yDownToFormatSpace( dataWindow );
	}

	ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, format.getDisplayWindow() );

	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	vector<float *> imageChannelData;
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		FloatVectorDataPtr cd = new FloatVectorData;
		vector<float> &c = cd->writable();
		c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f );
		result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd );
		imageChannelData.push_back( &(c[0]) );
	}

	parallel_for( blocked_range2d<size_t>( 0, dataWindow.size().x+1, tileSize(), 0, dataWindow.size().y+1, tileSize() ),
		      GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) );

	return result;
}
IECore::ImagePrimitivePtr DepthTexture::imagePrimitive() const
{
	ScopedBinding binding( *this );
	
	GLint width = 0;
	GLint height = 0;
	glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width );
	glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height );

	vector<float> data( width * height );

	glGetTexImage( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, GL_FLOAT, &data[0] );

	FloatVectorDataPtr zd = new FloatVectorData();
	vector<float> &z = zd->writable();
	z.resize( width * height );

	unsigned int i = 0;
	for( int y=height-1; y>=0; y-- )
	{
		float *rz = &z[y*width];
		for( int x=0; x<width; x++ )
		{
			rz[x] = data[i++];
		}
	}

	Box2i imageExtents( V2i( 0, 0 ), V2i( width-1, height-1 ) );
	ImagePrimitivePtr image = new ImagePrimitive( imageExtents, imageExtents );
	image->variables["Z"] = PrimitiveVariable( PrimitiveVariable::Vertex, zd );

	return image;
}
Beispiel #4
0
IECore::ConstFloatVectorDataPtr Shape::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	assert( parent == shapePlug() );
	if( channelName == g_shapeChannelName )
	{
		// Private channel we use for caching the shape but don't advertise via channelNames.
		return computeShapeChannelData( tileOrigin, context );
	}
	else
	{
		ConstFloatVectorDataPtr shape = parent->channelData( g_shapeChannelName, context->get<V2i>( ImagePlug::tileOriginContextName ) );
		const float c = channelValue( parent, channelName );
		if( c == 1 )
		{
			return shape;
		}
		else
		{
			FloatVectorDataPtr resultData = shape->copy();
			vector<float> &result = resultData->writable();
			for( vector<float>::iterator it = result.begin(), eIt = result.end(); it != eIt; ++it )
			{
				*it *= c;
			}
			return resultData;
		}
	}
}
Beispiel #5
0
static IECore::FloatVectorDataPtr parseFloats( const std::string &value )
{
	FloatVectorDataPtr result = new FloatVectorData;

	string::const_iterator first = value.begin();
	bool r = qi::phrase_parse(

		first, value.end(),

		/////////////////
		qi::omit[ -qi::char_( '{' ) ] >>
		(
			qi::float_ % ','
		) >>
		qi::omit[ -qi::char_( '}' ) ]
		,
		/////////////////

		ascii::space,
		result->writable()

	);

	if( !r || first != value.end() )
	{
		return 0;
	}

	return result;
}
IECore::CompoundDataPtr IECoreRI::SXRendererImplementation::shadePlane( const V2i &resolution ) const
{
	IECore::CompoundDataPtr points = new IECore::CompoundData();
	
	V3fVectorDataPtr pData = new IECore::V3fVectorData();
	V3fVectorDataPtr nData = new IECore::V3fVectorData();
	FloatVectorDataPtr sData = new IECore::FloatVectorData();
	FloatVectorDataPtr tData = new IECore::FloatVectorData();

	std::vector<V3f> &p = pData->writable();
	std::vector<V3f> &n = nData->writable();
	std::vector<float> &s = sData->writable();
	std::vector<float> &t = tData->writable();
	
	unsigned numPoints = resolution[0] * resolution[1];
	
	p.resize( numPoints );
	n.resize( numPoints );
	s.resize( numPoints );
	t.resize( numPoints );
	
	unsigned xResMinus1 = resolution[0] - 1;
	unsigned yResMinus1 = resolution[1] - 1;
	
	unsigned i = 0;
	for( int y = 0; y < resolution[1]; y++ )
	{
		for( int x = 0; x < resolution[0]; x++ )
		{
			p[i] = V3f( float(x) / xResMinus1 , float(y) / yResMinus1, 0.0 );	
			s[i] = p[i][0];
			t[i] = p[i][1];
			n[i] = V3f( 0.0f, 0.0f, 1.0f );
			i++;
		}
	}	
	
	points->writable()[ "P" ] = pData;
	points->writable()[ "N" ] = nData;
	points->writable()[ "s" ] = sData;
	points->writable()[ "t" ] = tData;
	
	return shade( points, resolution );
}
Beispiel #7
0
IECore::ConstFloatVectorDataPtr Constant::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	const int channelIndex = colorIndex( context->get<std::string>( ImagePlug::channelNameContextName ) );
	const float value = colorPlug()->getChild( channelIndex )->getValue();

	FloatVectorDataPtr result = new FloatVectorData;
	result->writable().resize( ImagePlug::tileSize() * ImagePlug::tileSize(), value );

	return result;
}
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;
}
Beispiel #9
0
void Clamp::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channelName, FloatVectorDataPtr outData ) const
{
	const int channelIndex = std::max( 0, ImageAlgo::colorIndex( channelName ) );

	const float minimum = minPlug()->getChild( channelIndex )->getValue();
	const float maximum = maxPlug()->getChild( channelIndex )->getValue();
	const float minClampTo = minClampToPlug()->getChild( channelIndex )->getValue();
	const float maxClampTo = maxClampToPlug()->getChild( channelIndex )->getValue();
	const bool minimumEnabled = minEnabledPlug()->getValue();
	const bool maximumEnabled = maxEnabledPlug()->getValue();
	const bool minClampToEnabled = minClampToEnabledPlug()->getValue();
	const bool maxClampToEnabled = maxClampToEnabledPlug()->getValue();

	std::vector<float> &out = outData->writable();

	std::vector<float>::iterator outDataIterator;

	for (outDataIterator = out.begin(); outDataIterator != out.end(); ++outDataIterator)
	{

		if (minimumEnabled)
		{
			if (*outDataIterator < minimum)
			{
				if (minClampToEnabled)
				{
					*outDataIterator = minClampTo;
				}
				else
				{
					*outDataIterator = minimum;
				}
			}
		}

		if (maximumEnabled)
		{
			if (*outDataIterator > maximum)
			{
				if (maxClampToEnabled)
				{
					*outDataIterator = maxClampTo;
				}
				else
				{
					*outDataIterator = maximum;
				}
			}
		}

	}
}
void ToArnoldShapeConverter::convertRadius( const IECore::Primitive *primitive, AtNode *shape ) const
{
	ConstFloatVectorDataPtr radius = primitive->variableData<FloatVectorData>( "radius" );
	if( !radius )
	{
		FloatVectorDataPtr calculatedRadius = new FloatVectorData();
		if( const FloatData *constantRadius = primitive->variableData<FloatData>( "radius", PrimitiveVariable::Constant ) )
		{
			calculatedRadius->writable().push_back( constantRadius->readable() );
		}
		else if( const FloatVectorData *width = primitive->variableData<FloatVectorData>( "width" ) )
		{
			calculatedRadius->writable().resize( width->readable().size() );
			const std::vector<float>::iterator end = calculatedRadius->writable().end();
			std::vector<float>::const_iterator wIt = width->readable().begin();
			for( std::vector<float>::iterator it = calculatedRadius->writable().begin(); it != end; it++, wIt++ )
			{
				*it = *wIt / 2.0f;
			}
		}
		else
		{
			const FloatData *constantWidth = primitive->variableData<FloatData>( "width", PrimitiveVariable::Constant );
			if( !constantWidth )
			{
				constantWidth = primitive->variableData<FloatData>( "constantwidth", PrimitiveVariable::Constant );
			}
			float r = constantWidth ? constantWidth->readable() / 2.0f : 0.5f;
			calculatedRadius->writable().push_back( r );
		}
		radius = calculatedRadius;
	}
	
	AiNodeSetArray(
		shape,
		"radius",
		AiArrayConvert( radius->readable().size(), 1, AI_TYPE_FLOAT, (void *)&( radius->readable()[0] ) )
	);
}
Beispiel #11
0
		virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize )
		{
			Box2i yUpBox = m_gafferFormat.yDownToFormatSpace( box );
			const V2i boxMinTileOrigin = ImagePlug::tileOrigin( yUpBox.min );
			const V2i boxMaxTileOrigin = ImagePlug::tileOrigin( yUpBox.max );
			for( int tileOriginY = boxMinTileOrigin.y; tileOriginY <= boxMaxTileOrigin.y; tileOriginY += ImagePlug::tileSize() )
			{
				for( int tileOriginX = boxMinTileOrigin.x; tileOriginX <= boxMaxTileOrigin.x; tileOriginX += ImagePlug::tileSize() )
				{
					for( int channelIndex = 0, numChannels = channelNames().size(); channelIndex < numChannels; ++channelIndex )
					{
						const V2i tileOrigin( tileOriginX, tileOriginY );
						ConstFloatVectorDataPtr tileData = getTile( tileOrigin, channelIndex );
						if( !tileData )
						{
							// we've been sent data outside of the data window
							continue;
						}

						// we must create a new object to hold the updated tile data,
						// because the old one might well have been returned from
						// computeChannelData and be being held in the cache.
						FloatVectorDataPtr updatedTileData = tileData->copy();
						vector<float> &updatedTile = updatedTileData->writable();

						const Box2i tileBound( tileOrigin, tileOrigin + Imath::V2i( GafferImage::ImagePlug::tileSize() - 1 ) );
						const Box2i transferBound = IECore::boxIntersection( tileBound, yUpBox );
						for( int y = transferBound.min.y; y<=transferBound.max.y; ++y )
						{
							int srcY = m_gafferFormat.formatToYDownSpace( y );
							size_t srcIndex = ( ( srcY - box.min.y ) * ( box.size().x + 1 ) * numChannels ) + ( transferBound.min.x - box.min.x ) + channelIndex;
							size_t dstIndex = ( y - tileBound.min.y ) * ImagePlug::tileSize() + transferBound.min.x - tileBound.min.x;
							const size_t srcEndIndex = srcIndex + transferBound.size().x * numChannels;
							while( srcIndex <= srcEndIndex )
							{
								updatedTile[dstIndex] = data[srcIndex];
								srcIndex += numChannels;
								dstIndex++;
							}
						}

						setTile( tileOrigin, channelIndex, updatedTileData );
					}
				}
			}

			dataReceivedSignal()( this, box );
		}
Beispiel #12
0
IECore::ConstFloatVectorDataPtr CopyChannels::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	ConstCompoundObjectPtr mapping;
	{
		ImagePlug::GlobalScope c( context );
		mapping = mappingPlug()->getValue();
	}
	if( const IntData *i = mapping->member<const IntData>( channelName ) )
	{
		const ImagePlug *inputImage = inPlugs()->getChild<ImagePlug>( i->readable() );
		const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName );
		const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );
		Box2i inputDataWindow;
		{
			ImagePlug::GlobalScope c( context );
			inputDataWindow = inputImage->dataWindowPlug()->getValue();
		}
		const Box2i validBound = BufferAlgo::intersection( tileBound, inputDataWindow );
		if( validBound == tileBound )
		{
			return inputImage->channelDataPlug()->getValue();
		}
		else
		{
			FloatVectorDataPtr resultData = new FloatVectorData;
			vector<float> &result = resultData->writable();
			result.resize( ImagePlug::tileSize() * ImagePlug::tileSize(), 0.0f );
			if( !BufferAlgo::empty( validBound ) )
			{
				ConstFloatVectorDataPtr inputData = inputImage->channelDataPlug()->getValue();
				copyRegion(
					&inputData->readable().front(),
					tileBound,
					validBound,
					&result.front(),
					tileBound,
					validBound.min
				);
			}
			return resultData;
		}
	}
	else
	{
		return ImagePlug::blackTile();
	}
}
Beispiel #13
0
IECore::ConstFloatVectorDataPtr Constant::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	FloatVectorDataPtr resultData = new FloatVectorData;
	vector<float> &result = resultData->writable();
	result.resize( ImagePlug::tileSize() * ImagePlug::tileSize() );
	
	int idx = channelName == "R" ? 0 : channelName == "G" ? 1 : channelName == "B" ? 2 : 3;
	const float v = colorPlug()->getValue()[idx];
	
	float *ptr = &result[0];
	for( int i = 0; i < ImagePlug::tileSize() * ImagePlug::tileSize(); i++ )
	{
		*ptr++ = v;
	}
	
	return resultData;
}
Beispiel #14
0
IECore::ImagePrimitivePtr ImagePlug::image() const
{
	Format format = formatPlug()->getValue();
	Box2i dataWindow = dataWindowPlug()->getValue();
	Box2i newDataWindow( Imath::V2i(0) );

	if( dataWindow.isEmpty() )
	{
		dataWindow = Box2i( Imath::V2i(0) );
	}
	else
	{
		newDataWindow = format.yDownToFormatSpace( dataWindow );
	}

	// use the default format if we don't have an explicit one.
	/// \todo: remove this once FormatPlug is handling it for
	/// us during ExecutableNode::execute (see issue #887).
	if( format.getDisplayWindow().isEmpty() )
	{
		format = Context::current()->get<Format>( Format::defaultFormatContextName, Format() );
	}
	
	ImagePrimitivePtr result = new ImagePrimitive( newDataWindow, format.getDisplayWindow() );
	
	ConstCompoundObjectPtr metadata = metadataPlug()->getValue();
	compoundObjectToCompoundData( metadata.get(), result->blindData() );
	
	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	vector<float *> imageChannelData;
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		FloatVectorDataPtr cd = new FloatVectorData;
		vector<float> &c = cd->writable();
		c.resize( result->variableSize( PrimitiveVariable::Vertex ), 0.0f );
		result->variables[*it] = PrimitiveVariable( PrimitiveVariable::Vertex, cd );
		imageChannelData.push_back( &(c[0]) );
	}

	parallel_for( blocked_range3d<size_t>( 0, imageChannelData.size(), 1, 0, dataWindow.size().x+1, tileSize(), 0, dataWindow.size().y+1, tileSize() ),
		      GafferImage::Detail::CopyTiles( imageChannelData, channelNames, channelDataPlug(), dataWindow, Context::current(), tileSize()) );

	return result;
}
Beispiel #15
0
IECore::ConstFloatVectorDataPtr ImageReader::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	std::string fileName = fileNamePlug()->getValue();
	ustring uFileName( fileName.c_str() );
	const ImageSpec *spec = imageCache()->imagespec( uFileName );

	vector<string>::const_iterator channelIt = find( spec->channelnames.begin(), spec->channelnames.end(), channelName );
	if( channelIt == spec->channelnames.end() )
	{
		{
			return parent->channelDataPlug()->defaultValue();
		}
	}

	Format format( Imath::Box2i( Imath::V2i( spec->full_x, spec->full_y ), Imath::V2i( spec->full_width + spec->full_x - 1, spec->full_height + spec->full_y - 1 ) ) );
	const int newY = format.formatToYDownSpace( tileOrigin.y + ImagePlug::tileSize() - 1 );

	std::vector<float> channelData( ImagePlug::tileSize() * ImagePlug::tileSize() );
	size_t channelIndex = channelIt - spec->channelnames.begin();
	imageCache()->get_pixels(
		uFileName,
		0, 0, // subimage, miplevel
		tileOrigin.x, tileOrigin.x + ImagePlug::tileSize(),
		newY, newY + ImagePlug::tileSize(),
		0, 1,
		channelIndex, channelIndex + 1,
		TypeDesc::FLOAT,
		&(channelData[0])
	);

	// Create the output data buffer.
	FloatVectorDataPtr resultData = new FloatVectorData;
	vector<float> &result = resultData->writable();
	result.resize( ImagePlug::tileSize() * ImagePlug::tileSize() );

	// Flip the tile in the Y axis to convert it to our internal image data representation.
	for( int y = 0; y < ImagePlug::tileSize(); ++y )
	{
		memcpy( &(result[ ( ImagePlug::tileSize() - y - 1 ) * ImagePlug::tileSize() ]), &(channelData[ y * ImagePlug::tileSize() ]), sizeof(float)*ImagePlug::tileSize()  );
	}

	return resultData;
}
Beispiel #16
0
IECore::ConstFloatVectorDataPtr Mirror::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	const bool horizontal = horizontalPlug()->getValue();
	const bool vertical = verticalPlug()->getValue();

	if( !horizontal && !vertical )
	{
		return inPlug()->channelDataPlug()->getValue();
	}

	const Box2i displayWindow = inPlug()->formatPlug()->getValue().getDisplayWindow();
	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );
	const Box2i sampleWindow = mirror(
		tileBound,
		horizontal,
		vertical,
		displayWindow
	);

	Sampler sampler( inPlug(), channelName, sampleWindow );

	FloatVectorDataPtr outData = new FloatVectorData;
	vector<float> &out = outData->writable();
	out.reserve( ImagePlug::tileSize() * ImagePlug::tileSize() );

	V2i pIn;
	V2i pOut;
	for( pOut.y = tileBound.min.y; pOut.y < tileBound.max.y; ++pOut.y )
	{
		pOut.x = tileBound.min.x;
		pIn = mirror( pOut, horizontal, vertical, displayWindow );
		const int xStep = horizontal ? -1 : 1;
		for( ; pOut.x < tileBound.max.x; ++pOut.x )
		{
			out.push_back( sampler.sample( pIn.x, pIn.y ) );
			pIn.x += xStep;
		}
	}

	return outData;
}
Beispiel #17
0
IECoreImage::ImagePrimitivePtr ImagePlug::image() const
{
	Format format = formatPlug()->getValue();
	Box2i dataWindow = dataWindowPlug()->getValue();
	Box2i newDataWindow( Imath::V2i( 0 ) );

	if( !BufferAlgo::empty( dataWindow ) )
	{
		newDataWindow = format.toEXRSpace( dataWindow );
	}
	else
	{
		dataWindow = newDataWindow;
	}

	Box2i newDisplayWindow = format.toEXRSpace( format.getDisplayWindow() );

	IECoreImage::ImagePrimitivePtr result = new IECoreImage::ImagePrimitive( newDataWindow, newDisplayWindow );

	ConstCompoundDataPtr metadata = metadataPlug()->getValue();
	result->blindData()->Object::copyFrom( metadata.get() );

	ConstStringVectorDataPtr channelNamesData = channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();

	vector<float *> imageChannelData;
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it!=eIt; it++ )
	{
		FloatVectorDataPtr cd = new FloatVectorData;
		vector<float> &c = cd->writable();
		c.resize( result->channelSize(), 0.0f );
		result->channels[*it] = cd;
		imageChannelData.push_back( &(c[0]) );
	}

	CopyTile copyTile( imageChannelData, channelNames, dataWindow );
	ImageAlgo::parallelProcessTiles( this, channelNames, copyTile, dataWindow );

	return result;
}
Beispiel #18
0
void Unpremultiply::processChannelData( const Gaffer::Context *context, const ImagePlug *parent, const std::string &channel, FloatVectorDataPtr outData ) const
{
	std::string alphaChannel = alphaChannelPlug()->getValue();

	if ( channel == alphaChannel )
	{
		return;
	}

	ConstStringVectorDataPtr inChannelNamesPtr;
	{
		ImagePlug::GlobalScope c( context );
		inChannelNamesPtr = inPlug()->channelNamesPlug()->getValue();
	}

	const std::vector<std::string> &inChannelNames = inChannelNamesPtr->readable();
	if ( std::find( inChannelNames.begin(), inChannelNames.end(), alphaChannel ) == inChannelNames.end() )
	{
		std::ostringstream channelError;
		channelError << "Channel '" << alphaChannel << "' does not exist";
		throw( IECore::Exception( channelError.str() ) );
	}

	ImagePlug::ChannelDataScope channelDataScope( context );
	channelDataScope.setChannelName( alphaChannel );

	ConstFloatVectorDataPtr aData = inPlug()->channelDataPlug()->getValue();
	const std::vector<float> &a = aData->readable();
	std::vector<float> &out = outData->writable();

	std::vector<float>::const_iterator aIt = a.begin();
	for ( std::vector<float>::iterator outIt = out.begin(), outItEnd = out.end(); outIt != outItEnd; ++outIt, ++aIt )
	{
		if ( *aIt != 0.0f )
		{
			*outIt /= *aIt;
		}
	}
}
Beispiel #19
0
ObjectPtr SLOReader::doOperation( const CompoundObject * operands )
{
	tbb::mutex::scoped_lock lock( g_mutex );
	
	if( Slo_SetShader( (char *)fileName().c_str() ) )
	{
		throw Exception( boost::str( boost::format( "Unable to set shader to \"%s\"" ) % fileName() ) );
	}

	string name = Slo_GetName();
	string type = Slo_TypetoStr( Slo_GetType() );
	ShaderPtr result = new Shader( name, type );

	CompoundDataPtr typeHints = new CompoundData;
	result->blindData()->writable().insert( pair<string, DataPtr>( "ri:parameterTypeHints", typeHints ) );

	// we lose the ordering of parameter names when we put them in result->parameters(),
	// so we stick the correct order in the blind data as a workaround for anyone interested
	// in the true ordering.
	StringVectorDataPtr orderedParameterNames = new StringVectorData;
	result->blindData()->writable().insert( pair<string, DataPtr>( "ri:orderedParameterNames", orderedParameterNames ) );	

	// we don't have a way of communicating which parameters are outputs in the Shader::parametersData(),
	// so we work around that using the blind data too.
	StringVectorDataPtr outputParameterNames = new StringVectorData;
	result->blindData()->writable().insert( pair<string, DataPtr>( "ri:outputParameterNames", outputParameterNames ) );	

	int numArgs = Slo_GetNArgs();
	for( int i=1; i<=numArgs; i++ )
	{
		DataPtr data = 0;

		SLO_VISSYMDEF *arg = Slo_GetArgById( i );
		switch( arg->svd_type )
		{
			case SLO_TYPE_POINT :
			case SLO_TYPE_VECTOR :
			case SLO_TYPE_NORMAL :
				{
					if( arg->svd_arraylen==0 )
					{
						const SLO_POINT *p = arg->svd_default.pointval;
						if( p )
						{
							data = new V3fData( V3f( p->xval, p->yval, p->zval ) );
						}
						else
						{
							// 0 length and null value signifies a variable length array
							data = new V3fVectorData();
						}
					}
					else
					{
						V3fVectorDataPtr vData = new V3fVectorData();
						data = vData;
						for( int j=0; j<arg->svd_arraylen; j++ )
						{
							SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j );
							const SLO_POINT *p = a->svd_default.pointval;
							vData->writable().push_back( V3f( p->xval, p->yval, p->zval ) );
						}
					}
					typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( Slo_TypetoStr( arg->svd_type ) ) ) );
					break;
				}

			case SLO_TYPE_COLOR :
				{
					if( arg->svd_arraylen==0 )
					{
						const SLO_POINT *p = arg->svd_default.pointval;
						if( p )
						{
							data = new Color3fData( Color3f( p->xval, p->yval, p->zval ) );
						}
						else
						{
							// 0 length and null value signifies a variable length array
							data = new Color3fVectorData();
						}
					}
					else
					{
						Color3fVectorDataPtr vData = new Color3fVectorData();
						data = vData;
						for( int j=0; j<arg->svd_arraylen; j++ )
						{
							SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j );
							const SLO_POINT *p = a->svd_default.pointval;
							vData->writable().push_back( Color3f( p->xval, p->yval, p->zval ) );
						}
					}
				}
				break;

			case SLO_TYPE_SCALAR :
				{
					if( arg->svd_arraylen==0 )
					{
						const float *value = arg->svd_default.scalarval;
						if( value )
						{
							data = new FloatData( *value );
						}
						else
						{
							// 0 length and null value signifies a variable length array
							data = new FloatVectorData();
						}
					}
					else
					{
						FloatVectorDataPtr vData = new FloatVectorData();
						data = vData;
						for( int j=0; j<arg->svd_arraylen; j++ )
						{
							SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j );
							vData->writable().push_back( *(a->svd_default.scalarval) );
						}
						if( arg->svd_arraylen==3 )
						{
							// allow V3fData and V3fVectorData to be mapped to float[3] parameters.
							typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( "float[3]" ) ) );
						}
					}
				}
				break;

			case SLO_TYPE_STRING :
				{
					if( arg->svd_arraylen==0 )
					{
						const char *defaultValue = arg->svd_default.stringval;
						if( defaultValue )
						{
							data = new StringData( defaultValue );
						}
						else
						{
							// 0 length and null value signifies a variable length array
							data = new StringVectorData();
						}
					}
					else
					{
						StringVectorDataPtr vData = new StringVectorData();
						data = vData;
						for( int j=0; j<arg->svd_arraylen; j++ )
						{
							SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j );
							// sometimes the default value for an element of a string array can be a null pointer.
							// i'm not sure what the meaning of this is. the 3delight shaderinfo utility reports such values
							// as "(null)", so that's what we do too.
							const char *defaultValue = a->svd_default.stringval;
							vData->writable().push_back( defaultValue ? defaultValue : "(null)" );
						}
					}
				}
				break;

			case SLO_TYPE_MATRIX :
				{
					if( arg->svd_arraylen==0 )
					{
						const float *m = arg->svd_default.matrixval;
						if( m )
						{
							M44f mm(	m[0], m[1], m[2], m[3],
										m[4], m[5], m[6], m[7],
										m[8], m[9], m[10], m[11],
										m[12], m[13], m[14], m[15] 	);
							data = new M44fData( mm );
						}
						else
						{
							// 0 length and null value signifies a variable length array
							data = new M44fVectorData();
						}
					}
					else
					{
						M44fVectorDataPtr vData = new M44fVectorData();
						data = vData;
						for( int j=0; j<arg->svd_arraylen; j++ )
						{
							SLO_VISSYMDEF *a = Slo_GetArrayArgElement( arg, j );
							const float *m = a->svd_default.matrixval;
							M44f mm(	m[0], m[1], m[2], m[3],
										m[4], m[5], m[6], m[7],
										m[8], m[9], m[10], m[11],
										m[12], m[13], m[14], m[15] 	);
							vData->writable().push_back( mm );
						}
					}
				}
				break;
				
			case SLO_TYPE_SHADER :
				{
					if( arg->svd_arraylen==0 )
					{
						if( !arg->svd_valisvalid )
						{
							// variable length array
							data = new StringVectorData();
						}
						else
						{
							data = new StringData();
						}
					}
					else
					{
						StringVectorDataPtr sData = new StringVectorData();
						data = sData;
						sData->writable().resize( arg->svd_arraylen );
					}
					typeHints->writable().insert( pair<string, DataPtr>( arg->svd_name, new StringData( Slo_TypetoStr( arg->svd_type ) ) ) );
				}
				break;

			default :

				msg( Msg::Warning, "SLOReader::read", format( "Parameter \"%s\" has unsupported type." ) % arg->svd_name );
		}

		if( data )
		{
			orderedParameterNames->writable().push_back( arg->svd_name );
			result->parameters().insert( CompoundDataMap::value_type( arg->svd_name, data ) );
			if( arg->svd_storage == SLO_STOR_OUTPUTPARAMETER )
			{
				outputParameterNames->writable().push_back( arg->svd_name );
			}
		}

	}

	// shader annotations
	
	CompoundDataPtr annotations = new CompoundData;
	result->blindData()->writable().insert( pair<string, DataPtr>( "ri:annotations", annotations ) );
	
#ifndef PRMANEXPORT
	for( int i=1, n=Slo_GetNAnnotations(); i <= n; i++ )
	{
		const char *key = Slo_GetAnnotationKeyById( i );
		annotations->writable()[key] = new StringData( Slo_GetAnnotationByKey( key ) );
	}
#endif

	Slo_EndShader();
	return result;
}
Beispiel #20
0
void LuminanceOp::modifyPrimitive( Primitive * primitive, const CompoundObject * operands )
{
	DataPtr luminanceData = 0;
	PrimitiveVariable::Interpolation interpolation = PrimitiveVariable::Invalid;
	int steps[3] = { 1, 1, 1 };

	PrimitiveVariableMap::iterator colorIt = primitive->variables.find( m_colorPrimVarParameter->getTypedValue() );
	if( colorIt!=primitive->variables.end() && colorIt->second.data )
	{
		// RGB in a single channel
		switch( colorIt->second.data->typeId() )
		{
			case Color3fDataTypeId :
				{
					FloatDataPtr l = new FloatData;
					const float *d = staticPointerCast<Color3fData>( colorIt->second.data )->baseReadable();
					calculate( d, d + 1, d + 2, steps, 1, l->baseWritable() );
					luminanceData = l;
				}
				break;
			case Color3fVectorDataTypeId :
				{
					FloatVectorDataPtr l = new FloatVectorData;
					Color3fVectorDataPtr d = staticPointerCast<Color3fVectorData>( colorIt->second.data );
					l->writable().resize( d->readable().size() );
					const float *dd = d->baseReadable();
					steps[0] = steps[1] = steps[2] = 3;
					calculate( dd, dd + 1, dd + 2, steps, d->readable().size(), l->baseWritable() );
					luminanceData = l;
				}
				break;
			default :
				throw Exception( "PrimitiveVariable has unsupported type." );
				break;
		}
		interpolation = colorIt->second.interpolation;
	}
	else
	{
		// separate RGB channels?
		PrimitiveVariableMap::iterator rIt = primitive->variables.find( m_redPrimVarParameter->getTypedValue() );
		PrimitiveVariableMap::iterator gIt = primitive->variables.find( m_greenPrimVarParameter->getTypedValue() );
		PrimitiveVariableMap::iterator bIt = primitive->variables.find( m_bluePrimVarParameter->getTypedValue() );
		if( rIt==primitive->variables.end() || gIt==primitive->variables.end() || bIt==primitive->variables.end() )
		{
			throw Exception( "Primitive does not have appropriately named PrimitiveVariables." );
		}
		TypeId type = rIt->second.data->typeId();
		if( gIt->second.data->typeId() != type || bIt->second.data->typeId() != type )
		{
			throw Exception( "PrimitiveVariable types do not match." );
		}
		size_t rSize = despatchTypedData<TypedDataSize>( rIt->second.data );
		size_t gSize = despatchTypedData<TypedDataSize>( gIt->second.data );
		size_t bSize = despatchTypedData<TypedDataSize>( bIt->second.data );
		if( rSize!=gSize || rSize!=bSize )
		{
			throw Exception( "PrimitiveVariable sizes do not match." );
		}
		switch( type )
		{
			case HalfDataTypeId :
				{
					HalfDataPtr l = new HalfData;
					calculate(
						staticPointerCast<HalfData>( rIt->second.data )->baseReadable(),
						staticPointerCast<HalfData>( gIt->second.data )->baseReadable(),
						staticPointerCast<HalfData>( bIt->second.data )->baseReadable(),
						steps,
						rSize,
						l->baseWritable()
					);
					luminanceData = l;
				}
				break;
			case HalfVectorDataTypeId :
				{
					HalfVectorDataPtr l = new HalfVectorData;
					l->writable().resize( rSize );
					calculate(
						staticPointerCast<HalfVectorData>( rIt->second.data )->baseReadable(),
						staticPointerCast<HalfVectorData>( gIt->second.data )->baseReadable(),
						staticPointerCast<HalfVectorData>( bIt->second.data )->baseReadable(),
						steps,
						rSize,
						l->baseWritable()
					);
					luminanceData = l;
				}
				break;
			case FloatDataTypeId :
				{
					FloatDataPtr l = new FloatData;
					calculate(
						staticPointerCast<FloatData>( rIt->second.data )->baseReadable(),
						staticPointerCast<FloatData>( gIt->second.data )->baseReadable(),
						staticPointerCast<FloatData>( bIt->second.data )->baseReadable(),
						steps,
						rSize,
						l->baseWritable()
					);
					luminanceData = l;
				}
				break;
			case FloatVectorDataTypeId :
				{
					FloatVectorDataPtr l = new FloatVectorData;
					l->writable().resize( rSize );
					calculate(
						staticPointerCast<FloatVectorData>( rIt->second.data )->baseReadable(),
						staticPointerCast<FloatVectorData>( gIt->second.data )->baseReadable(),
						staticPointerCast<FloatVectorData>( bIt->second.data )->baseReadable(),
						steps,
						rSize,
						l->baseWritable()
					);
					luminanceData = l;
				}
				break;
			default :
				throw Exception( "PrimitiveVariables have unsupported type." );
				break;
		}
		interpolation = rIt->second.interpolation;
	}

	assert( interpolation != PrimitiveVariable::Invalid );
	assert( luminanceData );

	primitive->variables[luminancePrimVarParameter()->getTypedValue()] = PrimitiveVariable( interpolation, luminanceData );

	if( removeColorPrimVarsParameter()->getTypedValue() )
	{
		primitive->variables.erase( colorPrimVarParameter()->getTypedValue() );
		primitive->variables.erase( redPrimVarParameter()->getTypedValue() );
		primitive->variables.erase( greenPrimVarParameter()->getTypedValue() );
		primitive->variables.erase( bluePrimVarParameter()->getTypedValue() );
	}
}
Beispiel #21
0
ImagePrimitivePtr ColorTexture::imagePrimitive() const
{
	ScopedBinding binding( *this );

	GLint width = 0;
	GLint height = 0;
	glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width );
	glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height );

	GLint internalFormat = 0;
	glGetTexLevelParameteriv( GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, &internalFormat );

	unsigned int numChannels = 4;
	vector<float> data( width * height * numChannels );

	glGetTexImage( GL_TEXTURE_2D, 0, GL_RGBA, GL_FLOAT, &data[0] );

	FloatVectorDataPtr rd = new FloatVectorData();
	vector<float> &r = rd->writable(); r.resize( width * height );

	FloatVectorDataPtr gd = new FloatVectorData();
	vector<float> &g = gd->writable(); g.resize( width * height );

	FloatVectorDataPtr bd = new FloatVectorData();
	vector<float> &b = bd->writable(); b.resize( width * height );

	FloatVectorDataPtr ad = 0;
	vector<float> *a = 0;
	// there are potentially loads of different internal formats which denote alpha.
	// these are the only ones encountered so far, but it's not a great way of testing
	// and i can't find another way of doing it.
	if( internalFormat==GL_RGBA || internalFormat==GL_RGBA8_EXT || internalFormat==GL_RGBA16 )
	{
		ad = new FloatVectorData();
		a = &ad->writable(); a->resize( width * height );
	}

	unsigned int i = 0;
	for( int y=height-1; y>=0; y-- )
	{
		float *rr = &r[y*width];
		float *rg = &g[y*width];
		float *rb = &b[y*width];
		float *ra = a ? &(*a)[y*width] : 0;
		for( int x=0; x<width; x++ )
		{
			rr[x] = data[i++];
			rg[x] = data[i++];
			rb[x] = data[i++];
			if( ra )
			{
				ra[x] = data[i++];
			}
		}
	}

	Box2i imageExtents( V2i( 0, 0 ), V2i( width-1, height-1 ) );
	ImagePrimitivePtr image = new ImagePrimitive( imageExtents, imageExtents );
	image->variables["R"] = PrimitiveVariable( PrimitiveVariable::Vertex, rd );
	image->variables["G"] = PrimitiveVariable( PrimitiveVariable::Vertex, gd );
	image->variables["B"] = PrimitiveVariable( PrimitiveVariable::Vertex, bd );
	if( a )
	{
		image->variables["A"] = PrimitiveVariable( PrimitiveVariable::Vertex, ad );
	}

	Exception::throwIfError();
	
	return image;
}
Beispiel #22
0
MeshPrimitivePtr MeshPrimitive::createSphere( float radius, float zMin, float zMax, float thetaMax, const Imath::V2i &divisions )
{
    IntVectorDataPtr vertexIds = new IntVectorData;
    IntVectorDataPtr verticesPerFace = new IntVectorData;
    std::vector<int> &vpf = verticesPerFace->writable();
    std::vector<int> &vIds = vertexIds->writable();

    V3fVectorDataPtr pData = new V3fVectorData;
    V3fVectorDataPtr nData = new V3fVectorData;
    std::vector<V3f> &pVector = pData->writable();
    std::vector<V3f> &nVector = nData->writable();

    FloatVectorDataPtr sData = new FloatVectorData;
    FloatVectorDataPtr tData = new FloatVectorData;
    std::vector<float> &sVector = sData->writable();
    std::vector<float> &tVector = tData->writable();

    float oMin = Math<float>::asin( zMin );
    float oMax = Math<float>::asin( zMax );
    const unsigned int nO = max( 4u, (unsigned int)( ( divisions.x + 1 ) * (oMax - oMin) / M_PI ) );

    float thetaMaxRad = thetaMax / 180.0f * M_PI;
    const unsigned int nT = max( 7u, (unsigned int)( ( divisions.y + 1 ) * thetaMaxRad / (M_PI*2) ) );

    for ( unsigned int i=0; i<nO; i++ )
    {
        float v = (float)i/(float)(nO-1);
        float o = lerp( oMin, oMax, v );
        float z = radius * Math<float>::sin( o );
        float r = radius * Math<float>::cos( o );

        for ( unsigned int j=0; j<nT; j++ )
        {
            float u = (float)j/(float)(nT-1);
            float theta = thetaMaxRad * u;
            V3f p( r * Math<float>::cos( theta ), r * Math<float>::sin( theta ), z );
            sVector.push_back( u );
            tVector.push_back( v );
            pVector.push_back( p );
            nVector.push_back( p );
            if( i < nO - 1 && j < nT - 1 )
            {
                unsigned int i0 = i * nT + j;
                unsigned int i1 = i0 + 1;
                unsigned int i2 = i0 + nT;
                unsigned int i3 = i2 + 1;
                vpf.push_back( 3 );
                vIds.push_back( i0 );
                vIds.push_back( i1 );
                vIds.push_back( i2 );
                vpf.push_back( 3 );
                vIds.push_back( i1 );
                vIds.push_back( i3 );
                vIds.push_back( i2 );
            }
        }
    }

    MeshPrimitivePtr result = new MeshPrimitive( verticesPerFace, vertexIds, "linear", pData );
    result->variables["N"] = PrimitiveVariable( PrimitiveVariable::Vertex, nData );
    result->variables["s"] = PrimitiveVariable( PrimitiveVariable::Vertex, sData );
    result->variables["t"] = PrimitiveVariable( PrimitiveVariable::Vertex, tData );

    return result;
}
CompoundDataPtr BGEOParticleReader::readAttributes( const std::vector<std::string> &names )
{
	if( !open() )
	{
		return 0;
	}
	
	CompoundDataPtr result = new CompoundData();
	
	std::vector< struct AttrInfo > attrInfo;
	
	int intAttribBuffer[ 3 ];
	int *intAttributePtr = &intAttribBuffer[0];
	float floatAttribBuffer[ 4 ];
	float *floatAttributePtr = &floatAttribBuffer[0];
	
	vector<Record>::const_iterator it;
	for( it=m_header.attributes.begin(); it!=m_header.attributes.end(); it++ )
	{
		V3fVectorDataPtr v3fVector = 0;
		V2fVectorDataPtr v2fVector = 0;
		FloatVectorDataPtr floatVector = 0;
		IntVectorDataPtr intVector = 0;
		StringVectorDataPtr stringVector = 0;
		DataPtr dataVector = 0;
		
		if ( it->size == 1 )
		{
			if ( it->type == Float )
			{
				floatVector = new FloatVectorData();
				floatVector->writable().resize( numParticles() );
				dataVector = floatVector;
			}
			else if ( it->type == Integer )
			{
				intVector = new IntVectorData();
				intVector->writable().resize( numParticles() );
				dataVector = intVector;
			}
			else if ( it->type == Index )
			{
				stringVector = new StringVectorData();
				stringVector->writable().resize( numParticles() );
				dataVector = stringVector;
			}
		}
		else if ( it->size == 2 )
		{
			v2fVector = new V2fVectorData();
			v2fVector->writable().resize( numParticles() );
			dataVector = v2fVector;
		}
		else if ( it->size == 3 || it->size == 4 )
		{
			v3fVector = new V3fVectorData();
			v3fVector->writable().resize( numParticles() );
			dataVector = v3fVector;
		}
		else
		{
			msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized type '%d' of size '%d' while loading attribute %s." ) % it->type % it->size % it->name );
			return 0;
		}

		AttrInfo info = {
			*it,
			dataVector,
		};

		attrInfo.push_back( info );
	}
		
	// read all of the data at once
	std::vector<char> dataBuffer;
	dataBuffer.resize( m_header.numPoints * m_header.dataSize );
	char *dataBufferPtr = &dataBuffer[0];
	m_iStream->seekg( ios_base::beg + m_header.firstPointPosition );
	m_iStream->read( dataBufferPtr, m_header.numPoints * m_header.dataSize );
	for ( int i = 0; i < m_header.numPoints; i++)
	{
		std::vector< struct AttrInfo >::iterator it;
		for (it = attrInfo.begin(); it != attrInfo.end(); it++)
		{
			// P contains an additional byte in the BGEO
			if ( it->info.type == Integer || it->info.type == Index )
			{
				readAttributeData( &dataBufferPtr, intAttributePtr, it->info.size );
			}
			else
			{
				readAttributeData( &dataBufferPtr, floatAttributePtr, it->info.size );
			}
			
			switch (it->targetData->typeId())
			{
			case V3fVectorDataTypeId:
				{
					V3f &p = staticPointerCast<V3fVectorData>(it->targetData)->writable()[ i ];
					p[0] = floatAttributePtr[0];
					p[1] = floatAttributePtr[1];
					p[2] = floatAttributePtr[2];
					break;
				}
			case V2fVectorDataTypeId:
				{
					V2f &p = staticPointerCast<V2fVectorData>(it->targetData)->writable()[ i ];
					p[0] = floatAttributePtr[0];
					p[1] = floatAttributePtr[1];
					break;
				}
			case FloatVectorDataTypeId:
				staticPointerCast<FloatVectorData>(it->targetData)->writable()[ i ] = floatAttributePtr[0];
				break;
			case IntVectorDataTypeId:
				staticPointerCast<IntVectorData>(it->targetData)->writable()[ i ] = intAttributePtr[0];
				break;
			case StringVectorDataTypeId:
				{
					std::string value = it->info.indexableValues.at( intAttributePtr[0] );
					staticPointerCast<StringVectorData>(it->targetData)->writable()[ i ] = value;
					break;
				}
			default:
				msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized typeId '%d'." ) % it->targetData->typeId() );
				return 0;
			}
		}
	}
	
	/// \todo Use particle ids for filtering.
	const Data *ids = 0;

	DataPtr filteredData = 0;
	// filter and convert each attribute individually.
	std::vector< struct AttrInfo >::const_iterator attrIt;
	for( attrIt=attrInfo.begin(); attrIt!=attrInfo.end(); attrIt++ )
	{
		// The data had to be read, but we don't need to filter or store it
		if( find( names.begin(), names.end(), attrIt->info.name ) == names.end() )
		{
			continue;
		}
		
		if ( attrIt->info.size == 1 )
		{
			if ( attrIt->info.type == Float )
			{
				switch( realType() )
				{
				case ParticleReader::Native :
				case ParticleReader::Float :
					filteredData = filterAttr<FloatVectorData, FloatVectorData>( staticPointerCast<FloatVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				case ParticleReader::Double :
					filteredData = filterAttr<DoubleVectorData, FloatVectorData>( staticPointerCast<FloatVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				}
			}
			else if ( attrIt->info.type == Integer )
			{
				filteredData = filterAttr<IntVectorData, IntVectorData>( staticPointerCast<IntVectorData>(attrIt->targetData), particlePercentage(), ids );
			}
			else if ( attrIt->info.type == Index )
			{
				filteredData = filterAttr<StringVectorData, StringVectorData>( staticPointerCast<StringVectorData>(attrIt->targetData), particlePercentage(), ids );
			}
		}
		else if ( attrIt->info.size == 2 )
		{
			if ( attrIt->info.type == Float )
			{
				switch( realType() )
				{
				case ParticleReader::Native :
				case ParticleReader::Float :
					filteredData = filterAttr<V2fVectorData, V2fVectorData>( staticPointerCast<V2fVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				case ParticleReader::Double :
					filteredData = filterAttr<V2dVectorData, V2fVectorData>( staticPointerCast<V2fVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				}
			}
		}
		else if ( attrIt->info.size == 3 || attrIt->info.size == 4 )
		{
			if ( ( attrIt->info.type == Float ) || ( attrIt->info.type == Vector ) )
			{
				switch( realType() )
				{
				case ParticleReader::Native :
				case ParticleReader::Float :
					filteredData = filterAttr<V3fVectorData, V3fVectorData>( staticPointerCast<V3fVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				case ParticleReader::Double :
					filteredData = filterAttr<V3dVectorData, V3fVectorData>( staticPointerCast<V3fVectorData>(attrIt->targetData), particlePercentage(), ids );
					break;
				}
			}
		}
		else
		{
			msg( Msg::Error, "BGEOParticleReader::readAttributes()", format( "Internal error. Unrecognized type '%d' of size '%d' while converting attribute %s." ) % attrIt->info.type % attrIt->info.size % attrIt->info.name );
			return 0;
		}
		
		result->writable()[attrIt->info.name] = filteredData;
	}
	
	return result;
}
Beispiel #24
0
IECore::ConstCompoundDataPtr OSLImage::computeShading( const Gaffer::Context *context ) const
{
	OSLRenderer::ConstShadingEnginePtr shadingEngine;
	if( const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source<Plug>()->node() ) )
	{
		shadingEngine = shader->shadingEngine();
	}

	if( !shadingEngine )
	{
		return static_cast<const CompoundData *>( shadingPlug()->defaultValue() );
	}

	const V2i tileOrigin = context->get<V2i>( ImagePlug::tileOriginContextName );
	const Format format = inPlug()->formatPlug()->getValue();

	CompoundDataPtr shadingPoints = new CompoundData();

	V3fVectorDataPtr pData = new V3fVectorData;
	FloatVectorDataPtr uData = new FloatVectorData;
	FloatVectorDataPtr vData = new FloatVectorData;

	vector<V3f> &pWritable = pData->writable();
	vector<float> &uWritable = uData->writable();
	vector<float> &vWritable = vData->writable();

	const size_t tileSize = ImagePlug::tileSize();
	pWritable.reserve( tileSize * tileSize );
	uWritable.reserve( tileSize * tileSize );
	vWritable.reserve( tileSize * tileSize );

	/// \todo Non-zero display window origins - do we have those?
	const float uStep = 1.0f / format.width();
	const float uMin = 0.5f * uStep;

	const float vStep = 1.0f / format.height();
	const float vMin = 0.5f * vStep;

	const size_t xMax = tileOrigin.x + tileSize;
	const size_t yMax = tileOrigin.y + tileSize;
	for( size_t y = tileOrigin.y; y < yMax; ++y )
	{
		const float v = vMin + y * vStep;
		for( size_t x = tileOrigin.x; x < xMax; ++x )
		{
			uWritable.push_back( uMin + x * uStep );
			vWritable.push_back( v );
			pWritable.push_back( V3f( x, y, 0.0f ) );
		}
	}

	shadingPoints->writable()["P"] = pData;
	shadingPoints->writable()["u"] = uData;
	shadingPoints->writable()["v"] = vData;

	ConstStringVectorDataPtr channelNamesData = inPlug()->channelNamesPlug()->getValue();
	const vector<string> &channelNames = channelNamesData->readable();
	for( vector<string>::const_iterator it = channelNames.begin(), eIt = channelNames.end(); it != eIt; ++it )
	{
		shadingPoints->writable()[*it] = boost::const_pointer_cast<FloatVectorData>( inPlug()->channelData( *it, tileOrigin ) );
	}

	CompoundDataPtr result = shadingEngine->shade( shadingPoints.get() );

	// remove results that aren't suitable to become channels
	for( CompoundDataMap::iterator it = result->writable().begin(); it != result->writable().end();  )
	{
		CompoundDataMap::iterator nextIt = it; nextIt++;
		if( !runTimeCast<FloatVectorData>( it->second ) )
		{
			result->writable().erase( it );
		}
		it = nextIt;
	}

	return result;
}
Beispiel #25
0
void FaceAreaOp::modifyTypedPrimitive( MeshPrimitive * mesh, const CompoundObject * operands )
{
	string areaPrimVarName = parameters()->parameter<StringParameter>( "areaPrimVar" )->getTypedValue();
	if( areaPrimVarName!="" )
	{
	
		const string &pName = parameters()->parameter<StringParameter>( "pointPrimVar" )->getTypedValue();
		ConstV3fVectorDataPtr pData = mesh->variableData<V3fVectorData>( pName, PrimitiveVariable::Vertex );
		if( !pData )
		{
			throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no \"%s\" primitive variable." ) % pName ) );
		}
		const vector<V3f> &p = pData->readable();

		FloatVectorDataPtr areasData = new FloatVectorData;
		vector<float> &areas = areasData->writable();
		areas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) );
		PolygonIterator faceEnd = mesh->faceEnd();
		for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ )
		{
			typedef vector<V3f> PointVector;
			areas.push_back( polygonArea( pIt.vertexBegin( p.begin() ), pIt.vertexEnd( p.begin() ) ) );
		}

		mesh->variables[areaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, areasData );
	}
	
	string textureAreaPrimVarName = parameters()->parameter<StringParameter>( "textureAreaPrimVar" )->getTypedValue();
	if( textureAreaPrimVarName!="" )
	{
	
		const string &sName = parameters()->parameter<StringParameter>( "sPrimVar" )->getTypedValue();
		PrimitiveVariable::Interpolation sInterpolation = PrimitiveVariable::Vertex;
		ConstFloatVectorDataPtr sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::Vertex );
		if( !sData )
		{
			sData = mesh->variableData<FloatVectorData>( sName, PrimitiveVariable::FaceVarying );
			if( !sData )
			{
				throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % sName ) );
			}
			sInterpolation = PrimitiveVariable::FaceVarying;
		}
		const vector<float> &s = sData->readable();

		const string &tName = parameters()->parameter<StringParameter>( "tPrimVar" )->getTypedValue();
		PrimitiveVariable::Interpolation tInterpolation = PrimitiveVariable::Vertex;
		ConstFloatVectorDataPtr tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::Vertex );
		if( !tData )
		{
			tData = mesh->variableData<FloatVectorData>( tName, PrimitiveVariable::FaceVarying );
			if( !tData )
			{
				throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : MeshPrimitive has no suitable \"%s\" primitive variable." ) % tName ) );
			}
			tInterpolation = PrimitiveVariable::FaceVarying;
		}
		const vector<float> &t = tData->readable();

		if( sInterpolation!=tInterpolation )
		{
			throw InvalidArgumentException( boost::str( boost::format( "FaceAreaOp : interpolation for \"%s\" and \"%s\" primitive variables don't match." ) % sName % tName ) );
		}

		FloatVectorDataPtr textureAreasData = new FloatVectorData;
		vector<float> &textureAreas = textureAreasData->writable();
		textureAreas.reserve( mesh->variableSize( PrimitiveVariable::Uniform ) );
		PolygonIterator faceEnd = mesh->faceEnd();
		for( PolygonIterator pIt = mesh->faceBegin(); pIt!=faceEnd; pIt++ )
		{
			if( sInterpolation==PrimitiveVariable::Vertex )
			{
				typedef PolygonVertexIterator<vector<float>::const_iterator> VertexIterator;
				typedef boost::tuple<VertexIterator, VertexIterator> IteratorTuple;
				typedef boost::zip_iterator<IteratorTuple> ZipIterator;
				typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator;
			
				STIterator begin( ZipIterator( IteratorTuple( pIt.vertexBegin( s.begin() ), pIt.vertexBegin( t.begin() ) ) ) );
				STIterator end( ZipIterator( IteratorTuple( pIt.vertexEnd( s.begin() ), pIt.vertexEnd( t.begin() ) ) ) );
			
				textureAreas.push_back( polygonArea( begin, end ) );
			}
			else
			{
				assert( sInterpolation==PrimitiveVariable::FaceVarying );
				typedef boost::tuple<vector<float>::const_iterator, vector<float>::const_iterator> IteratorTuple;
				typedef boost::zip_iterator<IteratorTuple> ZipIterator;
				typedef boost::transform_iterator<STTupleToV3f, ZipIterator> STIterator;
			
				STIterator begin( ZipIterator( IteratorTuple( pIt.faceVaryingBegin( s.begin() ), pIt.faceVaryingBegin( t.begin() ) ) ) );
				STIterator end( ZipIterator( IteratorTuple( pIt.faceVaryingEnd( s.begin() ), pIt.faceVaryingEnd( t.begin() ) ) ) );
			
				textureAreas.push_back( polygonArea( begin, end ) );
			}
		}

		mesh->variables[textureAreaPrimVarName] = PrimitiveVariable( PrimitiveVariable::Uniform, textureAreasData );
	
	}
	
}
void FromHoudiniPolygonsConverter::convertCreases( MeshPrimitive *mesh, const std::vector<int> &vertIds, size_t numEdges ) const
{
	// Houdini stores creases via a Vertex Attrib (which has been converted to a FaceVarying PrimitiveVariable),
	// with the first face-vert of each creased face-edge containing the sharpness, and all other face-verts set to 0.
	const auto *creaseWeightData = mesh->variableData<FloatVectorData>( g_creaseWeightAttrib, PrimitiveVariable::FaceVarying );
	if( !creaseWeightData )
	{
		return;
	}

	IntVectorDataPtr creaseLengthsData = new IntVectorData();
	auto &creaseLengths = creaseLengthsData->writable();

	IntVectorDataPtr creaseIdsData = new IntVectorData();
	auto &creaseIds = creaseIdsData->writable();

	FloatVectorDataPtr creaseSharpnessesData = new FloatVectorData();
	auto &creaseSharpnesses = creaseSharpnessesData->writable();

	// Calculate face-edge offsets based on winding order in Houdini,
	// which is opposite to that of Cortex. We need these to map from
	// single face-vert crease weights and find both verts of the edge.
	size_t faceOffset = 0;
	std::vector<int> windingOffsets;
	// most face-vert offsets will be to use the previous face-vert
	windingOffsets.resize( mesh->variableSize( PrimitiveVariable::FaceVarying ), -1 );
	for( auto numFaceVerts : mesh->verticesPerFace()->readable() )
	{
		// but we need to mark a wraparound vert for each face
		windingOffsets[faceOffset] = (numFaceVerts - 1);
		faceOffset += numFaceVerts;
	}

	const auto &creaseWeights = creaseWeightData->readable();
	for( int i = 0; i < creaseWeights.size(); ++i )
	{
		// there is a crease at this face-edge
		if( creaseWeights[i] > 0.0f )
		{
			// locate the 2nd vert of this face-edge
			int nextFaceVert = i + windingOffsets[i];

			// Since Houdini will have stored the crease in both directions
			// (once for each face-edge), we need to make sure we only record
			// it once, so we enforce that the vertIds are increasing.
			if( vertIds[i] < vertIds[nextFaceVert] )
			{
				creaseLengths.push_back( 2 );
				creaseIds.push_back( vertIds[i] );
				creaseIds.push_back( vertIds[nextFaceVert] );
				creaseSharpnesses.push_back( creaseWeights[i] );
			}
		}
	}

	if( !creaseLengths.empty() )
	{
		mesh->setCreases( creaseLengthsData.get(), creaseIdsData.get(), creaseSharpnessesData.get() );
		mesh->variables.erase( g_creaseWeightAttrib );
	}
}
Beispiel #27
0
MeshPrimitivePtr MeshPrimitive::createPlane( const Box2f &b, const Imath::V2i &divisions )
{
    V3fVectorDataPtr pData = new V3fVectorData;
    std::vector<V3f> &p = pData->writable();

    // add vertices
    float xStep = b.size().x / (float)divisions.x;
    float yStep = b.size().y / (float)divisions.y;
    for ( int i = 0; i <= divisions.y; ++i )
    {
        for ( int j = 0; j <= divisions.x; ++j )
        {
            p.push_back( V3f( b.min.x + j * xStep, b.min.y + i * yStep, 0 ) );
        }
    }

    IntVectorDataPtr vertexIds = new IntVectorData;
    IntVectorDataPtr verticesPerFace = new IntVectorData;
    std::vector<int> &vpf = verticesPerFace->writable();
    std::vector<int> &vIds = vertexIds->writable();

    FloatVectorDataPtr sData = new FloatVectorData;
    FloatVectorDataPtr tData = new FloatVectorData;
    std::vector<float> &s = sData->writable();
    std::vector<float> &t = tData->writable();

    float sStep = 1.0f / (float)divisions.x;
    float tStep = 1.0f / (float)divisions.y;

    // add faces
    int v0, v1, v2, v3;
    for ( int i = 0; i < divisions.y; ++i )
    {
        for ( int j = 0; j < divisions.x; ++j )
        {
            v0 = j + (divisions.x+1) * i;
            v1 = j + 1 + (divisions.x+1) * i;;
            v2 = j + 1 + (divisions.x+1) * (i+1);
            v3 = j + (divisions.x+1) * (i+1);

            vpf.push_back( 4 );
            vIds.push_back( v0 );
            vIds.push_back( v1 );
            vIds.push_back( v2 );
            vIds.push_back( v3 );

            s.push_back( j * sStep );
            s.push_back( (j+1) * sStep );
            s.push_back( (j+1) * sStep );
            s.push_back( j * sStep );

            t.push_back( 1 - i * tStep );
            t.push_back( 1 - i * tStep );
            t.push_back( 1 - (i+1) * tStep );
            t.push_back( 1 - (i+1) * tStep );
        }
    }

    MeshPrimitivePtr result = new MeshPrimitive( verticesPerFace, vertexIds, "linear", pData );
    result->variables["s"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, sData );
    result->variables["t"] = PrimitiveVariable( PrimitiveVariable::FaceVarying, tData );

    return result;
}
Beispiel #28
0
IECore::ConstFloatVectorDataPtr Merge::merge( F f, const std::string &channelName, const Imath::V2i &tileOrigin ) const
{
	FloatVectorDataPtr resultData = NULL;
	// Temporary buffer for computing the alpha of intermediate composited layers.
	FloatVectorDataPtr resultAlphaData = NULL;

	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );

	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it )
	{
		if( !(*it)->getInput<ValuePlug>() )
		{
			continue;
		}

		IECore::ConstStringVectorDataPtr channelNamesData = (*it)->channelNamesPlug()->getValue();
		const std::vector<std::string> &channelNames = channelNamesData->readable();

		ConstFloatVectorDataPtr channelData;
		ConstFloatVectorDataPtr alphaData;

		if( channelExists( channelNames, channelName ) )
		{
			channelData = (*it)->channelDataPlug()->getValue();
		}
		else
		{
			channelData = ImagePlug::blackTile();
		}

		if( channelExists( channelNames, "A" ) )
		{
			alphaData = (*it)->channelData( "A", tileOrigin );
		}
		else
		{
			alphaData = ImagePlug::blackTile();
		}

		const Box2i validBound = boxIntersection( tileBound, (*it)->dataWindowPlug()->getValue() );

		if( !resultData )
		{
			// The first connected layer, with which we must initialise our result.
			// There's no guarantee that this layer actually covers the full data
			// window though (the data window could have been expanded by the upper
			// layers) so we must take care to mask out any invalid areas of the input.
			/// \todo I'm not convinced this is correct - if we have no connection
			/// to in[0] then should that not be treated as being a black image, so
			/// we should unconditionally initaliase with in[0] and then always use
			/// the operation for in[1:], even if in[0] is disconnected. In other
			/// words, shouldn't multiplying a white constant over an unconnected
			/// in[0] produce black?
			resultData = channelData->copy();
			resultAlphaData = alphaData->copy();
			float *B = &resultData->writable().front();
			float *b = &resultAlphaData->writable().front();
			for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
			{
				const bool yValid = y >= validBound.min.y && y < validBound.max.y;
				for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
				{
					if( !yValid || x < validBound.min.x || x >= validBound.max.x )
					{
						*B = *b = 0.0f;
					}
					++B; ++b;
				}
			}
		}
		else
		{
			// A higher layer (A) which must be composited over the result (B).
			const float *A = &channelData->readable().front();
			float *B = &resultData->writable().front();
			const float *a = &alphaData->readable().front();
			float *b = &resultAlphaData->writable().front();

			for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
			{
				const bool yValid = y >= validBound.min.y && y < validBound.max.y;
				for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
				{
					const bool valid = yValid && x >= validBound.min.x && x < validBound.max.x;

					*B = f( valid ? *A : 0.0f, *B, valid ? *a : 0.0f, *b );
					*b = f( valid ? *a : 0.0f, *b, valid ? *a : 0.0f, *b );

					++A; ++B; ++a; ++b;
				}
			}
		}
	}

	return resultData;
}
Beispiel #29
0
IECore::ConstFloatVectorDataPtr Mix::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{

	const float mix = mixPlug()->getValue();

	if( mix == 0.0f )
	{
		return inPlugs()->getChild< ImagePlug>( 0 )->channelDataPlug()->getValue();
	}
	else if( mix == 1.0f && !maskPlug()->getInput<ValuePlug>() )
	{
		return inPlugs()->getChild< ImagePlug >( 1 )->channelDataPlug()->getValue();
	}

	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );

	IECore::ConstStringVectorDataPtr maskChannelNamesData;
	Box2i maskDataWindow;
	{
		ImagePlug::GlobalScope c( Context::current() );
		maskChannelNamesData = maskPlug()->channelNamesPlug()->getValue();
		maskDataWindow = maskPlug()->dataWindowPlug()->getValue();
	}

	const std::string &maskChannel = maskChannelPlug()->getValue();
	ConstFloatVectorDataPtr maskData = NULL;
	Box2i maskValidBound;
	if( maskPlug()->getInput<ValuePlug>() && ImageAlgo::channelExists( maskChannelNamesData->readable(), maskChannel ) )
	{
		maskData = maskPlug()->channelData( maskChannel, tileOrigin );
		maskValidBound = boxIntersection( tileBound, maskDataWindow );
	}

	ConstFloatVectorDataPtr channelData[2];
	Box2i validBound[2];

	int i = 0;
	for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it,++i )
	{
		IECore::ConstStringVectorDataPtr channelNamesData;
		Box2i dataWindow;
		{
			ImagePlug::GlobalScope c( Context::current() );
			channelNamesData = (*it)->channelNamesPlug()->getValue();
			dataWindow = (*it)->dataWindowPlug()->getValue();
		}

		const std::vector<std::string> &channelNames = channelNamesData->readable();


		if( ImageAlgo::channelExists( channelNames, channelName ) )
		{
			channelData[i] = (*it)->channelDataPlug()->getValue();
			validBound[i] = boxIntersection( tileBound, dataWindow );
		}
		else
		{
			channelData[i] = NULL;
			validBound[i] = Box2i();
		}

	}


	FloatVectorDataPtr resultData = ImagePlug::blackTile()->copy();
	float *R = &resultData->writable().front();
	const float *A = channelData[0] ? &channelData[0]->readable().front() : NULL;
	const float *B = channelData[1] ? &channelData[1]->readable().front() : NULL;
	const float *M = maskData ? &maskData->readable().front() : NULL;

	for( int y = tileBound.min.y; y < tileBound.max.y; ++y )
	{
		const bool yValidIn0 = y >= validBound[0].min.y && y < validBound[0].max.y;
		const bool yValidIn1 = y >= validBound[1].min.y && y < validBound[1].max.y;
		const bool yValidMask = y >= maskValidBound.min.y && y < maskValidBound.max.y;

		for( int x = tileBound.min.x; x < tileBound.max.x; ++x )
		{
			float a = 0;
			if( yValidIn0 && x >= validBound[0].min.x && x < validBound[0].max.x )
			{
				a = *A;
			}

			float b = 0;
			if( yValidIn1 && x >= validBound[1].min.x && x < validBound[1].max.x )
			{
				b = *B;
			}

			float m = mix;
			if( yValidMask && x >= maskValidBound.min.x && x < maskValidBound.max.x )
			{
				m *= std::max( 0.0f, std::min( 1.0f, *M ) );
			}

			*R = a * ( 1 - m ) + b * m;

			++R; ++A; ++B; ++M;
		}
	}

	return resultData;
}
Beispiel #30
0
IECore::ConstFloatVectorDataPtr Resample::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const
{
	V2f ratio, offset;
	ratioAndOffset( matrixPlug()->getValue(), ratio, offset );

	Filter2DPtr filter = createFilter( filterPlug()->getValue(), filterWidthPlug()->getValue(), ratio );
	const unsigned passes = requiredPasses( this, parent, filter.get() );

	Sampler sampler(
		passes == Vertical ? horizontalPassPlug() : inPlug(),
		channelName,
		inputRegion( tileOrigin, passes, ratio, offset, filter.get() ),
		(Sampler::BoundingMode)boundingModePlug()->getValue()
	);

	const V2i filterRadius = inputFilterRadius( filter.get(), ratio );
	const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) );

	FloatVectorDataPtr resultData = new FloatVectorData;
	resultData->writable().resize( ImagePlug::tileSize() * ImagePlug::tileSize() );
	std::vector<float>::iterator pIt = resultData->writable().begin();

	if( passes == Both )
	{
		// When the filter isn't separable we must perform all the
		// filtering in a single pass. This version also provides
		// a reference implementation against which the two-pass
		// version can be validated - use the SinglePass debug mode
		// to force the use of this code path.

		V2i oP; // output pixel position
		V2f iP; // input pixel position (floating point)
		V2i iPI; // input pixel position (floored to int)
		V2f iPF; // fractional part of input pixel position after flooring

		for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y )
		{
			iP.y = ( oP.y + 0.5 ) / ratio.y + offset.y;
			iPF.y = OIIO::floorfrac( iP.y, &iPI.y );

			for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x )
			{
				iP.x = ( oP.x + 0.5 ) / ratio.x + offset.x;
				iPF.x = OIIO::floorfrac( iP.x, &iPI.x );

				V2i fP; // relative filter position
				float v = 0.0f;
				float totalW = 0.0f;
				for( fP.y = -filterRadius.y; fP.y<= filterRadius.y; ++fP.y )
				{
					for( fP.x = -filterRadius.x; fP.x<= filterRadius.x; ++fP.x )
					{
						/// \todo version of sample taking V2i.
						const float w = (*filter)(
							ratio.x * (fP.x - ( iPF.x - 0.5f )),
							ratio.y * (fP.y - ( iPF.y - 0.5f ))
						);

						if( w == 0.0f )
						{
							continue;
						}

						v += w * sampler.sample( iPI.x + fP.x, iPI.y + fP.y );
						totalW += w;
					}
				}

				if( totalW != 0.0f )
				{
					*pIt = v / totalW;
				}

				++pIt;
			}
		}
	}
	else if( passes == Horizontal )
	{
		// When the filter is separable we can perform filtering in two
		// passes, one for the horizontal and one for the vertical. We
		// output the horizontal pass on the horizontalPassPlug() so that
		// it is cached for use in the vertical pass. The HorizontalPass
		// debug mode causes this pass to be output directly for inspection.

		// Pixels in the same column share the same filter weights, so
		// we precompute the weights now to avoid repeating work later.
		std::vector<float> weights;
		filterWeights( filter.get(), filterRadius.x, tileBound.min.x, ratio.x, offset.x, Horizontal, weights );

		V2i oP; // output pixel position
		float iX; // input pixel x coordinate (floating point)
		int iXI; // input pixel position (floored to int)

		for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y )
		{
			std::vector<float>::const_iterator wIt = weights.begin();
			for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x )
			{

				iX = ( oP.x + 0.5 ) / ratio.x + offset.x;
				OIIO::floorfrac( iX, &iXI );

				int fX; // relative filter position
				float v = 0.0f;
				float totalW = 0.0f;
				for( fX = -filterRadius.x; fX<= filterRadius.x; ++fX )
				{
					const float w = *wIt++;
					if( w == 0.0f )
					{
						continue;
					}

					v += w * sampler.sample( iXI + fX, oP.y );
					totalW += w;
				}

				if( totalW != 0.0f )
				{
					*pIt = v / totalW;
				}

				++pIt;
			}
		}
	}
	else if( passes == Vertical )
	{
		V2i oP; // output pixel position
		float iY; // input pixel position (floating point)
		int iYI; // input pixel position (floored to int)

		// Pixels in the same row share the same filter weights, so
		// we precompute the weights now to avoid repeating work later.
		std::vector<float> weights;
		filterWeights( filter.get(), filterRadius.y, tileBound.min.y, ratio.y, offset.y, Vertical, weights );

		for( oP.y = tileBound.min.y; oP.y < tileBound.max.y; ++oP.y )
		{
			iY = ( oP.y + 0.5 ) / ratio.y + offset.y;
			OIIO::floorfrac( iY, &iYI );

			for( oP.x = tileBound.min.x; oP.x < tileBound.max.x; ++oP.x )
			{
				int fY; // relative filter position
				float v = 0.0f;
				float totalW = 0.0f;
				std::vector<float>::const_iterator wIt = weights.begin() + ( oP.y - tileBound.min.y ) * ( filterRadius.y * 2 + 1);
				for( fY = -filterRadius.y; fY<= filterRadius.y; ++fY )
				{
					const float w = *wIt++;
					if( w == 0.0f )
					{
						continue;
					}

					v += w * sampler.sample( oP.x, iYI + fY );
					totalW += w;
				}

				if( totalW != 0.0f )
				{
					*pIt = v / totalW;
				}

				++pIt;
			}
		}
	}

	return resultData;
}