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; }
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" ); }
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; }
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; }
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; }
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; }
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 ); } }
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; } }
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; }
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; }
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; }
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; }
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; }
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; }
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; }
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(); }
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; }
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; }
void testMemberRetrieval() { CompoundDataPtr c = new CompoundData(); c->writable()["floatElement"] = new FloatData( 42.0f ); c->writable()["stringElement"] = new StringData( "cake" ); try { FloatData *f = c->member<FloatData>( "floatElement", false ); BOOST_CHECK( f ); BOOST_CHECK( f->staticTypeId() == FloatData::staticTypeId() ); IntData *i = c->member<IntData>( "floatElement", false ); BOOST_CHECK( !i ); StringData *s = c->member<StringData>( "iAmMissing", false ); BOOST_CHECK( !s ); } catch ( std::exception &e ) { BOOST_WARN( !e.what() ); BOOST_CHECK( !"Exception thrown during member retrieval with exceptions disabled." ); } try { FloatData *f = c->member<FloatData>( "floatElement", true ); BOOST_REQUIRE( f ); BOOST_CHECK( f->staticTypeId() == FloatData::staticTypeId() ); StringData *s = c->member<StringData>( "stringElement", true ); BOOST_REQUIRE( s ); BOOST_CHECK( s->staticTypeId() == StringData::staticTypeId() ); } catch ( std::exception &e ) { BOOST_WARN( !e.what() ); BOOST_CHECK( !"Exception thrown during member retrieval." ); } try { IntData *i = c->member<IntData>( "floatElement", true ); BOOST_CHECK( !"Exception not thrown during invalid member retrieval." ); BOOST_CHECK( !i ); } catch ( IECore::Exception &e ) { } catch( ... ) { BOOST_CHECK( !"Incorrect exception type thrown during invalid member retrieval." ); } try { StringData *s = c->member<StringData>( "iAmMissing", true, false ); BOOST_CHECK( !"Exception not thrown during missing member retrieval." ); BOOST_CHECK( !s ); } catch ( IECore::Exception &e ) { } catch( ... ) { BOOST_CHECK( !"Incorrect exception type thrown during invalid member retrieval." ); } try { StringData *s = c->member<StringData>( "iAmMissing", true, true ); BOOST_REQUIRE( s ); BOOST_CHECK( s->staticTypeId() == StringData::staticTypeId() ); FloatData *f = c->member<CompoundData>( "newParent", true, true )->member<FloatData>( "newChild", true, true ); BOOST_REQUIRE( f ); BOOST_CHECK( f->staticTypeId() == FloatData::staticTypeId() ); } catch ( std::exception &e ) { BOOST_CHECK( !"Exception thrown during creation of member." ); } }
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; }
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; }
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; }
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; }
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; }
/// \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; }
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; }
void testNullData() { CompoundDataPtr d = new CompoundData(); d->writable()["floatElement"] = new FloatData( 42.0f ); d->writable()["stringElement"] = new StringData( "cake" ); // sanity check first. try { CompoundDataPtr dd = d->copy(); } catch ( std::exception &e ) { BOOST_CHECK( !"Exception thrown during CompoundData copy." ); } CompoundDataPtr c = new CompoundData(); c->writable()["nullElement"] = 0; // copy try { CompoundDataPtr d = c->copy(); BOOST_CHECK( !"Exception not thrown during copy with invalid NULL data." ); } catch ( std::exception &e ) { } // save try { IndexedIOPtr io = new MemoryIndexedIO( NULL, IndexedIO::rootPath, IndexedIO::Write); IndexedIO::EntryID entryName( "test" ); c->Object::save( io, entryName ); BOOST_CHECK( !"Exception not thrown during save with invalid NULL data." ); } catch ( std::exception &e ) { } // memoryUsage try { c->Object::memoryUsage(); } catch ( std::exception &e ) { BOOST_CHECK( !"Exception thrown during memoryCopy with invalid NULL data." ); } // isEqual try { CompoundDataPtr c2 = new CompoundData(); c2->writable()["nullElement"] = 0; bool i = c->isEqualTo( c ); BOOST_CHECK( i ); i = c->isEqualTo( c2 ); BOOST_CHECK( i ); i = c2->isEqualTo( c ); BOOST_CHECK( i ); i = c->isEqualTo( d ); BOOST_CHECK( !i ); i = d->isEqualTo( c ); BOOST_CHECK( !i ); } catch ( std::exception &e ) { BOOST_CHECK( !"Exception thrown during isEqual with invalid NULL data." ); } // hash try { c->Object::hash(); BOOST_CHECK( !"Exception not thrown during hash with invalid NULL data." ); } catch ( std::exception &e ) { } }