IECore::ConstFloatVectorDataPtr Shape::computeChannelData( const std::string &channelName, const Imath::V2i &tileOrigin, const Gaffer::Context *context, const ImagePlug *parent ) const { assert( parent == shapePlug() ); if( channelName == g_shapeChannelName ) { // Private channel we use for caching the shape but don't advertise via channelNames. return computeShapeChannelData( tileOrigin, context ); } else { ConstFloatVectorDataPtr shape = parent->channelData( g_shapeChannelName, context->get<V2i>( ImagePlug::tileOriginContextName ) ); const float c = channelValue( parent, channelName ); if( c == 1 ) { return shape; } else { FloatVectorDataPtr resultData = shape->copy(); vector<float> &result = resultData->writable(); for( vector<float>::iterator it = result.begin(), eIt = result.end(); it != eIt; ++it ) { *it *= c; } return resultData; } } }
virtual void imageData( const Imath::Box2i &box, const float *data, size_t dataSize ) { Box2i yUpBox = m_gafferFormat.yDownToFormatSpace( box ); const V2i boxMinTileOrigin = ImagePlug::tileOrigin( yUpBox.min ); const V2i boxMaxTileOrigin = ImagePlug::tileOrigin( yUpBox.max ); for( int tileOriginY = boxMinTileOrigin.y; tileOriginY <= boxMaxTileOrigin.y; tileOriginY += ImagePlug::tileSize() ) { for( int tileOriginX = boxMinTileOrigin.x; tileOriginX <= boxMaxTileOrigin.x; tileOriginX += ImagePlug::tileSize() ) { for( int channelIndex = 0, numChannels = channelNames().size(); channelIndex < numChannels; ++channelIndex ) { const V2i tileOrigin( tileOriginX, tileOriginY ); ConstFloatVectorDataPtr tileData = getTile( tileOrigin, channelIndex ); if( !tileData ) { // we've been sent data outside of the data window continue; } // we must create a new object to hold the updated tile data, // because the old one might well have been returned from // computeChannelData and be being held in the cache. FloatVectorDataPtr updatedTileData = tileData->copy(); vector<float> &updatedTile = updatedTileData->writable(); const Box2i tileBound( tileOrigin, tileOrigin + Imath::V2i( GafferImage::ImagePlug::tileSize() - 1 ) ); const Box2i transferBound = IECore::boxIntersection( tileBound, yUpBox ); for( int y = transferBound.min.y; y<=transferBound.max.y; ++y ) { int srcY = m_gafferFormat.formatToYDownSpace( y ); size_t srcIndex = ( ( srcY - box.min.y ) * ( box.size().x + 1 ) * numChannels ) + ( transferBound.min.x - box.min.x ) + channelIndex; size_t dstIndex = ( y - tileBound.min.y ) * ImagePlug::tileSize() + transferBound.min.x - tileBound.min.x; const size_t srcEndIndex = srcIndex + transferBound.size().x * numChannels; while( srcIndex <= srcEndIndex ) { updatedTile[dstIndex] = data[srcIndex]; srcIndex += numChannels; dstIndex++; } } setTile( tileOrigin, channelIndex, updatedTileData ); } } } dataReceivedSignal()( this, box ); }
SmoothSkinningData::SmoothSkinningData( ConstStringVectorDataPtr influenceNames, ConstM44fVectorDataPtr influencePose, ConstIntVectorDataPtr pointIndexOffsets, ConstIntVectorDataPtr pointInfluenceCounts, ConstIntVectorDataPtr pointInfluenceIndices, ConstFloatVectorDataPtr pointInfluenceWeights) { assert( influenceNames ); assert( influencePose ); assert( pointIndexOffsets ); assert( pointInfluenceCounts ); assert( pointInfluenceIndices ); assert( pointInfluenceWeights ); m_influenceNames = influenceNames->copy(); m_influencePose = influencePose->copy(); m_pointIndexOffsets = pointIndexOffsets->copy(); m_pointInfluenceCounts = pointInfluenceCounts->copy(); m_pointInfluenceIndices = pointInfluenceIndices->copy(); m_pointInfluenceWeights = pointInfluenceWeights->copy(); }
IECore::ConstFloatVectorDataPtr Merge::merge( F f, const std::string &channelName, const Imath::V2i &tileOrigin ) const { FloatVectorDataPtr resultData = NULL; // Temporary buffer for computing the alpha of intermediate composited layers. FloatVectorDataPtr resultAlphaData = NULL; const Box2i tileBound( tileOrigin, tileOrigin + V2i( ImagePlug::tileSize() ) ); for( ImagePlugIterator it( inPlugs() ); !it.done(); ++it ) { if( !(*it)->getInput<ValuePlug>() ) { continue; } IECore::ConstStringVectorDataPtr channelNamesData = (*it)->channelNamesPlug()->getValue(); const std::vector<std::string> &channelNames = channelNamesData->readable(); ConstFloatVectorDataPtr channelData; ConstFloatVectorDataPtr alphaData; if( channelExists( channelNames, channelName ) ) { channelData = (*it)->channelDataPlug()->getValue(); } else { channelData = ImagePlug::blackTile(); } if( channelExists( channelNames, "A" ) ) { alphaData = (*it)->channelData( "A", tileOrigin ); } else { alphaData = ImagePlug::blackTile(); } const Box2i validBound = boxIntersection( tileBound, (*it)->dataWindowPlug()->getValue() ); if( !resultData ) { // The first connected layer, with which we must initialise our result. // There's no guarantee that this layer actually covers the full data // window though (the data window could have been expanded by the upper // layers) so we must take care to mask out any invalid areas of the input. /// \todo I'm not convinced this is correct - if we have no connection /// to in[0] then should that not be treated as being a black image, so /// we should unconditionally initaliase with in[0] and then always use /// the operation for in[1:], even if in[0] is disconnected. In other /// words, shouldn't multiplying a white constant over an unconnected /// in[0] produce black? resultData = channelData->copy(); resultAlphaData = alphaData->copy(); float *B = &resultData->writable().front(); float *b = &resultAlphaData->writable().front(); for( int y = tileBound.min.y; y < tileBound.max.y; ++y ) { const bool yValid = y >= validBound.min.y && y < validBound.max.y; for( int x = tileBound.min.x; x < tileBound.max.x; ++x ) { if( !yValid || x < validBound.min.x || x >= validBound.max.x ) { *B = *b = 0.0f; } ++B; ++b; } } } else { // A higher layer (A) which must be composited over the result (B). const float *A = &channelData->readable().front(); float *B = &resultData->writable().front(); const float *a = &alphaData->readable().front(); float *b = &resultAlphaData->writable().front(); for( int y = tileBound.min.y; y < tileBound.max.y; ++y ) { const bool yValid = y >= validBound.min.y && y < validBound.max.y; for( int x = tileBound.min.x; x < tileBound.max.x; ++x ) { const bool valid = yValid && x >= validBound.min.x && x < validBound.max.x; *B = f( valid ? *A : 0.0f, *B, valid ? *a : 0.0f, *b ); *b = f( valid ? *a : 0.0f, *b, valid ? *a : 0.0f, *b ); ++A; ++B; ++a; ++b; } } } } return resultData; }
void NURBSPrimitive::setTopology( int uOrder, ConstFloatVectorDataPtr uKnot, float uMin, float uMax, int vOrder, ConstFloatVectorDataPtr vKnot, float vMin, float vMax ) { // check order isn't too small if( uOrder<2 ) { throw Exception( "Order in u direction too small." ); } if( vOrder<2 ) { throw Exception( "Order in v direction too small." ); } // check knots have enough entries for the order. // an order of N demands at least N control points // and numKnots==numControlPoints + order // so we need numKnots>=2*order if( (int)uKnot->readable().size() < uOrder * 2 ) { throw Exception( "Not enough knot values in u direction." ); } if( (int)vKnot->readable().size() < vOrder * 2 ) { throw Exception( "Not enough knot values in v direction." ); } // check knots are monotonically increasing const vector<float> &u = uKnot->readable(); float previous = u[0]; for( unsigned int i=0; i<u.size(); i++ ) { if( u[i]<previous ) { throw Exception( "Knots not monotonically increasing in u direction." ); } previous = u[i]; } const vector<float> &v = vKnot->readable(); previous = v[0]; for( unsigned int i=0; i<v.size(); i++ ) { if( v[i]<previous ) { throw Exception( "Knots not monotonically increasing in v direction." ); } previous = v[i]; } // check min and max parametric values are in range if( uMin > uMax ) { throw Exception( "uMin greater than uMax." ); } if( vMin > vMax ) { throw Exception( "vMin greater than vMax." ); } if( uMin < u[uOrder-2] ) { throw Exception( "uMin too small." ); } if( uMax > u[u.size()-uOrder+1] ) { throw Exception( "uMax too great." ); } if( vMin < v[vOrder-2] ) { throw Exception( "vMin too small." ); } if( vMax > v[v.size()-vOrder+1] ) { throw Exception( "vMax too great." ); } // set everything (taking copies of the data) m_uOrder = uOrder; m_uKnot = uKnot->copy(); m_uMin = uMin; m_uMax = uMax; m_vOrder = vOrder; m_vKnot = vKnot->copy(); m_vMin = vMin; m_vMax = vMax; }