Example #1
0
IECore::ConstCompoundObjectPtr Set::computeProcessedGlobals( const Gaffer::Context *context, IECore::ConstCompoundObjectPtr inputGlobals ) const
{
	std::string name = namePlug()->getValue();
	if( !name.size() )
	{
		return inputGlobals;
	}

	IECore::CompoundObjectPtr result = new IECore::CompoundObject;
	// Since we're not going to modify any existing members other than the sets,
	// and our result becomes const on returning it, we can directly reference
	// the input members in our result without copying. We have to be careful not
	// to modify the input sets though.
	result->members() = inputGlobals->members();

	CompoundDataPtr sets = new CompoundData;
	if( const CompoundData *inputSets = inputGlobals->member<CompoundData>( "gaffer:sets" ) )
	{
		sets->writable() = inputSets->readable();
	}
	result->members()["gaffer:sets"] = sets;

	ConstObjectPtr set = pathMatcherPlug()->getValue();
	// const cast is acceptable because we're just using it to place a const object into a
	// container that will be treated as const everywhere immediately after return from this method.
	sets->writable()[name] = const_cast<Data *>( static_cast<const Data *>( set.get() ) );

	return result;
}
Example #2
0
void ObjectWriter::doWrite( const CompoundObject *operands )
{
	IndexedIOPtr io = new FileIndexedIO( fileName(), IndexedIO::rootPath, IndexedIO::Exclusive | IndexedIO::Write);

	/// \todo Establish why we only accept CompoundData / Data here when HeaderGenerator::header(), for example,
	/// returns a CompoundObject

	// write the header
	CompoundDataPtr header = boost::static_pointer_cast<CompoundData>( m_headerParameter->getValue()->copy() );

	header->writable()["typeName"] = new StringData( object()->typeName() );

	if( const VisibleRenderable* visibleRenderable = runTimeCast<const VisibleRenderable>(object()) )
	{
		header->writable()["bound"] = new Box3fData( visibleRenderable->bound() );
	}

	CompoundObjectPtr genericHeader = HeaderGenerator::header();
	for ( CompoundObject::ObjectMap::const_iterator it = genericHeader->members().begin(); it != genericHeader->members().end(); it++ )
	{
		assert( it->second );
		if ( it->second->isInstanceOf( Data::staticTypeId() ) )
		{
			header->writable()[ it->first ] = boost::static_pointer_cast< Data >( it->second );
		}
	}

	((ObjectPtr)header)->save( io, "header" );

	// write the object
	object()->save( io, "object" );
}
Example #3
0
static IECore::ConstCompoundDataPtr metadataGetter( const std::string &key, size_t &cost )
{
	cost = 1;
	if( !key.size() )
	{
		return NULL;
	}
	
	const char *searchPath = getenv( "OSL_SHADER_PATHS" );
	OSLQuery query;
	if( !query.open( key, searchPath ? searchPath : "" ) )
	{
		throw Exception( query.error() );
	}
	
	CompoundDataPtr metadata = new CompoundData;
	metadata->writable()["shader"] = convertMetadata( query.metadata() );
	
	CompoundDataPtr parameterMetadata = new CompoundData;
	metadata->writable()["parameter"] = parameterMetadata;
	for( size_t i = 0; i < query.nparams(); ++i )
	{
		const OSLQuery::Parameter *parameter = query.getparam( i );
		if( parameter->metadata.size() )
		{
			parameterMetadata->writable()[parameter->name] = convertMetadata( parameter->metadata );
		}
	}
	
	return metadata;
}
IECore::ObjectPtr FromMayaCameraConverter::doConversion( const MDagPath &dagPath, IECore::ConstCompoundObjectPtr operands ) const
{
	MFnCamera fnCamera( dagPath );

	// convert things that are required by the IECore::Renderer specification

	CameraPtr result = new Camera;
	result->setName( IECore::convert<std::string>( fnCamera.name() ) );

	result->setTransform( new MatrixTransform( IECore::convert<Imath::M44f>( dagPath.inclusiveMatrix() ) ) );

	V2i resolution;
	if( operands->member<IntData>( "resolutionMode" )->readable()==RenderGlobals )
	{
		MCommonRenderSettingsData renderSettings;
		MRenderUtil::getCommonRenderSettings( renderSettings );
		resolution = Imath::V2i( renderSettings.width, renderSettings.height );
	}
	else
	{
		resolution = operands->member<V2iData>( "resolution" )->readable();
	}
	result->parameters()["resolution"] = new V2iData( resolution );

	Imath::V2f clippingPlanes = Imath::V2f( fnCamera.nearClippingPlane(), fnCamera.farClippingPlane() );
	result->parameters()["clippingPlanes"] = new V2fData( clippingPlanes );

	Imath::Box2d frustum;
	fnCamera.getRenderingFrustum( (float)resolution.x / (float)resolution.y, frustum.min.x, frustum.max.x, frustum.min.y, frustum.max.y );

	if( fnCamera.isOrtho() )
	{
		// orthographic
		result->parameters()["projection"] = new StringData( "orthographic" );
		result->parameters()["screenWindow"] = new Box2fData( Box2f( frustum.min, frustum.max ) );
	}
	else
	{
		// perspective
		result->parameters()["projection"] = new StringData( "perspective" );

		// derive horizontal field of view from the viewing frustum
		float fov = Math<double>::atan( frustum.max.x / clippingPlanes[0] ) * 2.0f;
		fov = radiansToDegrees( fov );
		result->parameters()["projection:fov"] = new FloatData( fov );

		// scale the frustum so that it's -1,1 in x and that gives us the screen window
		float frustumScale = 2.0f/(frustum.max.x - frustum.min.x);
		Box2f screenWindow( V2f( -1, frustum.min.y * frustumScale ), V2f( 1, frustum.max.y * frustumScale ) );
		result->parameters()["screenWindow"] = new Box2fData( screenWindow );
	}

	// and add on other bits and bobs from maya attributes as blind data
	CompoundDataPtr maya = new CompoundData;
	result->blindData()->writable()["maya"] = maya;
	maya->writable()["aperture"] = new V2fData( Imath::V2f( fnCamera.horizontalFilmAperture(), fnCamera.verticalFilmAperture() ) );

	return result;
}
Example #5
0
IECore::CompoundDataPtr LinkedScene::linkAttributeData( const SceneInterface *scene )
{
	std::string f = scene->fileName();
	InternedStringVectorDataPtr r = new InternedStringVectorData();
	scene->path( r->writable() );
	CompoundDataPtr d = new CompoundData();
	d->writable()[g_fileName] = new StringData(f);
	d->writable()[g_root] = r;
	return d;
}
Example #6
0
IECore::CompoundDataPtr AlembicInput::metaData() const
{
	const MetaData &md = m_data->object.getMetaData();
	CompoundDataPtr resultData = new CompoundData;
	CompoundDataMap &resultMap = resultData->writable();
	for( MetaData::const_iterator it = md.begin(), eIt = md.end(); it!=eIt; it++ )
	{
		resultMap[it->first] = new StringData( it->second );
	}
	
	return resultData;
}
Example #7
0
static IECore::CompoundDataPtr convertMetadata( const std::vector<OSLQuery::Parameter> &metadata )
{
	CompoundDataPtr result = new CompoundData;
	for( std::vector<OSLQuery::Parameter>::const_iterator it = metadata.begin(), eIt = metadata.end(); it != eIt; ++it )
	{
		DataPtr data = convertMetadata( *it );
		if( data )
		{
			result->writable()[it->name.c_str()] = data;
		}
	}
	return result;
}
ObjectPtr BGEOParticleReader::doOperation( const CompoundObject *operands )
{
	vector<string> attributes;
	particleAttributes( attributes );
	size_t nParticles = numParticles();
	PointsPrimitivePtr result = new PointsPrimitive( nParticles );

	CompoundDataPtr attributeData = readAttributes( attributes );
	if ( !attributeData )
	{
		throw Exception( ( format( "Failed to load \"%s\"." ) % fileName() ).str() );

	}

	bool haveNumPoints = false;
	for( vector<string>::const_iterator it = attributes.begin(); it!=attributes.end(); it++ )
	{
		CompoundDataMap::const_iterator itData = attributeData->readable().find( *it );
		if ( itData == attributeData->readable().end() )
		{
			msg( Msg::Warning, "ParticleReader::doOperation", format( "Attribute %s expected but not found." ) % *it );
			continue;
		}
		
		DataPtr d = itData->second;
		
		if ( testTypedData<TypeTraits::IsVectorTypedData>( d ) )
		{
			size_t s = despatchTypedData< TypedDataSize, TypeTraits::IsVectorTypedData >( d );
			if( !haveNumPoints )
			{
				result->setNumPoints( s );
				haveNumPoints = true;
			}
			if( s==result->getNumPoints() )
			{
				result->variables.insert( PrimitiveVariableMap::value_type( *it, PrimitiveVariable( PrimitiveVariable::Vertex, d ) ) );
			}
			else
			{
				msg( Msg::Warning, "ParticleReader::doOperation", format( "Ignoring attribute \"%s\" due to insufficient elements (expected %d but found %d)." ) % *it % result->getNumPoints() % s );
			}
		}
		else if ( testTypedData<TypeTraits::IsSimpleTypedData>( d ) )
		{
			result->variables.insert( PrimitiveVariableMap::value_type( *it, PrimitiveVariable( PrimitiveVariable::Constant, d ) ) );
		}
	}

	return result;
}
Example #9
0
void SetVisualiser::compute( Gaffer::ValuePlug *output, const Gaffer::Context *context ) const
{
	if( output == outSetsPlug() )
	{
		const StringAlgo::MatchPattern requestedSetsPattern = setsPlug()->getValue();

		std::vector<InternedString> names;
		std::vector<Color3f> colors;

		if( !requestedSetsPattern.empty() )
		{
			const std::vector<Override> overrides = unpackOverrides( colorOverridesPlug() );

			ConstInternedStringVectorDataPtr allSetNamesData = inPlug()->setNames();

			// Sorting now makes everything easier, otherwise you have to
			// sort parallel arrays later, which is a pain.
			std::vector<InternedString> allNames = allSetNamesData->readable();
			std::sort( allNames.begin(), allNames.end(), internedStringCompare );

			for( auto &name : allNames )
			{
				// Gaffer has some internal sets that begin with the '__'
				// prefix. These are usually Lights, Cameras, etc... We filter
				// these out as they most of their objects don't even draw in
				// the viewer in a meaningful way for visualising set Membership
				if( boost::starts_with( name.string(), "__" ) )
				{
					continue;
				}

				if( StringAlgo::matchMultiple( name, requestedSetsPattern ) )
				{
					names.push_back( name );
					colors.push_back( colorForSetName( name, overrides ) );
				}
			}
		}

		CompoundDataPtr data = new CompoundData();
		data->writable()["names"] = new InternedStringVectorData( names );
		data->writable()["colors"] = new Color3fVectorData( colors );
		static_cast<AtomicCompoundDataPlug *>( output )->setValue( data );
	}
	else
	{
		SceneElementProcessor::compute( output, context );
	}
}
Example #10
0
IECore::ConstObjectPtr OSLObject::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
    const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
    if( !inputPrimitive )
    {
        return inputObject;
    }

    if( !inputPrimitive->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex ) )
    {
        return inputObject;
    }

    ConstOSLShaderPtr shader = runTimeCast<const OSLShader>( shaderPlug()->source<Plug>()->node() );
    ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : NULL;

    if( !shadingEngine )
    {
        return inputObject;
    }

    CompoundDataPtr shadingPoints = new CompoundData;
    for( PrimitiveVariableMap::const_iterator it = inputPrimitive->variables.begin(), eIt = inputPrimitive->variables.end(); it != eIt; ++it )
    {
        if( it->second.interpolation == PrimitiveVariable::Vertex )
        {
            // cast is ok - we're only using it to be able to reference the data from the shadingPoints,
            // but nothing will modify the data itself.
            shadingPoints->writable()[it->first] = boost::const_pointer_cast<Data>( it->second.data );
        }
    }

    PrimitivePtr outputPrimitive = inputPrimitive->copy();

    ShadingEngine::Transforms transforms;

    transforms[ g_world ] = ShadingEngine::Transform( inPlug()->fullTransform( path ));

    CompoundDataPtr shadedPoints = shadingEngine->shade( shadingPoints.get(), transforms );
    for( CompoundDataMap::const_iterator it = shadedPoints->readable().begin(), eIt = shadedPoints->readable().end(); it != eIt; ++it )
    {
        if( it->first != "Ci" )
        {
            outputPrimitive->variables[it->first] = PrimitiveVariable( PrimitiveVariable::Vertex, it->second );
        }
    }

    return outputPrimitive;
}
Example #11
0
static void unameHeaderGenerator( CompoundObjectPtr header )
{
	struct utsname name;

	if ( !uname( &name ) )
	{
		CompoundDataPtr compound = new CompoundData();
		compound->writable()["systemName"] = new StringData( name.sysname );
		compound->writable()["nodeName"] = new StringData( name.nodename );
		compound->writable()["systemRelease"] = new StringData( name.release );
		compound->writable()["systemVersion"] = new StringData( name.version );
		compound->writable()["machineName"] = new StringData( name.machine );
		header->members()["host"] = compound;
	}
}
DataPtr BGEOParticleReader::readAttribute( const std::string &name )
{
	std::vector< std::string > names;
	names.push_back( name );
	CompoundDataPtr result = readAttributes( names );
	
	if (!result)
	{
		return 0;
	}
	CompoundDataMap::const_iterator it = result->readable().find( name );
	if ( it == result->readable().end() )
	{
		return 0;
	}
	return it->second;
}
Example #13
0
IECore::ConstObjectPtr OSLObject::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
	if( !inputPrimitive )
	{
		return inputObject;
	}

	if( !inputPrimitive->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex ) )
	{
		return inputObject;
	}

	OSLRenderer::ConstShadingEnginePtr shadingEngine = OSLImage::shadingEngine( shaderPlug() );
	if( !shadingEngine )
	{
		return inputObject;	
	}
	
	CompoundDataPtr shadingPoints = new CompoundData;
	for( PrimitiveVariableMap::const_iterator it = inputPrimitive->variables.begin(), eIt = inputPrimitive->variables.end(); it != eIt; ++it )
	{
		if( it->second.interpolation == PrimitiveVariable::Vertex )
		{
			// cast is ok - we're only using it to be able to reference the data from the shadingPoints,
			// but nothing will modify the data itself.
			shadingPoints->writable()[it->first] = constPointerCast<Data>( it->second.data );
		}
	}

	PrimitivePtr outputPrimitive = inputPrimitive->copy();

	ConstCompoundDataPtr shadedPoints = shadingEngine->shade( shadingPoints );
	const std::vector<Color3f> &ci = shadedPoints->member<Color3fVectorData>( "Ci" )->readable();
	
	V3fVectorDataPtr p = new V3fVectorData;
	p->writable().reserve( ci.size() );
	std::copy( ci.begin(), ci.end(), back_inserter( p->writable() ) );
	
	outputPrimitive->variables["P"] = PrimitiveVariable( PrimitiveVariable::Vertex, p );

	/// \todo Allow shaders to write arbitrary primitive variables.
			
	return outputPrimitive;
}
Example #14
0
IECore::ConstCompoundDataPtr GafferScene::sets( const ScenePlug *scene )
{
	ConstInternedStringVectorDataPtr setNamesData = scene->setNamesPlug()->getValue();
	std::vector<GafferScene::ConstPathMatcherDataPtr> setsVector;
	setsVector.resize( setNamesData->readable().size(), NULL );

	Sets setsCompute( scene, setNamesData->readable(), setsVector );
	parallel_for( tbb::blocked_range<size_t>( 0, setsVector.size() ), setsCompute );

	CompoundDataPtr result = new CompoundData;
	for( size_t i = 0, e = setsVector.size(); i < e; ++i )
	{
		// The const_pointer_cast is ok because we're just using it to put the set into
		// a container that will be const on return - we never modify the set itself.
		result->writable()[setNamesData->readable()[i]] = boost::const_pointer_cast<GafferScene::PathMatcherData>( setsVector[i] );
	}
	return result;
}
Example #15
0
static IECore::ConstCompoundDataPtr metadataGetter( const std::string &key, size_t &cost )
{
	cost = 1;
	if( !key.size() )
	{
		return NULL;
	}

	const char *searchPath = getenv( "OSL_SHADER_PATHS" );
	OSLQuery query;
	if( !query.open( key, searchPath ? searchPath : "" ) )
	{
		throw Exception( query.geterror() );
	}

	CompoundDataPtr metadata = new CompoundData;
	metadata->writable()["shader"] = convertMetadata( query.metadata() );

	CompoundDataPtr parameterMetadata = new CompoundData;
	metadata->writable()["parameter"] = parameterMetadata;
	for( size_t i = 0; i < query.nparams(); ++i )
	{
		const OSLQuery::Parameter *parameter = query.getparam( i );
		if( parameter->metadata.size() )
		{
			string nameWithoutSuffix;
			const OSLQuery::Parameter *positionsParameter;
			const OSLQuery::Parameter *valuesParameter;
			const OSLQuery::Parameter *basisParameter;

			// If this parameter is part of a spline, register the metadata onto the spline plug
			if( findSplineParameters( query, parameter, nameWithoutSuffix, positionsParameter, valuesParameter, basisParameter ) )
			{
				// We merge metadata found on all the parameters that make up the plug, but in no particular order.
				// If you specify conflicting metadata on the different parameters you may get inconsistent results.
				CompoundData *prevData = parameterMetadata->member<CompoundData>( nameWithoutSuffix );
				CompoundDataPtr data = convertMetadata( parameter->metadata );
				if( prevData )
				{
					data->writable().insert( prevData->readable().begin(), prevData->readable().end() );
				}

				parameterMetadata->writable()[nameWithoutSuffix] = data;
			}
			else
			{
				parameterMetadata->writable()[parameter->name.c_str()] = convertMetadata( parameter->metadata );
			}
		}
	}

	return metadata;
}
Example #16
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;
}
Example #17
0
IECore::ConstCompoundDataPtr GafferScene::SceneAlgo::sets( const ScenePlug *scene, const std::vector<IECore::InternedString> &setNames )
{
	std::vector<IECore::ConstPathMatcherDataPtr> setsVector;
	setsVector.resize( setNames.size(), nullptr );

	Sets setsCompute( scene, Context::current(), setNames, setsVector );
	tbb::task_group_context taskGroupContext( tbb::task_group_context::isolated );
	parallel_for(
		tbb::blocked_range<size_t>( 0, setsVector.size() ), setsCompute,
		taskGroupContext // Prevents outer tasks silently cancelling our tasks
	);

	CompoundDataPtr result = new CompoundData;
	for( size_t i = 0, e = setsVector.size(); i < e; ++i )
	{
		// The const_pointer_cast is ok because we're just using it to put the set into
		// a container that will be const on return - we never modify the set itself.
		result->writable()[setNames[i]] = boost::const_pointer_cast<PathMatcherData>( setsVector[i] );
	}
	return result;
}
Example #18
0
IECore::ConstObjectPtr OSLLight::computeSource( const Gaffer::Context *context ) const
{
	switch( shapePlug()->getValue() )
	{
		case Disk :
			return new DiskPrimitive( radiusPlug()->getValue() );
		case Sphere :
			return new SpherePrimitive( radiusPlug()->getValue() );
		case Geometry :
		{
			CompoundDataPtr parameters = new CompoundData;
			geometryParametersPlug()->fillCompoundData( parameters->writable() );
			return new IECoreScenePreview::Geometry(
				geometryTypePlug()->getValue(),
				geometryBoundPlug()->getValue(),
				parameters
			);
		}
	}
	return NullObject::defaultNullObject();
}
Example #19
0
static IECore::ConstCompoundDataPtr metadataGetter( const std::string &key, size_t &cost )
{
	IECoreArnold::UniverseBlock arnoldUniverse( /* writable = */ false );

	const AtNodeEntry *shader = AiNodeEntryLookUp( AtString( key.c_str() ) );
	if( !shader )
	{
		throw Exception( str( format( "Shader \"%s\" not found" ) % key ) );
	}

	CompoundDataPtr metadata = new CompoundData;

	CompoundDataPtr shaderMetadata = new CompoundData;
	metadata->writable()["shader"] = shaderMetadata;

	// Currently we don't store metadata for parameters.
	// We add the "parameter" CompoundData mainly so that we are consistent with the OSLShader.
	// Eventually we will load all metadata here and access it from ArnoldShaderUI.
	CompoundDataPtr parameterMetadata = new CompoundData;
	metadata->writable()["parameter"] = parameterMetadata;

	AtString value;
	if( AiMetaDataGetStr( shader, /* look up metadata on node, not on parameter */ g_nullArnoldString , g_primaryInputArnoldString, &value ) )
	{
		shaderMetadata->writable()["primaryInput"] = new StringData( value.c_str() );
	}

	AtString shaderType;
	if( AiMetaDataGetStr( shader, /* look up metadata on node, not on parameter */ g_nullArnoldString , g_shaderTypeArnoldString, &shaderType ) )
	{
		shaderMetadata->writable()["shaderType"] = new StringData( shaderType.c_str() );
	}

	return metadata;
}
Example #20
0
IECore::ConstObjectPtr OSLObject::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	const Primitive *inputPrimitive = runTimeCast<const Primitive>( inputObject.get() );
	if( !inputPrimitive )
	{
		return inputObject;
	}

	const OSLShader *shader = runTimeCast<const OSLShader>( shaderPlug()->source()->node() );
	ConstShadingEnginePtr shadingEngine = shader ? shader->shadingEngine() : nullptr;

	if( !shadingEngine )
	{
		return inputObject;
	}

	PrimitiveVariable::Interpolation interpolation = static_cast<PrimitiveVariable::Interpolation>( interpolationPlug()->getValue() );

	IECoreScene::ConstPrimitivePtr resampledObject = IECore::runTimeCast<const IECoreScene::Primitive>( resampledInPlug()->objectPlug()->getValue() );
	CompoundDataPtr shadingPoints = prepareShadingPoints( resampledObject.get(), shadingEngine.get() );

	PrimitivePtr outputPrimitive = inputPrimitive->copy();

	ShadingEngine::Transforms transforms;

	transforms[ g_world ] = ShadingEngine::Transform( inPlug()->fullTransform( path ));

	CompoundDataPtr shadedPoints = shadingEngine->shade( shadingPoints.get(), transforms );
	for( CompoundDataMap::const_iterator it = shadedPoints->readable().begin(), eIt = shadedPoints->readable().end(); it != eIt; ++it )
	{

		// Ignore the output color closure as the debug closures are used to define what is 'exported' from the shader
		if( it->first != "Ci" )
		{
			outputPrimitive->variables[it->first] = PrimitiveVariable( interpolation, it->second );
		}
	}

	return outputPrimitive;
}
Example #21
0
Gaffer::PathFilterPtr ScenePath::createStandardFilter( const std::vector<std::string> &setNames, const std::string &setsLabel )
{
	if( !setNames.size() )
	{
		return NULL;
	}

	UnionFilterPtr unionFilter = new UnionFilter;

	std::string defaultLabel = "Show only ";
	for( std::vector<std::string>::const_iterator it = setNames.begin(), eIt = setNames.end(); it != eIt; ++it )
	{
		SetFilterPtr setFilter = new SetFilter();
		unionFilter->addChild( setFilter );
		setFilter->setPlug()->setValue( *it );
		unionFilter->inPlugs()->getChild<Gaffer::Plug>( it - setNames.begin() )->setInput( setFilter->outPlug() );

		if( it != setNames.begin() )
		{
			defaultLabel += ", ";
		}
		defaultLabel += *it;
	}

	SceneFilterPathFilterPtr setsFilter = new SceneFilterPathFilter( unionFilter );
	CompoundDataPtr uiUserData = new CompoundData;
	uiUserData->writable()["label"] = new StringData( setsLabel.size() ? setsLabel : defaultLabel );
	setsFilter->userData()->writable()["UI"] = uiUserData;

	/// \todo It'd be nice to add a MatchPatternPathFilter here for the user to type
	/// in arbitrary match patterns, just as we do in FileSystemPath::createStandardFilter().
	/// To be effective though, it makes most sense if such a filter applies only to leaf
	/// paths, and at present no ScenePath is considered to be leaf.

	return setsFilter;
}
Example #22
0
// \todo This function may be useful on other situations. Add as Converter?
void ImagePlug::compoundObjectToCompoundData( const CompoundObject *object, CompoundData *data )
{
    CompoundDataMap &dataMap = data->writable();
    const CompoundObject::ObjectMap &objectMap = object->members();
    for ( CompoundObject::ObjectMap::const_iterator it = objectMap.begin(); it != objectMap.end(); ++it )
    {
        if ( it->second->typeId() == CompoundObjectTypeId )
        {
            CompoundDataPtr newData = new CompoundData();
            dataMap[ it->first ] = newData;
            compoundObjectToCompoundData( static_cast<const CompoundObject *>( it->second.get() ), newData.get() );
        }
        else if ( Data *value = IECore::runTimeCast<Data>( it->second.get() ) )
        {
            dataMap[ it->first ] = value;
        }
    }
}
Example #23
0
	static ShaderPtr construct( const std::string &name="defaultsurface", const std::string &type="surface", CompoundDataPtr parameters = 0 )
	{
		return new Shader( name, type, parameters ? parameters->readable() : CompoundDataMap() );
	}
Example #24
0
IECore::ObjectPtr Group::computeMapping( const Gaffer::Context *context ) const
{
	/// \todo It might be more optimal to make our own Object subclass better tailored
	/// for passing the information we want.
	CompoundObjectPtr result = new CompoundObject();

	InternedStringVectorDataPtr childNamesData = new InternedStringVectorData();
	vector<InternedString> &childNames = childNamesData->writable();
	result->members()["__GroupChildNames"] = childNamesData;

	ObjectVectorPtr forwardMappings = new ObjectVector;
	result->members()["__GroupForwardMappings"] = forwardMappings;

	boost::regex namePrefixSuffixRegex( "^(.*[^0-9]+)([0-9]+)$" );
	boost::format namePrefixSuffixFormatter( "%s%d" );

	set<InternedString> allNames;
	for( ScenePlugIterator it( inPlugs() ); it != it.end(); ++it )
	{
		ConstInternedStringVectorDataPtr inChildNamesData = (*it)->childNames( ScenePath() );
		CompoundDataPtr forwardMapping = new CompoundData;
		forwardMappings->members().push_back( forwardMapping );

		const vector<InternedString> &inChildNames = inChildNamesData->readable();
		for( vector<InternedString>::const_iterator cIt = inChildNames.begin(), ceIt = inChildNames.end(); cIt!=ceIt; cIt++ )
		{
			InternedString name = *cIt;
			if( allNames.find( name ) != allNames.end() )
			{
				// uniqueify the name
				/// \todo This code is almost identical to code in GraphComponent::setName(),
				/// is there a sensible place it can be shared? The primary obstacle is that
				/// each use has a different method of storing the existing names.
				string prefix = name;
				int suffix = 1;

				boost::cmatch match;
				if( regex_match( name.value().c_str(), match, namePrefixSuffixRegex ) )
				{
					prefix = match[1];
					suffix = boost::lexical_cast<int>( match[2] );
				}

				do
				{
					name = boost::str( namePrefixSuffixFormatter % prefix % suffix );
					suffix++;
				} while( allNames.find( name ) != allNames.end() );
			}

			allNames.insert( name );
			childNames.push_back( name );
			forwardMapping->writable()[*cIt] = new InternedStringData( name );

			CompoundObjectPtr entry = new CompoundObject;
			entry->members()["n"] = new InternedStringData( *cIt );
			entry->members()["i"] = new IntData( it.base() - inPlugs()->children().begin() );
			result->members()[name] = entry;
		}
	}

	return result;
}
Example #25
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;
}
Example #26
0
IECore::ConstObjectPtr CameraTweaks::computeProcessedObject( const ScenePath &path, const Gaffer::Context *context, IECore::ConstObjectPtr inputObject ) const
{
	IECoreScene::ConstCameraPtr inputCamera = IECore::runTimeCast<const IECoreScene::Camera>( inputObject );
	if( !inputCamera )
	{
		return inputObject;
	}

	const Plug *tweaksPlug = this->tweaksPlug();
	if( tweaksPlug->children().empty() )
	{
		return inputObject;
	}

	IECoreScene::CameraPtr result = inputCamera->copy();

	for( TweakPlugIterator tIt( tweaksPlug ); !tIt.done(); ++tIt )
	{
		if( !(*tIt)->enabledPlug()->getValue() )
		{
			continue;
		}
		const std::string name = (*tIt)->namePlug()->getValue();
		if( name.empty() )
		{
			continue;
		}

		if( name == "fieldOfView" )
		{
			InternedString internedName(name);
			CompoundDataPtr dummyParameters = new CompoundData();
			dummyParameters->writable()[internedName] = new FloatData( result->calculateFieldOfView()[0] );
			(*tIt)->applyTweak( dummyParameters.get() );
			FloatData *tweakedData = dummyParameters->member<FloatData>( internedName );
			if( tweakedData )
			{
				float fieldOfView = std::max( 0.0f, std::min( 179.99f, tweakedData->readable() ) );
				result->setFocalLengthFromFieldOfView( fieldOfView );
			}
		}
		else if( name == "apertureAspectRatio" )
		{
			InternedString internedName(name);
			Imath::V2f aperture = result->getAperture();
			CompoundDataPtr dummyParameters = new CompoundData();
			dummyParameters->writable()[internedName] = new FloatData( aperture[0] / aperture[1] );
			(*tIt)->applyTweak( dummyParameters.get() );
			FloatData *tweakedData = dummyParameters->member<FloatData>( internedName );
			if( tweakedData )
			{
				aperture[1] = aperture[0] / max( 0.0000001f, tweakedData->readable() );
				result->setAperture( aperture );
			}
		}
		else
		{
			(*tIt)->applyTweak( result->parametersData() );
		}
	}


	return result;
}
CompoundObjectPtr FromHoudiniPolygonsConverter::transferMeshInterpolation( const GU_Detail *geo, const IECore::CompoundObject *operands, IECoreScene::MeshPrimitive *mesh ) const
{
	// We store mesh interpolation in Houdini as an indexed string Prim Attrib (eg Uniform PrimitiveVariable)
	// but we don't want to extract it as such because it can be expensive to deal with indexed variables when
	// many meshes are stored in a single SOP. Since we know there is a fixed number of valid values, and we
	// only support a single value per mesh (rather than per polygon as its stored in Houdini), we can get
	// better performance with a specific extraction process.

	GA_ROHandleS meshTypeAttrib( geo, GA_ATTRIB_PRIMITIVE, g_interpolationAttrib.c_str() );
	if( !meshTypeAttrib.isValid() )
	{
		// The attrib isn't here, so everything stays at the default value of linear
		return nullptr;
	}

	// We're going to convert ieMeshInterpolation ourselves. Update the operands to
	// filter out the attrib so it isn't transfered as a standard PrimitiveVariable.
	CompoundObjectPtr modifiedOperands = operands->copy();
	std::string &attributeFilter = modifiedOperands->member<StringData>( g_attributeFilter )->writable();
	attributeFilter += g_interpolationAttribNegated.c_str();

	GA_Size polyId, subdivId = -1;
	const GA_Attribute *meshTypeAttr = meshTypeAttrib.getAttribute();
	/// \todo: replace with GA_ROHandleS somehow... its not clear how, there don't seem to be iterators.
	const GA_AIFSharedStringTuple *meshTypeTuple = meshTypeAttr->getAIFSharedStringTuple();
	for( GA_AIFSharedStringTuple::iterator it = meshTypeTuple->begin( meshTypeAttr ); !it.atEnd(); ++it )
	{
		if( const char *value = it.getString() )
		{
			if( !strcmp( value, g_subdiv.c_str() ) )
			{
				subdivId = it.getIndex();
			}
			else if( !strcmp( value, g_poly.c_str() ) )
			{
				polyId = it.getIndex();
			}
		}
	}

	if( subdivId == -1 )
	{
		// No faces were set as subdiv, so all meshes are linear. We still return
		// the updated operands so ieMeshInterpolation is never converted.
		return modifiedOperands;
	}

	GA_ROHandleS nameAttrib( geo, GA_ATTRIB_PRIMITIVE, GA_Names::name );
	if( nameAttrib.isValid() )
	{
		// Multiple names means we may need to collect the mesh interpolation for
		// post-processing via the DetailSplitter.

		CompoundDataPtr meshTypeMapData = new CompoundData;
		auto &meshTypeMap = meshTypeMapData->writable();

		// Prepare the map of location to mesh type. We're going to store a
		// bool because there are only 2 possible values (currently) and this
		// is expected to be transient / never-serialized data.
		std::vector<bool *> locationMeshTypes;
		const GA_Attribute *nameAttr = nameAttrib.getAttribute();
		/// \todo: replace with GA_ROHandleS somehow... its not clear how, there don't seem to be iterators.
		const GA_AIFSharedStringTuple *nameTuple = nameAttr->getAIFSharedStringTuple();
		for( GA_AIFSharedStringTuple::iterator it = nameTuple->begin( nameAttr ); !it.atEnd(); ++it )
		{
			BoolDataPtr meshTypeData = new BoolData( false );
			meshTypeMap.insert( { it.getString(), meshTypeData } );
			locationMeshTypes.emplace_back( &meshTypeData->writable() );
		}

		// Calculate the mesh type per location
		GA_Offset start, end;
		for( GA_Iterator it( geo->getPrimitiveRange() ); it.blockAdvance( start, end ); )
		{
			for( GA_Offset offset = start; offset < end; ++offset )
			{
				int id = nameAttrib.getIndex( offset );
				if( id < 0 )
				{
					continue;
				}

				if( meshTypeAttrib.getIndex( offset ) == subdivId )
				{
					( *locationMeshTypes[id] ) = true;
				}
			}
		}

		mesh->blindData()->writable()[g_interpolationAttrib] = meshTypeMapData;
		return modifiedOperands;
	}

	// No name attrib means we have a single mesh, so we can fallback to
	// simpler logic without worrying about the DetailSplitter.

	bool found = false;
	GA_Offset start, end;
	InternedString interpolation = g_linear;

	for( GA_Iterator it( geo->getPrimitiveRange() ); !found && it.blockAdvance( start, end ); )
	{
		for( GA_Offset offset = start; !found && offset < end; ++offset )
		{
			GA_Size meshTypeId = meshTypeAttrib.getIndex( offset );
			if( meshTypeId == subdivId )
			{
				interpolation = g_catmullClark;
				// Subdiv meshes should not have normals. We assume this occurred because the geo contained
				// both subdiv and linear meshes, inadvertantly extending the normals attribute to both.
				attributeFilter += " ^N";
				found = true;
				break;
			}
			else if( meshTypeId == polyId )
			{
				interpolation = g_linear;
				found = true;
				break;
			}
		}
	}

	mesh->setInterpolation( interpolation );
	return modifiedOperands;
}
Example #28
0
/// \todo This mapping is very similar to the one created by the Group node. Perhaps
/// some generalisation of the two could form the basis for a nice unified HierarchyProcessor?
/// In this case I think we would have a custom mapping class rather than just pass around
/// CompoundData, and then parentAndBranchPaths() (or the future version of it) could be a method
/// on the mapping object.
IECore::ConstCompoundDataPtr BranchCreator::computeMapping( const Gaffer::Context *context ) const
{
	// get the parent. currently this is simply retrieving the value of parentPlug(),
	// but if we wanted to support multiple parents in future, here we would find the
	// parent appropriate to the current "scene:path" context entry.
	
	/// \todo We should introduce a plug type which stores its values as a ScenePath directly.
	ScenePlug::ScenePath parent;
	string parentAsString = parentPlug()->getValue();
	if( parentAsString.empty() )
	{
		// no parent specified so no mapping needed
		return static_cast<const CompoundData *>( mappingPlug()->defaultValue() );
	}
	ScenePlug::stringToPath( parentAsString, parent );
	
	// see if we're interested in creating children or not. if we're not
	// we can early out. no innuendo intended.
	
	ConstInternedStringVectorDataPtr branchChildNamesData = computeBranchChildNames( parent, ScenePath(), context );
	if( !branchChildNamesData->readable().size() )
	{
		return static_cast<const CompoundData *>( mappingPlug()->defaultValue() );
	}

	// create our result. in future it might be useful to create our datatype for this,
	// but for now we're just packing everything into a CompoundData.

	CompoundDataPtr result = new CompoundData;
	result->writable()["__BranchCreatorParent"] = new InternedStringVectorData( parent );
	
	// calculate the child names for the result. this is the full list of child names
	// immediately below the parent. we need to be careful to ensure that we rename any
	// branch names which conflict with existing children of the parent.
	
	ConstInternedStringVectorDataPtr inChildNamesData = inPlug()->childNames( parent );
	InternedStringVectorDataPtr childNamesData = new InternedStringVectorData();
	
	const vector<InternedString> &inChildNames = inChildNamesData->readable();
	const vector<InternedString> &branchChildNames = branchChildNamesData->readable();
	vector<InternedString> &childNames = childNamesData->writable();
	
	result->writable()["__BranchCreatorChildNames"] = childNamesData;
	
	set<InternedString> allNames;
	for( vector<InternedString>::const_iterator it = inChildNames.begin(); it != inChildNames.end(); ++it )
	{
		allNames.insert( *it );
		childNames.push_back( *it );
	}
	
	boost::regex namePrefixSuffixRegex( "^(.*[^0-9]+)([0-9]+)$" );
	boost::format namePrefixSuffixFormatter( "%s%d" );

	for( vector<InternedString>::const_iterator it = branchChildNames.begin(); it != branchChildNames.end(); ++it )
	{
		InternedString name = *it;
		if( allNames.find( name ) != allNames.end() )
		{
			// uniqueify the name
			string prefix = name;
			int suffix = 1;
			
			boost::cmatch match;
			if( regex_match( name.value().c_str(), match, namePrefixSuffixRegex ) )
			{
				prefix = match[1];
				suffix = boost::lexical_cast<int>( match[2] );
			}
			
			do
			{
				name = boost::str( namePrefixSuffixFormatter % prefix % suffix );
				suffix++;
			} while( allNames.find( name ) != allNames.end() );
		}
		
		allNames.insert( name );
		childNames.push_back( name );
		
		result->writable()[name] = new InternedStringData( *it );
	}
	
	return result;
}
Example #29
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;
}
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;
}